Browse Source

Merge pull request #6220 from spesmilo/jsonrpc_nodeps

Remove dependencies: jsonrpcserver, jsonrpcclient
bip39-recovery
ThomasV 5 years ago
committed by GitHub
parent
commit
d9c5258014
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      contrib/build-wine/deterministic.spec
  2. 2
      contrib/osx/osx.spec
  3. 2
      contrib/requirements/requirements.txt
  4. 64
      electrum/daemon.py
  5. 13
      electrum/lnworker.py
  6. 30
      electrum/util.py

2
contrib/build-wine/deterministic.spec

@ -50,8 +50,6 @@ datas += collect_data_files('btchip')
datas += collect_data_files('keepkeylib')
datas += collect_data_files('ckcc')
datas += collect_data_files('bitbox02')
datas += collect_data_files('jsonrpcserver')
datas += collect_data_files('jsonrpcclient')
# We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports
a = Analysis([home+'run_electrum',

2
contrib/osx/osx.spec

@ -83,8 +83,6 @@ datas += collect_data_files('btchip')
datas += collect_data_files('keepkeylib')
datas += collect_data_files('ckcc')
datas += collect_data_files('bitbox02')
datas += collect_data_files('jsonrpcserver')
datas += collect_data_files('jsonrpcclient')
# Add the QR Scanner helper app
datas += [(electrum + "contrib/osx/CalinsQRReader/build/Release/CalinsQRReader.app", "./contrib/osx/CalinsQRReader/build/Release/CalinsQRReader.app")]

2
contrib/requirements/requirements.txt

@ -9,6 +9,4 @@ aiohttp>=3.3.0,<4.0.0
aiohttp_socks>=0.3
certifi
bitstring
jsonrpcserver
jsonrpcclient
attrs

64
electrum/daemon.py

@ -29,18 +29,15 @@ import time
import traceback
import sys
import threading
from typing import Dict, Optional, Tuple, Iterable
from typing import Dict, Optional, Tuple, Iterable, Callable, Union, Sequence, Mapping
from base64 import b64decode, b64encode
from collections import defaultdict
import concurrent
from concurrent import futures
import json
import aiohttp
from aiohttp import web, client_exceptions
import jsonrpcclient
import jsonrpcserver
from jsonrpcserver import response
from jsonrpcclient.clients.aiohttp_client import AiohttpClient
from aiorpcx import TaskGroup
from . import util
@ -107,10 +104,8 @@ def request(config: SimpleConfig, endpoint, args=(), timeout=60):
loop = asyncio.get_event_loop()
async def request_coroutine():
async with aiohttp.ClientSession(auth=auth) as session:
server = AiohttpClient(session, server_url, timeout=timeout)
f = getattr(server, endpoint)
response = await f(*args)
return response.data.result
c = util.JsonRPCClient(session, server_url)
return await c.request(endpoint, *args)
try:
fut = asyncio.run_coroutine_threadsafe(request_coroutine(), loop)
return fut.result(timeout=timeout)
@ -156,6 +151,11 @@ class AuthenticatedServer(Logger):
self.rpc_user = rpc_user
self.rpc_password = rpc_password
self.auth_lock = asyncio.Lock()
self._methods = {} # type: Dict[str, Callable]
def register_method(self, f):
assert f.__name__ not in self._methods, f"name collision for {f.__name__}"
self._methods[f.__name__] = f
async def authenticate(self, headers):
if self.rpc_password == '':
@ -184,16 +184,28 @@ class AuthenticatedServer(Logger):
text='Unauthorized', status=401)
except AuthenticationCredentialsInvalid:
return web.Response(text='Forbidden', status=403)
request = await request.text()
response = await jsonrpcserver.async_dispatch(request, methods=self.methods)
if isinstance(response, jsonrpcserver.response.ExceptionResponse):
self.logger.error(f"error handling request: {request}", exc_info=response.exc)
# this exposes the error message to the client
response.message = str(response.exc)
if response.wanted:
return web.json_response(response.deserialized(), status=response.http_status)
else:
return web.Response()
try:
request = await request.text()
request = json.loads(request)
method = request['method']
_id = request['id']
params = request.get('params', []) # type: Union[Sequence, Mapping]
if method not in self._methods:
raise Exception(f"attempting to use unregistered method: {method}")
f = self._methods[method]
except Exception as e:
self.logger.exception("invalid request")
return web.Response(text='Invalid Request', status=500)
response = {'id': _id}
try:
if isinstance(params, dict):
response['result'] = await f(**params)
else:
response['result'] = await f(*params)
except BaseException as e:
self.logger.exception("internal error while executing RPC")
response['error'] = str(e)
return web.json_response(response)
class CommandsServer(AuthenticatedServer):
@ -208,13 +220,12 @@ class CommandsServer(AuthenticatedServer):
self.port = self.config.get('rpcport', 0)
self.app = web.Application()
self.app.router.add_post("/", self.handle)
self.methods = jsonrpcserver.methods.Methods()
self.methods.add(self.ping)
self.methods.add(self.gui)
self.register_method(self.ping)
self.register_method(self.gui)
self.cmd_runner = Commands(config=self.config, network=self.daemon.network, daemon=self.daemon)
for cmdname in known_commands:
self.methods.add(getattr(self.cmd_runner, cmdname))
self.methods.add(self.run_cmdline)
self.register_method(getattr(self.cmd_runner, cmdname))
self.register_method(self.run_cmdline)
async def run(self):
self.runner = web.AppRunner(self.app)
@ -276,9 +287,8 @@ class WatchTowerServer(AuthenticatedServer):
self.lnwatcher = network.local_watchtower
self.app = web.Application()
self.app.router.add_post("/", self.handle)
self.methods = jsonrpcserver.methods.Methods()
self.methods.add(self.get_ctn)
self.methods.add(self.add_sweep_tx)
self.register_method(self.get_ctn)
self.register_method(self.add_sweep_tx)
async def run(self):
self.runner = web.AppRunner(self.app)

13
electrum/lnworker.py

@ -10,6 +10,7 @@ import time
from typing import Optional, Sequence, Tuple, List, Dict, TYPE_CHECKING, NamedTuple, Union, Mapping
import threading
import socket
import aiohttp
import json
from datetime import datetime, timezone
from functools import partial
@ -25,7 +26,7 @@ from . import constants, util
from . import keystore
from .util import profiler
from .invoices import PR_TYPE_LN, PR_UNPAID, PR_EXPIRED, PR_PAID, PR_INFLIGHT, PR_FAILED, PR_ROUTING, LNInvoice, LN_EXPIRY_NEVER
from .util import NetworkRetryManager
from .util import NetworkRetryManager, JsonRPCClient
from .lnutil import LN_MAX_FUNDING_SAT
from .keystore import BIP32_KeyStore
from .bitcoin import COIN
@ -525,12 +526,6 @@ class LNWallet(LNWorker):
@ignore_exceptions
@log_exceptions
async def sync_with_remote_watchtower(self):
import aiohttp
from jsonrpcclient.clients.aiohttp_client import AiohttpClient
class myAiohttpClient(AiohttpClient):
async def request(self, *args, **kwargs):
r = await super().request(*args, **kwargs)
return r.data.result
while True:
await asyncio.sleep(5)
watchtower_url = self.config.get('watchtower_url')
@ -538,7 +533,9 @@ class LNWallet(LNWorker):
continue
try:
async with make_aiohttp_session(proxy=self.network.proxy) as session:
watchtower = myAiohttpClient(session, watchtower_url)
watchtower = JsonRPCClient(session, watchtower_url)
watchtower.add_method('get_ctn')
watchtower.add_method('add_sweep_tx')
for chan in self.channels.values():
await self.sync_channel_with_watchtower(chan, watchtower)
except aiohttp.client_exceptions.ClientConnectorError:

30
electrum/util.py

@ -1368,3 +1368,33 @@ class MySocksProxy(aiorpcx.SOCKSProxy):
else:
raise NotImplementedError # http proxy not available with aiorpcx
return ret
class JsonRPCClient:
def __init__(self, session: aiohttp.ClientSession, url: str):
self.session = session
self.url = url
self._id = 0
async def request(self, endpoint, *args):
self._id += 1
data = ('{"jsonrpc": "2.0", "id":"%d", "method": "%s", "params": %s }'
% (self._id, endpoint, json.dumps(args)))
async with self.session.post(self.url, data=data) as resp:
if resp.status == 200:
r = await resp.json()
result = r.get('result')
error = r.get('error')
if error:
return 'Error: ' + str(error)
else:
return result
else:
text = await resp.text()
return 'Error: ' + str(text)
def add_method(self, endpoint):
async def coro(*args):
return await self.request(endpoint, *args)
setattr(self, endpoint, coro)

Loading…
Cancel
Save