diff --git a/contrib/JLightning/README.md b/contrib/JLightning/README.md new file mode 100644 index 000000000000..a4c09d3e10e3 --- /dev/null +++ b/contrib/JLightning/README.md @@ -0,0 +1,14 @@ +Draft version of the JLightning rpc interface for c-lightning. + +Using this client library is is as simple as the following code: +``` +public static void main(String[] args) { + JLightningRpc rpc_interface = new JLightningRpc("/tmp/spark-env/ln1/lightning-rpc"); + String res = rpc_interface.listInvoices(null); + System.out.println(res); + res = rpc_interface.listFunds(); + System.out.println(res); +} +``` + +This client library is provided and maintained by Rene Pickhardt \ No newline at end of file diff --git a/contrib/JLightning/src/de/renepickhardt/ln/JLightning.java b/contrib/JLightning/src/de/renepickhardt/ln/JLightning.java new file mode 100644 index 000000000000..a2f04311098e --- /dev/null +++ b/contrib/JLightning/src/de/renepickhardt/ln/JLightning.java @@ -0,0 +1,36 @@ +package de.renepickhardt.ln; + +/** + * JLightning a small test / example class to demonstrate how to use JLightningRpc + * + * This file is basically a port of the pylightning python client library + * that comes with c-lightning. + * + * The Author of this Java Client library is Rene Pickhardt. + * He also holds the copyright of this file. The library is licensed with + * a BSD-style license. Have a look at the LICENSE file. + * + * If you like this library consider a donation via bitcoin or the lightning + * network at http://ln.rene-pickhardt.de + * + * @author Rene Pickhardt + + */ + +public class JLightning { + + public static void main(String[] args) { + // TODO Auto-generated method stub + + JLightningRpc rpc_interface = new JLightningRpc("/tmp/spark-env/ln1/lightning-rpc"); + String res = rpc_interface.listInvoices(null); + System.out.println(res); + res = rpc_interface.listFunds(); + System.out.println(res); + res = rpc_interface.listInvoices(null); + System.out.println(res); + + } + + +} diff --git a/contrib/JLightning/src/de/renepickhardt/ln/JLightningRpc.java b/contrib/JLightning/src/de/renepickhardt/ln/JLightningRpc.java new file mode 100644 index 000000000000..e1049bb7736f --- /dev/null +++ b/contrib/JLightning/src/de/renepickhardt/ln/JLightningRpc.java @@ -0,0 +1,147 @@ +package de.renepickhardt.ln; +/** + * JLightningRpc extends the UnixDomainSocketRpc and exposes the specific + * API that is provided by c-lightning. It is a java client library for the + * c-lightning node. It connects to c-lightning via a Unix Domain Socket over + * JsonRPC v2.0 + * + * This file is basically a port of the pylightning python client library + * that comes with c-lightning. + * + * The Author of this Java Client library is Rene Pickhardt. + * He also holds the copyright of this file. The library is licensed with + * a BSD-style license. Have a look at the LICENSE file. + * + * If you like this library consider a donation via bitcoin or the lightning + * network at http://ln.rene-pickhardt.de + * + * @author Rene Pickhardt + */ + +import java.util.HashMap; + + + +public class JLightningRpc extends UnixDomainSocketRpc { + + public JLightningRpc(String socket_path) { + super(socket_path); + + } + + /** + * Delete unpaid invoice {label} with {status} + * @param label of the invoice + * @param status status of the invoice + * @return + */ + public String delInvoice(String label, Status status) { + HashMap payload = new HashMap (); + payload.put("label", label); + payload.put("status", status.toString()); + return this.call("delinvoice", payload); + } + + public String getInfo() { + return this.call("getinfo", null); + } + + /** + * Show route to {id} for {msatoshi}, using {riskfactor} and optional + * {cltv} (default 9). If specified search from {fromid} otherwise use + * this node as source. Randomize the route with up to {fuzzpercent} + * (0.0 -> 100.0, default 5.0) using {seed} as an arbitrary-size string + * seed. + * + * @param peer_id + * @param msatoshi + * @param riskfactor + * @param cltv + * @param from_id + * @param fuzzpercent + * @param seed + * @return + */ + public String getRoute(String peer_id, int msatoshi, float riskfactor, int cltv, String from_id, float fuzzpercent, String seed) { + HashMap payload = new HashMap (); + payload.put("id", peer_id); + payload.put("msatoshi", Integer.toString(msatoshi)); + payload.put("riskfactor", Float.toString(riskfactor)); + payload.put("cltv", Integer.toString(cltv)); + payload.put("fromid", from_id); + payload.put("fuzzpercent", Float.toString(fuzzpercent)); + payload.put("seed", seed); + return this.call("getroute", payload); + } + + /** + * Create an invoice for {msatoshi} with {label} and {description} with + * optional {expiry} seconds (default 1 hour) + * + * @param msatoshi + * @param label + * @param description + * @param expiry + * @param fallbacks + * @param preimage + * @return + */ + public String invoice (int msatoshi,String label, String description, int expiry,String fallbacks, String preimage) { + HashMap payload = new HashMap (); + payload.put("msatoshi", Integer.toString(msatoshi)); + payload.put("label", label); + payload.put("description", description); + payload.put("expiry", Integer.toString(expiry)); + payload.put("fallbacks", fallbacks); + payload.put("preimage", preimage); + return this.call("invoice", payload); + } + + /** + * Show funds available for opening channels and open channels + * @return + */ + public String listFunds() { + return this.call("listfunds", null); + } + + /** + * Show all known channels, accept optional {short_channel_id} + */ + public String listChannels(String short_channel_id) { + HashMap payload = new HashMap (); + payload.put("short_channel_id", short_channel_id); + return this.call("listchannels", payload); + } + + /** + * Show invoice {label} (or all, if no {label)) + * @param label for a specific invoice to look up + * @return + */ + public String listInvoices(String label) { + HashMap payload = new HashMap (); + payload.put("label", label); + return this.call("listinvoices", payload); + } + + public String listNodes(String node_id) { + HashMap payload = new HashMap (); + payload.put("id", node_id); + return this.call("listnodes", payload); + } + + /** + * Wait for the next invoice to be paid, after {lastpay_index} + * (if supplied) + * @param last_payindex + * @return + */ + public String waitAnyInvoice(int last_payindex) { + HashMap payload = new HashMap (); + payload.put("last_pay_index", Integer.toString(last_payindex)); + return this.call("waitanyinvoice", payload); + } + + +} diff --git a/contrib/JLightning/src/de/renepickhardt/ln/Status.java b/contrib/JLightning/src/de/renepickhardt/ln/Status.java new file mode 100644 index 000000000000..d407e06e009f --- /dev/null +++ b/contrib/JLightning/src/de/renepickhardt/ln/Status.java @@ -0,0 +1,29 @@ +package de.renepickhardt.ln; +/** + * Named enum to encode the Status of invoices and payments + * + * This file is basically a port of the pylightning python client library + * that comes with c-lightning. + * + * The Author of this Java Client library is Rene Pickhardt. + * He also holds the copyright of this file. The library is licensed with + * a BSD-style license. Have a look at the LICENSE file. + * + * If you like this library consider a donation via bitcoin or the lightning + * network at http://ln.rene-pickhardt.de + * + * @author rpickhardt + */ +public enum Status { + PAID("paid"), UNPAID("unpaid"), EXPIRED("expired"); + + private final String statusDescription; + + private Status(String value) { + statusDescription = value; + } + + public String getStatusDescription() { + return statusDescription; + } +} diff --git a/contrib/JLightning/src/de/renepickhardt/ln/UnixDomainSocketRpc.java b/contrib/JLightning/src/de/renepickhardt/ln/UnixDomainSocketRpc.java new file mode 100644 index 000000000000..ce2e4b77cbac --- /dev/null +++ b/contrib/JLightning/src/de/renepickhardt/ln/UnixDomainSocketRpc.java @@ -0,0 +1,119 @@ +package de.renepickhardt.ln; +/** + * UnixDomainSocketRpc the base class to handle communication between + * JLightning and the c-lightning node over the UnixDomainSocket + * + * This file is basically a port of the pylightning python client library + * that comes with c-lightning. + * + * The Author of this Java Client library is Rene Pickhardt. + * He also holds the copyright of this file. The library is licensed with + * a BSD-style license. Have a look at the LICENSE file. + * + * If you like this library consider a donation via bitcoin or the lightning + * network at http://ln.rene-pickhardt.de + * + * @author Rene Pickhardt + */ + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + + +import org.json.JSONException; +import org.json.JSONObject; +import org.newsclub.net.unix.AFUNIXSocket; +import org.newsclub.net.unix.AFUNIXSocketAddress; + +public class UnixDomainSocketRpc { + protected AFUNIXSocket sock; + protected InputStream is; + protected OutputStream os; + protected static int id = 1; + + public UnixDomainSocketRpc(String socket_path) { + File socketFile = new File(socket_path); + try { + this.sock = AFUNIXSocket.newInstance(); + this.sock.connect(new AFUNIXSocketAddress(socketFile)); + this.is = sock.getInputStream(); + this.os = sock.getOutputStream(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public String call(String method, HashMap payload) { + // if no payload is given make empty one + if(payload == null) { + payload = new HashMap(); + } + + //remove null items from payload + Set keySet = new HashSet(); + for (String key: payload.keySet()) { + keySet.add(key); + } + for(String k:keySet) { + if(payload.get(k)==null){ + payload.remove(k); + } + } + + JSONObject json = new JSONObject(); + + try { + json.put("method", method); + json.put("params", new JSONObject(payload)); + // FIXME: Use id field to dispatch requests + json.put("id", Integer.toString(this.id++)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + this.os.write(json.toString().getBytes("UTF-8")); + this.os.flush(); + + // FIXME: Using a StringBuilder would be preferable but not so easy + String response = ""; + int buffSize = 1024; + byte[] buf = new byte[buffSize]; + + while(true) { + int read = this.is.read(buf); + response = response + new String(buf, 0, read, "UTF-8"); + if(read <=0 || response.contains("\n\n" )) { + break; + } + } + json = new JSONObject(response); + if (json.has("result")) { + json = json.getJSONObject("result"); + return json.toString(2); + } + else if (json.has("error")) { + json = json.getJSONObject("error"); + return json.toString(2); + } + else + return "Could not Parse Response from Lightning Node: " + response; + + } catch (IOException e) { + e.printStackTrace(); + // FIXME: make json rpc? + return "no Response from lightning node"; + } catch (JSONException e) { + e.printStackTrace(); + return "Could not parse response from Lightning Node"; + } + + } +}