2017-01-14 20:30:37 +01:00
|
|
|
from concurrent import futures
|
|
|
|
|
|
|
|
import io
|
|
|
|
import json
|
|
|
|
import logging
|
|
|
|
import socket
|
|
|
|
import sys
|
|
|
|
import threading
|
|
|
|
|
2017-01-17 23:26:00 +01:00
|
|
|
class UnixDomainSocketRpc(object):
|
2017-01-14 20:30:37 +01:00
|
|
|
def __init__(self, socket_path, executor=None):
|
|
|
|
self.socket_path = socket_path
|
|
|
|
self.decoder = json.JSONDecoder()
|
|
|
|
self.executor = executor
|
|
|
|
|
|
|
|
def _writeobj(self, sock, obj):
|
|
|
|
s = json.dumps(obj)
|
|
|
|
sock.sendall(bytearray(s, 'UTF-8'))
|
|
|
|
|
|
|
|
def _readobj(self, sock):
|
|
|
|
buff = b''
|
|
|
|
while True:
|
|
|
|
try:
|
2017-03-18 16:06:52 +01:00
|
|
|
b = sock.recv(1024)
|
|
|
|
buff += b
|
|
|
|
if len(b) == 0:
|
|
|
|
return {'error': 'Connection to RPC server lost.'}
|
2017-01-14 20:30:37 +01:00
|
|
|
# Convert late to UTF-8 so glyphs split across recvs do not
|
|
|
|
# impact us
|
|
|
|
objs, _ = self.decoder.raw_decode(buff.decode("UTF-8"))
|
|
|
|
return objs
|
|
|
|
except ValueError:
|
|
|
|
# Probably didn't read enough
|
|
|
|
pass
|
|
|
|
|
2017-04-12 20:08:48 +02:00
|
|
|
def __getattr__(self, name):
|
|
|
|
"""Intercept any call that is not explicitly defined and call _call
|
|
|
|
|
|
|
|
We might still want to define the actual methods in the subclasses for
|
|
|
|
documentation purposes.
|
|
|
|
"""
|
|
|
|
name = name.replace('_', '-')
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
return self._call(name, args)
|
|
|
|
return wrapper
|
|
|
|
|
2017-01-14 20:30:37 +01:00
|
|
|
def _call(self, method, args):
|
|
|
|
logging.debug("Calling %s with arguments %r", method, args)
|
|
|
|
|
|
|
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
|
|
sock.connect(self.socket_path)
|
|
|
|
self._writeobj(sock, {
|
|
|
|
"method": method,
|
|
|
|
"params": args,
|
|
|
|
"id": 0
|
|
|
|
})
|
|
|
|
resp = self._readobj(sock)
|
|
|
|
sock.close()
|
|
|
|
|
|
|
|
logging.debug("Received response for %s call: %r", method, resp)
|
|
|
|
if 'error' in resp:
|
|
|
|
raise ValueError("RPC call failed: {}".format(resp['error']))
|
|
|
|
elif 'result' not in resp:
|
|
|
|
raise ValueError("Malformed response, 'result' missing.")
|
|
|
|
return resp['result']
|
|
|
|
|
2017-01-17 23:26:00 +01:00
|
|
|
|
|
|
|
class LightningRpc(UnixDomainSocketRpc):
|
|
|
|
"""RPC client for the `lightningd` daemon.
|
|
|
|
|
|
|
|
This RPC client connects to the `lightningd` daemon through a unix
|
|
|
|
domain socket and passes calls through. Since some of the calls
|
|
|
|
are blocking, the corresponding python methods include an `async`
|
|
|
|
keyword argument. If `async` is set to true then the method
|
|
|
|
returns a future immediately, instead of blocking indefinitely.
|
|
|
|
|
|
|
|
This implementation is thread safe in that it locks the socket
|
|
|
|
between calls, but it does not (yet) support concurrent calls.
|
|
|
|
"""
|
|
|
|
|
2017-04-29 03:02:27 +02:00
|
|
|
def getpeer(self, peer_id, log_level=None):
|
|
|
|
"""Get info about a specific peer, optionally with its log.
|
2017-01-17 23:26:00 +01:00
|
|
|
"""
|
2017-04-29 03:02:27 +02:00
|
|
|
if log_level:
|
|
|
|
peers = self.getpeers(log_level)['peers']
|
|
|
|
else:
|
|
|
|
peers = self.getpeers()['peers']
|
2017-01-17 23:26:00 +01:00
|
|
|
for p in peers:
|
|
|
|
if p['peerid'] == peer_id:
|
|
|
|
return p
|
|
|
|
return None
|
|
|
|
|
|
|
|
def getlog(self, level=None):
|
|
|
|
args = []
|
|
|
|
if level is not None:
|
|
|
|
args.append(level)
|
|
|
|
return self._call("getlog", args)
|
|
|
|
|
|
|
|
def dev_add_route(self, src, dst, base, var, delay, minblocks):
|
2017-04-12 20:08:48 +02:00
|
|
|
""" Add a route from src to dst using the given parameters.
|
|
|
|
|
|
|
|
Add route from {src} to {dst}, {base} rate in msatoshi, {var} rate in
|
|
|
|
msatoshi, {delay} blocks delay and {minblocks} minimum timeout
|
2017-01-17 23:26:00 +01:00
|
|
|
"""
|
|
|
|
return self._call("dev-add-route", [src, dst, base, var, delay, minblocks])
|
|
|
|
|
2017-03-15 21:52:49 +01:00
|
|
|
|
2017-01-14 20:30:37 +01:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
l1 = LightningRpc("/tmp/lightning1/lightning-rpc")
|
|
|
|
l5 = LightningRpc("/tmp/lightning5/lightning-rpc")
|
|
|
|
|
|
|
|
import random
|
|
|
|
|
|
|
|
info5 = l5.getinfo()
|
|
|
|
print(info5)
|
2017-11-05 13:38:15 +01:00
|
|
|
invoice = l5.invoice(100, "lbl{}".format(random.random()), "testpayment")
|
2017-01-14 20:30:37 +01:00
|
|
|
print(invoice)
|
|
|
|
route = l1.getroute(info5['id'], 100, 1)
|
|
|
|
print(route)
|
2017-11-05 13:38:15 +01:00
|
|
|
print(l1.sendpay(route['route'], invoice['rhash']))
|