Merge pull request #391 from pikers/json_rpc_generic
Pull jsonrpc machinery out of deribit backendsize_in_shm_token
commit
71412310c4
|
@ -23,7 +23,6 @@ import time
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from contextlib import asynccontextmanager as acm, AsyncExitStack
|
from contextlib import asynccontextmanager as acm, AsyncExitStack
|
||||||
from itertools import count
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Optional, Iterable, Callable
|
from typing import Any, Optional, Iterable, Callable
|
||||||
|
@ -36,7 +35,11 @@ from fuzzywuzzy import process as fuzzy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from piker.data.types import Struct
|
from piker.data.types import Struct
|
||||||
from piker.data._web_bs import NoBsWs, open_autorecon_ws
|
from piker.data._web_bs import (
|
||||||
|
NoBsWs,
|
||||||
|
open_autorecon_ws,
|
||||||
|
open_jsonrpc_session
|
||||||
|
)
|
||||||
|
|
||||||
from .._util import resproc
|
from .._util import resproc
|
||||||
|
|
||||||
|
@ -422,65 +425,14 @@ async def get_client(
|
||||||
|
|
||||||
async with (
|
async with (
|
||||||
trio.open_nursery() as n,
|
trio.open_nursery() as n,
|
||||||
open_autorecon_ws(_testnet_ws_url) as ws
|
open_jsonrpc_session(
|
||||||
|
_testnet_ws_url, dtype=JSONRPCResult) as json_rpc
|
||||||
):
|
):
|
||||||
|
|
||||||
_rpc_id: Iterable = count(0)
|
|
||||||
_rpc_results: dict[int, dict] = {}
|
|
||||||
|
|
||||||
_expiry_time: int = float('inf')
|
|
||||||
_access_token: Optional[str] = None
|
|
||||||
_refresh_token: Optional[str] = None
|
|
||||||
|
|
||||||
async def json_rpc(method: str, params: dict) -> dict:
|
|
||||||
"""perform a json rpc call and wait for the result, raise exception in
|
|
||||||
case of error field present on response
|
|
||||||
"""
|
|
||||||
msg = {
|
|
||||||
'jsonrpc': '2.0',
|
|
||||||
'id': next(_rpc_id),
|
|
||||||
'method': method,
|
|
||||||
'params': params
|
|
||||||
}
|
|
||||||
_id = msg['id']
|
|
||||||
|
|
||||||
_rpc_results[_id] = {
|
|
||||||
'result': None,
|
|
||||||
'event': trio.Event()
|
|
||||||
}
|
|
||||||
|
|
||||||
await ws.send_msg(msg)
|
|
||||||
|
|
||||||
await _rpc_results[_id]['event'].wait()
|
|
||||||
|
|
||||||
ret = _rpc_results[_id]['result']
|
|
||||||
|
|
||||||
del _rpc_results[_id]
|
|
||||||
|
|
||||||
if ret.error is not None:
|
|
||||||
raise Exception(json.dumps(ret.error, indent=4))
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
async def _recv_task():
|
|
||||||
"""receives every ws message and stores it in its corresponding result
|
|
||||||
field, then sets the event to wakeup original sender tasks.
|
|
||||||
"""
|
|
||||||
async for msg in ws:
|
|
||||||
msg = JSONRPCResult(**msg)
|
|
||||||
|
|
||||||
if msg.id not in _rpc_results:
|
|
||||||
# in case this message wasn't beign accounted for store it
|
|
||||||
_rpc_results[msg.id] = {
|
|
||||||
'result': None,
|
|
||||||
'event': trio.Event()
|
|
||||||
}
|
|
||||||
|
|
||||||
_rpc_results[msg.id]['result'] = msg
|
|
||||||
_rpc_results[msg.id]['event'].set()
|
|
||||||
|
|
||||||
client = Client(json_rpc)
|
client = Client(json_rpc)
|
||||||
|
|
||||||
|
_refresh_token: Optional[str] = None
|
||||||
|
_access_token: Optional[str] = None
|
||||||
|
|
||||||
async def _auth_loop(
|
async def _auth_loop(
|
||||||
task_status: TaskStatus = trio.TASK_STATUS_IGNORED
|
task_status: TaskStatus = trio.TASK_STATUS_IGNORED
|
||||||
):
|
):
|
||||||
|
@ -536,7 +488,6 @@ async def get_client(
|
||||||
else:
|
else:
|
||||||
await trio.sleep(renew_time / 2)
|
await trio.sleep(renew_time / 2)
|
||||||
|
|
||||||
n.start_soon(_recv_task)
|
|
||||||
# if we have client creds launch auth loop
|
# if we have client creds launch auth loop
|
||||||
if client._key_id is not None:
|
if client._key_id is not None:
|
||||||
await n.start(_auth_loop)
|
await n.start(_auth_loop)
|
||||||
|
|
|
@ -19,6 +19,7 @@ ToOlS fOr CoPInG wITh "tHE wEB" protocols.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from contextlib import asynccontextmanager, AsyncExitStack
|
from contextlib import asynccontextmanager, AsyncExitStack
|
||||||
|
from itertools import count
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Any, Optional, Callable, AsyncGenerator
|
from typing import Any, Optional, Callable, AsyncGenerator
|
||||||
import json
|
import json
|
||||||
|
@ -35,6 +36,8 @@ from trio_websocket._impl import (
|
||||||
|
|
||||||
from ..log import get_logger
|
from ..log import get_logger
|
||||||
|
|
||||||
|
from .types import Struct
|
||||||
|
|
||||||
log = get_logger(__name__)
|
log = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -150,3 +153,86 @@ async def open_autorecon_ws(
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
await stack.aclose()
|
await stack.aclose()
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
JSONRPC response-request style machinery for transparent multiplexing of msgs
|
||||||
|
over a NoBsWs.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class JSONRPCResult(Struct):
|
||||||
|
jsonrpc: str = '2.0'
|
||||||
|
id: int
|
||||||
|
result: Optional[dict] = None
|
||||||
|
error: Optional[dict] = None
|
||||||
|
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def open_jsonrpc_session(
|
||||||
|
url: str,
|
||||||
|
start_id: int = 0,
|
||||||
|
dtype: type = JSONRPCResult
|
||||||
|
) -> Callable[[str, dict], dict]:
|
||||||
|
|
||||||
|
async with (
|
||||||
|
trio.open_nursery() as n,
|
||||||
|
open_autorecon_ws(url) as ws
|
||||||
|
):
|
||||||
|
rpc_id: Iterable = count(start_id)
|
||||||
|
rpc_results: dict[int, dict] = {}
|
||||||
|
|
||||||
|
async def json_rpc(method: str, params: dict) -> dict:
|
||||||
|
'''
|
||||||
|
perform a json rpc call and wait for the result, raise exception in
|
||||||
|
case of error field present on response
|
||||||
|
'''
|
||||||
|
msg = {
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': next(rpc_id),
|
||||||
|
'method': method,
|
||||||
|
'params': params
|
||||||
|
}
|
||||||
|
_id = msg['id']
|
||||||
|
|
||||||
|
rpc_results[_id] = {
|
||||||
|
'result': None,
|
||||||
|
'event': trio.Event()
|
||||||
|
}
|
||||||
|
|
||||||
|
await ws.send_msg(msg)
|
||||||
|
|
||||||
|
await rpc_results[_id]['event'].wait()
|
||||||
|
|
||||||
|
ret = rpc_results[_id]['result']
|
||||||
|
|
||||||
|
del rpc_results[_id]
|
||||||
|
|
||||||
|
if ret.error is not None:
|
||||||
|
raise Exception(json.dumps(ret.error, indent=4))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
async def recv_task():
|
||||||
|
'''
|
||||||
|
receives every ws message and stores it in its corresponding result
|
||||||
|
field, then sets the event to wakeup original sender tasks.
|
||||||
|
'''
|
||||||
|
async for msg in ws:
|
||||||
|
msg = dtype(**msg)
|
||||||
|
|
||||||
|
if msg.id not in rpc_results:
|
||||||
|
log.warning(f'Wasn\'t expecting ws msg: {json.dumps(msg, indent=4)}')
|
||||||
|
|
||||||
|
res = rpc_results.setdefault(
|
||||||
|
msg.id,
|
||||||
|
{'result': None, 'event': trio.Event()}
|
||||||
|
)
|
||||||
|
|
||||||
|
res['result'] = msg
|
||||||
|
res['event'].set()
|
||||||
|
|
||||||
|
|
||||||
|
n.start_soon(recv_task)
|
||||||
|
yield json_rpc
|
||||||
|
n.cancel_scope.cancel()
|
||||||
|
|
Loading…
Reference in New Issue