Merge pull request #6220 from spesmilo/jsonrpc_nodeps
Remove dependencies: jsonrpcserver, jsonrpcclient
This commit is contained in:
@@ -50,8 +50,6 @@ datas += collect_data_files('btchip')
|
|||||||
datas += collect_data_files('keepkeylib')
|
datas += collect_data_files('keepkeylib')
|
||||||
datas += collect_data_files('ckcc')
|
datas += collect_data_files('ckcc')
|
||||||
datas += collect_data_files('bitbox02')
|
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
|
# 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',
|
a = Analysis([home+'run_electrum',
|
||||||
|
|||||||
@@ -83,8 +83,6 @@ datas += collect_data_files('btchip')
|
|||||||
datas += collect_data_files('keepkeylib')
|
datas += collect_data_files('keepkeylib')
|
||||||
datas += collect_data_files('ckcc')
|
datas += collect_data_files('ckcc')
|
||||||
datas += collect_data_files('bitbox02')
|
datas += collect_data_files('bitbox02')
|
||||||
datas += collect_data_files('jsonrpcserver')
|
|
||||||
datas += collect_data_files('jsonrpcclient')
|
|
||||||
|
|
||||||
# Add the QR Scanner helper app
|
# Add the QR Scanner helper app
|
||||||
datas += [(electrum + "contrib/osx/CalinsQRReader/build/Release/CalinsQRReader.app", "./contrib/osx/CalinsQRReader/build/Release/CalinsQRReader.app")]
|
datas += [(electrum + "contrib/osx/CalinsQRReader/build/Release/CalinsQRReader.app", "./contrib/osx/CalinsQRReader/build/Release/CalinsQRReader.app")]
|
||||||
|
|||||||
@@ -9,6 +9,4 @@ aiohttp>=3.3.0,<4.0.0
|
|||||||
aiohttp_socks>=0.3
|
aiohttp_socks>=0.3
|
||||||
certifi
|
certifi
|
||||||
bitstring
|
bitstring
|
||||||
jsonrpcserver
|
|
||||||
jsonrpcclient
|
|
||||||
attrs
|
attrs
|
||||||
|
|||||||
@@ -29,18 +29,15 @@ import time
|
|||||||
import traceback
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
import threading
|
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 base64 import b64decode, b64encode
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import concurrent
|
import concurrent
|
||||||
from concurrent import futures
|
from concurrent import futures
|
||||||
|
import json
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from aiohttp import web, client_exceptions
|
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 aiorpcx import TaskGroup
|
||||||
|
|
||||||
from . import util
|
from . import util
|
||||||
@@ -107,10 +104,8 @@ def request(config: SimpleConfig, endpoint, args=(), timeout=60):
|
|||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
async def request_coroutine():
|
async def request_coroutine():
|
||||||
async with aiohttp.ClientSession(auth=auth) as session:
|
async with aiohttp.ClientSession(auth=auth) as session:
|
||||||
server = AiohttpClient(session, server_url, timeout=timeout)
|
c = util.JsonRPCClient(session, server_url)
|
||||||
f = getattr(server, endpoint)
|
return await c.request(endpoint, *args)
|
||||||
response = await f(*args)
|
|
||||||
return response.data.result
|
|
||||||
try:
|
try:
|
||||||
fut = asyncio.run_coroutine_threadsafe(request_coroutine(), loop)
|
fut = asyncio.run_coroutine_threadsafe(request_coroutine(), loop)
|
||||||
return fut.result(timeout=timeout)
|
return fut.result(timeout=timeout)
|
||||||
@@ -156,6 +151,11 @@ class AuthenticatedServer(Logger):
|
|||||||
self.rpc_user = rpc_user
|
self.rpc_user = rpc_user
|
||||||
self.rpc_password = rpc_password
|
self.rpc_password = rpc_password
|
||||||
self.auth_lock = asyncio.Lock()
|
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):
|
async def authenticate(self, headers):
|
||||||
if self.rpc_password == '':
|
if self.rpc_password == '':
|
||||||
@@ -184,16 +184,28 @@ class AuthenticatedServer(Logger):
|
|||||||
text='Unauthorized', status=401)
|
text='Unauthorized', status=401)
|
||||||
except AuthenticationCredentialsInvalid:
|
except AuthenticationCredentialsInvalid:
|
||||||
return web.Response(text='Forbidden', status=403)
|
return web.Response(text='Forbidden', status=403)
|
||||||
request = await request.text()
|
try:
|
||||||
response = await jsonrpcserver.async_dispatch(request, methods=self.methods)
|
request = await request.text()
|
||||||
if isinstance(response, jsonrpcserver.response.ExceptionResponse):
|
request = json.loads(request)
|
||||||
self.logger.error(f"error handling request: {request}", exc_info=response.exc)
|
method = request['method']
|
||||||
# this exposes the error message to the client
|
_id = request['id']
|
||||||
response.message = str(response.exc)
|
params = request.get('params', []) # type: Union[Sequence, Mapping]
|
||||||
if response.wanted:
|
if method not in self._methods:
|
||||||
return web.json_response(response.deserialized(), status=response.http_status)
|
raise Exception(f"attempting to use unregistered method: {method}")
|
||||||
else:
|
f = self._methods[method]
|
||||||
return web.Response()
|
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):
|
class CommandsServer(AuthenticatedServer):
|
||||||
@@ -208,13 +220,12 @@ class CommandsServer(AuthenticatedServer):
|
|||||||
self.port = self.config.get('rpcport', 0)
|
self.port = self.config.get('rpcport', 0)
|
||||||
self.app = web.Application()
|
self.app = web.Application()
|
||||||
self.app.router.add_post("/", self.handle)
|
self.app.router.add_post("/", self.handle)
|
||||||
self.methods = jsonrpcserver.methods.Methods()
|
self.register_method(self.ping)
|
||||||
self.methods.add(self.ping)
|
self.register_method(self.gui)
|
||||||
self.methods.add(self.gui)
|
|
||||||
self.cmd_runner = Commands(config=self.config, network=self.daemon.network, daemon=self.daemon)
|
self.cmd_runner = Commands(config=self.config, network=self.daemon.network, daemon=self.daemon)
|
||||||
for cmdname in known_commands:
|
for cmdname in known_commands:
|
||||||
self.methods.add(getattr(self.cmd_runner, cmdname))
|
self.register_method(getattr(self.cmd_runner, cmdname))
|
||||||
self.methods.add(self.run_cmdline)
|
self.register_method(self.run_cmdline)
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
self.runner = web.AppRunner(self.app)
|
self.runner = web.AppRunner(self.app)
|
||||||
@@ -276,9 +287,8 @@ class WatchTowerServer(AuthenticatedServer):
|
|||||||
self.lnwatcher = network.local_watchtower
|
self.lnwatcher = network.local_watchtower
|
||||||
self.app = web.Application()
|
self.app = web.Application()
|
||||||
self.app.router.add_post("/", self.handle)
|
self.app.router.add_post("/", self.handle)
|
||||||
self.methods = jsonrpcserver.methods.Methods()
|
self.register_method(self.get_ctn)
|
||||||
self.methods.add(self.get_ctn)
|
self.register_method(self.add_sweep_tx)
|
||||||
self.methods.add(self.add_sweep_tx)
|
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
self.runner = web.AppRunner(self.app)
|
self.runner = web.AppRunner(self.app)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import time
|
|||||||
from typing import Optional, Sequence, Tuple, List, Dict, TYPE_CHECKING, NamedTuple, Union, Mapping
|
from typing import Optional, Sequence, Tuple, List, Dict, TYPE_CHECKING, NamedTuple, Union, Mapping
|
||||||
import threading
|
import threading
|
||||||
import socket
|
import socket
|
||||||
|
import aiohttp
|
||||||
import json
|
import json
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from functools import partial
|
from functools import partial
|
||||||
@@ -25,7 +26,7 @@ from . import constants, util
|
|||||||
from . import keystore
|
from . import keystore
|
||||||
from .util import profiler
|
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 .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 .lnutil import LN_MAX_FUNDING_SAT
|
||||||
from .keystore import BIP32_KeyStore
|
from .keystore import BIP32_KeyStore
|
||||||
from .bitcoin import COIN
|
from .bitcoin import COIN
|
||||||
@@ -525,12 +526,6 @@ class LNWallet(LNWorker):
|
|||||||
@ignore_exceptions
|
@ignore_exceptions
|
||||||
@log_exceptions
|
@log_exceptions
|
||||||
async def sync_with_remote_watchtower(self):
|
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:
|
while True:
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
watchtower_url = self.config.get('watchtower_url')
|
watchtower_url = self.config.get('watchtower_url')
|
||||||
@@ -538,7 +533,9 @@ class LNWallet(LNWorker):
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
async with make_aiohttp_session(proxy=self.network.proxy) as session:
|
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():
|
for chan in self.channels.values():
|
||||||
await self.sync_channel_with_watchtower(chan, watchtower)
|
await self.sync_channel_with_watchtower(chan, watchtower)
|
||||||
except aiohttp.client_exceptions.ClientConnectorError:
|
except aiohttp.client_exceptions.ClientConnectorError:
|
||||||
|
|||||||
@@ -1368,3 +1368,33 @@ class MySocksProxy(aiorpcx.SOCKSProxy):
|
|||||||
else:
|
else:
|
||||||
raise NotImplementedError # http proxy not available with aiorpcx
|
raise NotImplementedError # http proxy not available with aiorpcx
|
||||||
return ret
|
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)
|
||||||
|
|||||||
Reference in New Issue
Block a user