jsonrpc
— JSON RPC Client/server¶
Note
This is a Json RPC library by Roland Koebler and the documentation is included here only for developer reference.
JSON-RPC (remote procedure call).
- It consists of 3 (independent) parts:
- proxy/dispatcher
- data structure / serializer
- transport
It’s intended for JSON-RPC, but since the above 3 parts are independent, it could be used for other RPCs as well.
Currently, JSON-RPC 2.0 and JSON-RPC 1.0 are implemented
version: | 2017-12-03-RELEASE |
---|---|
status: | experimental |
example: | simple Client with JsonRPC 2.0 and TCP/IP: >>> proxy = ServerProxy( JsonRpc20(), TransportTcpIp(addr=("127.0.0.1",31415)) )
>>> proxy.echo( "hello world" )
u'hello world'
>>> proxy.echo( "bye." )
u'bye.'
simple Server with JsonRPC2.0 and TCP/IP with logging to STDOUT: >>> server = Server( JsonRpc20(), TransportTcpIp(addr=("127.0.0.1",31415), logfunc=log_stdout) )
>>> def echo( s ):
... return s
>>> server.register_function( echo )
>>> server.serve( 2 ) # serve 2 requests
listen ('127.0.0.1', 31415)
('127.0.0.1', ...) connected
('127.0.0.1', ...) <-- {"jsonrpc": "2.0", "method": "echo", "params": ["hello world"], "id": 0}
('127.0.0.1', ...) --> {"jsonrpc": "2.0", "result": "hello world", "id": 0}
('127.0.0.1', ...) close
('127.0.0.1', ...) connected
('127.0.0.1', ...) <-- {"jsonrpc": "2.0", "method": "echo", "params": ["bye."], "id": 0}
('127.0.0.1', ...) --> {"jsonrpc": "2.0", "result": "bye.", "id": 0}
('127.0.0.1', ...) close
close ('127.0.0.1', 31415)
Client with JsonRPC2.0 and an abstract Unix Domain Socket: >>> proxy = ServerProxy( JsonRpc20(), TransportUnixSocket(addr="\x00.rpcsocket") )
>>> proxy.hi( message="hello" ) #named parameters
u'hi there'
>>> proxy.test() #fault
Traceback (most recent call last):
...
jsonrpc.RPCMethodNotFound: <RPCFault -32601: u'Method not found.' (None)>
>>> proxy.debug.echo( "hello world" ) #hierarchical procedures
u'hello world'
Server with JsonRPC2.0 and abstract Unix Domain Socket with a logfile: >>> server = Server( JsonRpc20(), TransportUnixSocket(addr="\x00.rpcsocket", logfunc=log_file("mylog.txt")) )
>>> def echo( s ):
... return s
>>> def hi( message ):
... return "hi there"
>>> server.register_function( hi )
>>> server.register_function( echo, name="debug.echo" )
>>> server.serve( 3 ) # serve 3 requests
"mylog.txt" then contains:
listen '\x00.rpcsocket'
'' connected
'' --> '{"jsonrpc": "2.0", "method": "hi", "params": {"message": "hello"}, "id": 0}'
'' <-- '{"jsonrpc": "2.0", "result": "hi there", "id": 0}'
'' close
'' connected
'' --> '{"jsonrpc": "2.0", "method": "test", "id": 0}'
'' <-- '{"jsonrpc": "2.0", "error": {"code":-32601, "message": "Method not found."}, "id": 0}'
'' close
'' connected
'' --> '{"jsonrpc": "2.0", "method": "debug.echo", "params": ["hello world"], "id": 0}'
'' <-- '{"jsonrpc": "2.0", "result": "hello world", "id": 0}'
'' close
close '\x00.rpcsocket'
|
note: | all exceptions derived from RPCFault are propagated to the client. other exceptions are logged and result in a sent-back “empty” INTERNAL_ERROR. |
uses: | logging, sys, json, codecs, time, socket, select |
seealso: | JSON-RPC 2.0 proposal, 1.0 specification |
warning: | Warning This is experimental code! |
author: | Dave Pedu (dave(at)davepedu.com) |
changelog: |
|
todo: |
|
-
class
pyircbot.jsonrpc.
JsonRpc10
(dumps=<function dumps>, loads=<function loads>)[source]¶ Bases:
object
JSON-RPC V1.0 data-structure / serializer
This implementation is quite liberal in what it accepts: It treats missing “params” and “id” in Requests and missing “result”/”error” in Responses as empty/null.
Seealso: JSON-RPC 1.0 specification Todo: catch json.dumps not-serializable-exceptions -
dumps_error
(error, id=None)[source]¶ serialize a JSON-RPC-Response-error
Since JSON-RPC 1.0 does not define an error-object, this uses the JSON-RPC 2.0 error-object.
Parameters: error (RPCFault) – an RPCFault instance Returns: str like {“result”: null, “error”: {“code”: code, “message”: message, “data”: data}, “id”: …}. “result”, “error” and “id” are always in this order, data is omitted if None. Raises: ValueError if error is not a RPCFault instance, TypeError if not JSON-serializable
-
dumps_notification
(method, params=())[source]¶ serialize a JSON-RPC-Notification
Parameters: Returns: str like {“method”: “…”, “params”: …, “id”: null}. “method”, “params” and “id” are always in this order.
Raises: TypeError if method/params is of wrong type or not JSON-serializable
-
dumps_request
(method, params=(), id=0)[source]¶ serialize JSON-RPC-Request
Parameters: Returns: str like`{“method”: “…”, “params”: …, “id”: …}`. “method”, “params” and “id” are always in this order.
Raises: TypeError if method/params is of wrong type or not JSON-serializable
-
dumps_response
(result, id=None)[source]¶ serialize a JSON-RPC-Response (without error)
Returns: str like {“result”: …, “error”: null, “id”: …}. “result”, “error” and “id” are always in this order. Raises: TypeError if not JSON-serializable
-
loads_request
(string)[source]¶ de-serialize a JSON-RPC Request/Notification
Returns: list like [method_name, params, id] or [method_name, params]. params is a tuple/list. if id is missing, this is a Notification Raises: RPCParseError, RPCInvalidRPC, RPCInvalidMethodParams
-
loads_response
(string)[source]¶ de-serialize a JSON-RPC Response/error
Returns: list like [result, id] for Responses Raises: RPCFault+derivates for error-packages/faults, RPCParseError, RPCInvalidRPCNote: error-packages which do not match the V2.0-definition, RPCFault(-1, “Error”, RECEIVED_ERROR_OBJ) is instead raised.
-
-
class
pyircbot.jsonrpc.
JsonRpc20
(dumps=<function dumps>, loads=<function loads>)[source]¶ Bases:
object
JSON-RPC V2.0 data-structure / serializer
See: JSON-RPC 2.0 specification Todo: catch simplejson.dumps not-serializable-exceptions Todo: rewrite serializer as modern java encoder subclass? support for more types this way? -
dumps_error
(error, id=None)[source]¶ serialize a JSON-RPC-Response-error
Parameters: error (RPCFault) – error to serialize Returns: str like {“jsonrpc”: “2.0”, “error”: {“code”: code, “message”: message, “data”: data}, “id”: …}. “jsonrpc”, “result”, “error” and “id” are always in this order, data is omitted if None. Raises: ValueError if error is not a RPCFault instance, TypeError if not JSON-serializable
-
dumps_notification
(method, params=())[source]¶ serialize a JSON-RPC-Notification
Parameters: Returns: String like {“jsonrpc”: “2.0”, “method”: “…”, “params”: …}. “jsonrpc”, “method” and “params” are always in this order.
Raises: see dumps_request
-
dumps_request
(method, params=(), id=0)[source]¶ serialize a JSON-RPC-Request to string
Parameters: : type id: request id (should not be None) :returns: string like: {“jsonrpc”: “2.0”, “method”: “…”, “params”: …, “id”: …}. “jsonrpc”, “method”,
“params” and “id” are always in this order. “params” is omitted if emptyRaises: TypeError if method/params is of wrong type or not JSON-serializable
-
dumps_response
(result, id=None)[source]¶ serialize a JSON-RPC-Response (without error)
Returns: str like {“jsonrpc”: “2.0”, “result”: …, “id”: …}.”jsonrpc”, “result”, and “id” are always in this order. Raises: TypeError if not JSON-serializable
-
-
exception
pyircbot.jsonrpc.
RPCAuthentificationError
(error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCFault
AUTHENTIFICATION_ERROR
-
exception
pyircbot.jsonrpc.
RPCFault
(error_code, error_message, error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCError
RPC error/fault package received.
This exception can also be used as a class, to generate a RPC-error/fault message.
Variables: - error_code: the RPC error-code
- error_string: description of the error
- error_data: optional additional information
- (must be json-serializable)
TODO: improve __str__
-
exception
pyircbot.jsonrpc.
RPCInternalError
(error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCFault
Internal error. (INTERNAL_ERROR)
-
exception
pyircbot.jsonrpc.
RPCInvalidMethodParams
(error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCFault
Invalid method-parameters. (INVALID_METHOD_PARAMS)
-
exception
pyircbot.jsonrpc.
RPCInvalidParamValues
(error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCFault
INVALID_PARAM_VALUES
-
exception
pyircbot.jsonrpc.
RPCInvalidRPC
(error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCFault
Invalid rpc-package. (INVALID_REQUEST)
-
exception
pyircbot.jsonrpc.
RPCMethodNotFound
(error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCFault
Method not found. (METHOD_NOT_FOUND)
-
exception
pyircbot.jsonrpc.
RPCParseError
(error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCFault
Broken rpc-package. (PARSE_ERROR)
-
exception
pyircbot.jsonrpc.
RPCPermissionDenied
(error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCFault
PERMISSION_DENIED
-
exception
pyircbot.jsonrpc.
RPCProcedureException
(error_data=None)[source]¶ Bases:
pyircbot.jsonrpc.RPCFault
Procedure exception. (PROCEDURE_EXCEPTION)
-
exception
pyircbot.jsonrpc.
RPCTimeoutError
[source]¶ Bases:
pyircbot.jsonrpc.RPCTransportError
Transport/reply timeout.
-
exception
pyircbot.jsonrpc.
RPCTransportError
[source]¶ Bases:
pyircbot.jsonrpc.RPCError
Transport error.
-
class
pyircbot.jsonrpc.
Server
(data_serializer, transport, logfile=None)[source]¶ Bases:
object
RPC server.
It works with different data/serializers and with different transports.
Example: see module-docstring
TODO: - mixed JSON-RPC 1.0/2.0 server?
- logging/loglevels?
-
handle
(rpcstr)[source]¶ Handle a RPC Request.
Parameters: rpcstr (str) – the received rpc message Returns: the data to send back or None if nothing should be sent back Raises: RPCFault (and maybe others)
-
log
(message)[source]¶ write a message to the logfile :param message: log message to write :type message: str
-
register_function
(function, name=None)[source]¶ Add a function to the RPC-services.
Parameters: - function – callable to add
- name (str) – RPC-name for the function. If omitted/None, the original name of the function is used.
-
register_instance
(myinst, name=None)[source]¶ Add all functions of a class-instance to the RPC-services.
All entries of the instance which do not begin with ‘_’ are added.
Parameters: - myinst – class-instance containing the functions
- name – hierarchical prefix. If omitted, the functions are added directly. If given, the functions are added as “name.function”.
Todo: - only add functions and omit attributes?
- improve hierarchy?
-
class
pyircbot.jsonrpc.
ServerProxy
(data_serializer, transport)[source]¶ Bases:
object
RPC-client: server proxy
A client-side logical connection to a RPC server.
It works with different data/serializers and different transports.
Notifications and id-handling/multicall are not yet implemented.
Example: see module-docstring Todo: verbose/logging?
-
class
pyircbot.jsonrpc.
Transport
[source]¶ Bases:
object
generic Transport-interface.
This class, and especially its methods and docstrings, define the Transport-Interface.
-
send
(data)[source]¶ send all data. must be implemented by derived classes. :param data: data to send :type data: str
-
serve
(handler, n=None)[source]¶ serve (forever or for n communicaions).
- receive data
- call result = handler(data)
- send back result if not None
The serving can be stopped by SIGINT.
TODO: - how to stop? maybe use a .run-file, and stop server if file removed?
- maybe make n_current accessible? (e.g. for logging)
-
-
class
pyircbot.jsonrpc.
TransportSTDINOUT
[source]¶ Bases:
pyircbot.jsonrpc.Transport
receive from STDIN, send to STDOUT. Useful e.g. for debugging.
-
class
pyircbot.jsonrpc.
TransportSocket
(addr, limit=4096, sock_type=<AddressFamily.AF_INET: 2>, sock_prot=<SocketKind.SOCK_STREAM: 1>, timeout=1.0, logfunc=<function log_dummy>)[source]¶ Bases:
pyircbot.jsonrpc.Transport
Transport via socket.
TODO: - documentation
- improve this (e.g. make sure that connections are closed, socket-files are deleted etc.)
- exception-handling? (socket.error)
-
class
pyircbot.jsonrpc.
TransportTcpIp
(addr=None, limit=4096, timeout=1.0, logfunc=<function log_dummy>)[source]¶ Bases:
pyircbot.jsonrpc.TransportSocket
Transport via TCP/IP.
-
class
pyircbot.jsonrpc.
TransportUnixSocket
(addr=None, limit=4096, timeout=1.0, logfunc=<function log_dummy>)[source]¶ Bases:
pyircbot.jsonrpc.TransportSocket
Transport via Unix Domain Socket.