Closes #104 DEFAULT_PORTS now a coin property A Peer object maintains peer information Revamp LocalRPC "peers" call to show a lot more information Have lib/jsonrpc.py take care of handling request timeouts Save and restore peers to a file Loosen JSON RPC rules so we work with electrum-server and beancurd which don't follow the spec. Handle incoming server.add_peer requests Send server.add_peer registrations if peer doesn't have us or correct ports Verify peers at regular intervals, forget stale peers, verify new peers or those with updated ports If connecting via one port fails, try the other Add socks.py for SOCKS4 and SOCKS5 proxying, so Tor servers can now be reached by TCP and SSL Put full licence boilerplate in lib/ files Disable IRC advertising on testnet Serve a Tor banner file if it seems like a connection came from your tor proxy (see ENVIONMENT.rst) Retry tor proxy hourly, and peers that are about to turn stale Report more onion peers to a connection that seems to be combing from your tor proxy Only report good peers to server.peers.subscribe; always report self if valid Handle peers on the wrong network robustly Default to 127.0.0.1 rather than localhost for Python <= 3.5.2 compatibility Put peer name in logs of connections to it Update docs
98 lines
2.9 KiB
Python
Executable File
98 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2016, Neil Booth
|
|
#
|
|
# All rights reserved.
|
|
#
|
|
# See the file "LICENCE" for information about the copyright
|
|
# and warranty status of this software.
|
|
|
|
'''Script to send RPC commands to a running ElectrumX server.'''
|
|
|
|
|
|
import argparse
|
|
import asyncio
|
|
import json
|
|
from functools import partial
|
|
from os import environ
|
|
|
|
from lib.jsonrpc import JSONSession, JSONRPCv2
|
|
from server.controller import Controller
|
|
|
|
|
|
class RPCClient(JSONSession):
|
|
|
|
def __init__(self):
|
|
super().__init__(version=JSONRPCv2)
|
|
self.max_send = 0
|
|
self.max_buffer_size = 5*10**6
|
|
self.event = asyncio.Event()
|
|
|
|
def have_pending_items(self):
|
|
self.event.set()
|
|
|
|
async def wait_for_response(self):
|
|
await self.event.wait()
|
|
await self.process_pending_items()
|
|
|
|
def send_rpc_request(self, method, params):
|
|
handler = partial(self.handle_response, method)
|
|
self.send_request(handler, method, params)
|
|
|
|
def handle_response(self, method, result, error):
|
|
if method in ('groups', 'peers', 'sessions') and not error:
|
|
lines_func = getattr(Controller, '{}_text_lines'.format(method))
|
|
for line in lines_func(result):
|
|
print(line)
|
|
elif error:
|
|
print('error: {} (code {:d})'
|
|
.format(error['message'], error['code']))
|
|
else:
|
|
print(json.dumps(result, indent=4, sort_keys=True))
|
|
|
|
|
|
def rpc_send_and_wait(port, method, params, timeout=15):
|
|
loop = asyncio.get_event_loop()
|
|
coro = loop.create_connection(RPCClient, 'localhost', port)
|
|
try:
|
|
transport, rpc_client = loop.run_until_complete(coro)
|
|
rpc_client.send_rpc_request(method, params)
|
|
try:
|
|
coro = rpc_client.wait_for_response()
|
|
loop.run_until_complete(asyncio.wait_for(coro, timeout))
|
|
except asyncio.TimeoutError:
|
|
print('request timed out after {}s'.format(timeout))
|
|
except OSError:
|
|
print('cannot connect - is ElectrumX catching up, not running, or '
|
|
'is {:d} the wrong RPC port?'.format(port))
|
|
finally:
|
|
loop.close()
|
|
|
|
|
|
def main():
|
|
'''Send the RPC command to the server and print the result.'''
|
|
parser = argparse.ArgumentParser('Send electrumx an RPC command' )
|
|
parser.add_argument('-p', '--port', metavar='port_num', type=int,
|
|
help='RPC port number')
|
|
parser.add_argument('command', nargs=1, default=[],
|
|
help='command to send')
|
|
parser.add_argument('param', nargs='*', default=[],
|
|
help='params to send')
|
|
args = parser.parse_args()
|
|
|
|
port = args.port
|
|
if port is None:
|
|
port = int(environ.get('RPC_PORT', 8000))
|
|
|
|
# Get the RPC request.
|
|
method = args.command[0]
|
|
params = args.param
|
|
if method in ('log', 'disconnect'):
|
|
params = [params]
|
|
|
|
rpc_send_and_wait(port, method, params)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|