|
|
|
import json
|
|
|
|
|
|
|
|
import requests
|
|
|
|
|
|
|
|
from .exceptions import (
|
|
|
|
RequestsError,
|
|
|
|
RequestsTimeoutError,
|
|
|
|
RPCError
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
_default_endpoint = 'http://localhost:9500'
|
|
|
|
_default_timeout = 30
|
|
|
|
|
|
|
|
|
|
|
|
def base_request(method, params=None, endpoint=_default_endpoint, timeout=_default_timeout) -> str:
|
|
|
|
"""
|
|
|
|
Basic RPC request
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
---------
|
|
|
|
method: str
|
|
|
|
RPC Method to call
|
|
|
|
params: :obj:`list`, optional
|
|
|
|
Parameters for the RPC method
|
|
|
|
endpoint: :obj:`str`, optional
|
|
|
|
Endpoint to send request to
|
|
|
|
timeout: :obj:`int`, optional
|
|
|
|
Timeout in seconds
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
str
|
|
|
|
Raw output from the request
|
|
|
|
|
|
|
|
Raises
|
|
|
|
------
|
|
|
|
TypeError
|
|
|
|
If params is not a list or None
|
|
|
|
RequestsTimeoutError
|
|
|
|
If request timed out
|
|
|
|
RequestsError
|
|
|
|
If other request error occured
|
|
|
|
"""
|
|
|
|
if params is None:
|
|
|
|
params = []
|
|
|
|
elif not isinstance(params, list):
|
|
|
|
raise TypeError(f'invalid type {params.__class__}')
|
|
|
|
|
|
|
|
try:
|
|
|
|
payload = {
|
|
|
|
"id": "1",
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": method,
|
|
|
|
"params": params
|
|
|
|
}
|
|
|
|
headers = {
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = requests.request('POST', endpoint, headers=headers, data=json.dumps(payload),
|
|
|
|
timeout=timeout, allow_redirects=True)
|
|
|
|
return resp.content
|
|
|
|
except requests.exceptions.Timeout as err:
|
|
|
|
raise RequestsTimeoutError(endpoint) from err
|
|
|
|
except requests.exceptions.RequestException as err:
|
|
|
|
raise RequestsError(endpoint) from err
|
|
|
|
|
|
|
|
|
|
|
|
def rpc_request(method, params=None, endpoint=_default_endpoint, timeout=_default_timeout) -> dict:
|
|
|
|
"""
|
|
|
|
RPC request
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
---------
|
|
|
|
method: str
|
|
|
|
RPC Method to call
|
|
|
|
params: :obj:`list`, optional
|
|
|
|
Parameters for the RPC method
|
|
|
|
endpoint: :obj:`str`, optional
|
|
|
|
Endpoint to send request to
|
|
|
|
timeout: :obj:`int`, optional
|
|
|
|
Timeout in seconds
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
dict
|
|
|
|
Returns dictionary representation of RPC response
|
|
|
|
Example format:
|
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id": 1,
|
|
|
|
"result": ...
|
|
|
|
}
|
|
|
|
|
|
|
|
Raises
|
|
|
|
------
|
|
|
|
RPCError
|
|
|
|
If RPC response returned a blockchain error
|
|
|
|
|
|
|
|
See Also
|
|
|
|
--------
|
|
|
|
base_request
|
|
|
|
"""
|
|
|
|
raw_resp = base_request(method, params, endpoint, timeout)
|
|
|
|
|
|
|
|
try:
|
|
|
|
resp = json.loads(raw_resp)
|
|
|
|
if 'error' in resp:
|
|
|
|
raise RPCError(method, endpoint, str(resp['error']))
|
|
|
|
return resp
|
|
|
|
except json.decoder.JSONDecodeError as err:
|
|
|
|
raise RPCError(method, endpoint, raw_resp) from err
|
|
|
|
|
|
|
|
|
|
|
|
# TODO: Add GET requests
|