quickrpc.codecs and .terse_codec modules

quickrpc.codecs module

Codecs convert message structures into bytes and vice versa.

Classes defined here:
  • Codec: base class
  • Message, DecodeError
class quickrpc.codecs.Codec[source]

Bases: object

Responsible for serializing and deserializing method calls.

Subclass and override encode, decode, optionally encode_reply, encode_error.

Protocol overview

Byte-data payload is generated from python data by using:

Python data is retrieved from bytes by decode. This returns a list of objects, which can be instances of Message, Reply and ErrorReply.

Security

Let payload denote the “inner” message data and frame the message going on the wire, both being byte sequences. encode*() can be given a sec_out() callback, taking the payload data and returning (secinfo, new_payload).

secinfo is a dict containing e.g. user info, signature, etc. (specific of Security provider).

new_payload is an optional transformed payload (bytes), e.g. encrypted data. If omitted, use original payload. encode*() then builds a frame using new payload and secinfo data, e.g. add crypt headers.

Depending on protocol, encode could be downwards-compatible if “guest” security applies i.e. secinfo is empty and payload stays untransformed.

Decoding: decode again takes a sec_in() callback, accepting security info and payload data, returning the “unpacked” payload. E.g. secinfo could check the signature and raise an error if the message was forged. The secinfo dictionary is returned within the Message, Reply or ErrorReply object.

decode(data, sec_in=None)[source]

decode data to method call with kwargs.

Return: [messages], remainder where [messages] is the list of decoded messages and remainder is leftover data (which may contain the beginning of another message).

If a message cannot be decoded properly, an exception is added in the message list. Decode should never raise an error, because in this case the remaining data cannot be retrieved.

messages can be instances of:
  • Message
  • Reply (to the previous message with the same id)
  • ErrorReply (to the previous message with the same id)
Message attributes
.method attribute (string), .kwargs attribute (dict), .id, .secinfo (dict)
Reply attributes
.result, .id, .secinfo (dict)
ErrorReply attributes
.exception, .id, .errorcode, .secinfo (dict)
encode(method, kwargs=None, id=0, sec_out=None)[source]

encode a method call with given kwargs.

sec_out callback parameters:

  • payload (bytes): Payload data for the frame.

sec_out returns (secinfo, new_payload):

  • sec_info (dict): security information, dictionary str->str, keys defined by Security provider.
  • new_payload (bytes): transformed payload; None indicates that original payload can be used.

Returns: frame data (bytes)

encode_error(in_reply_to, exception, errorcode=0, sec_out=None)[source]

encode error caused by the given Message.

encode_reply(in_reply_to, result, sec_out=None)[source]

encode reply to the Message

classmethod fromstring(expression)[source]

Creates a codec from a given string expression.

The expression must be “<shorthand>:<specific parameters>”, with shorthand being the wanted Codec’s .shorthand property. For the specific parameters, see the respective Codec’s .fromstring method.

shorthand = ''
exception quickrpc.codecs.DecodeError[source]

Bases: Exception

exception ‘quickrpc.codecs.DecodeError’ undocumented

exception quickrpc.codecs.EncodeError[source]

Bases: Exception

exception ‘quickrpc.codecs.EncodeError’ undocumented

class quickrpc.codecs.Message(method, kwargs, id=0, secinfo=None)[source]

Bases: object

class ‘quickrpc.codecs.Message’ undocumented

class quickrpc.codecs.Reply(result, id, secinfo=None)[source]

Bases: object

class ‘quickrpc.codecs.Reply’ undocumented

class quickrpc.codecs.ErrorReply(exception, id, errorcode=0, secinfo=None)[source]

Bases: object

class ‘quickrpc.codecs.ErrorReply’ undocumented

exception quickrpc.codecs.RemoteError(message, details)[source]

Bases: Exception

exception ‘quickrpc.codecs.RemoteError’ undocumented

class quickrpc.codecs.JsonRpcCodec(delimiter=b'x00')[source]

Bases: quickrpc.codecs.Codec

Json codec: convert to json

bytes values are converted into a an object containing the single key __bytes with value being base64-encoded data.

If security is used, the following “Authenticated-JSON-RPC” protocol applies:

Encoding

Prepend a special, valid json-rpc message before the payload:

{"jsonrpc": "2.0", "method": "rpc.secinfo", "params": <secinfo>}<DELIM><payload><DELIM>

If secinfo is empty, NOTHING is prepended (i.e. behaves like unextended JSON-RPC)

Note

Payload must not contain the delimiter even if it is encrypted. Raw data could be b64-encoded. If payload is encrypted, basic-JSON-RPC compatibility is of course lost.

Decoding with security

Decode delimited messages one-by-one as usual (“one” being the bytes between delimiters).

If a rpc.secinfo call is detected, take the unaltered payload from the next message, giving secinfo and payload. If next message is incomplete (no trailing delim), throw the rpc.secinfo message back into the remainder.

For regular call (method != rpc.secinfo), return the message itself as payload wtih empty secinfo.

Discussion:

  • allows framing without touching payload :-)
  • allows decoding the header without decoding payload :-)
  • allows using byte-payload as is, particularly allows encrypted+literal payload to coexist (however encrypted payload breaks JSON-RPC compat!) :-)
  • Msg to “unaware” peer: will throw the rpc.secinfo calls away silently or loudly, but is able to operate. Missing ID indicates a notification, i.e. peer will not send response back per JSON-RPC spec. :-)
  • Msg from “unaware” peer: will implicitly be treated as no-security message.
decode(data, sec_in=None)[source]

decode data to method call with kwargs.

Return: [messages], remainder where [messages] is the list of decoded messages and remainder is leftover data (which may contain the beginning of another message).

If a message cannot be decoded properly, an exception is added in the message list. Decode should never raise an error, because in this case the remaining data cannot be retrieved.

messages can be instances of:
  • Message
  • Reply (to the previous message with the same id)
  • ErrorReply (to the previous message with the same id)
Message attributes
.method attribute (string), .kwargs attribute (dict), .id, .secinfo (dict)
Reply attributes
.result, .id, .secinfo (dict)
ErrorReply attributes
.exception, .id, .errorcode, .secinfo (dict)
encode(method, kwargs, id=0, sec_out=None)[source]

encode a method call with given kwargs.

sec_out callback parameters:

  • payload (bytes): Payload data for the frame.

sec_out returns (secinfo, new_payload):

  • sec_info (dict): security information, dictionary str->str, keys defined by Security provider.
  • new_payload (bytes): transformed payload; None indicates that original payload can be used.

Returns: frame data (bytes)

encode_error(in_reply_to, exception, errorcode=0, sec_out=None)[source]

encode error caused by the given Message.

encode_reply(in_reply_to, result, sec_out=None)[source]

encode reply to the Message

classmethod fromstring(expression)[source]

jrpc:delimiter

delimiter is the character splitting the telegrams and must not occur within any telegram. Default = <null>.

shorthand = 'jrpc'

quickrpc.terse_codec module

module ‘quickrpc.terse_codec’ undocumented

quickrpc.terse_codec.L()

function ‘quickrpc.terse_codec.L’ undocumented

class quickrpc.terse_codec.TerseCodec[source]

Bases: quickrpc.codecs.Codec

Terse codec: encodes with minimum puncutation.

encodes to: method[id] param1:1, param2:”foo”<NL> values:

  • int/float: 1.0
  • bytes: ‘(base64-string’
  • str: “python-escaped str”
  • list: [val1 val2 val3 …]
  • dict: {key1:val1 key2:val2 …}

Reply is encoded to: [id]:value Error is encoded to: [id]! message:”string” details:”string”

  • Commands must be terminated by newline.
  • Newlines, double quote and backslash in strings are escaped as usual
  • Allowed dtypes: int, float, str, bytes (content base64-encoded), list, dict
decode(data, sec_in=None)[source]

decode data to method call with kwargs.

Return: [messages], remainder where [messages] is the list of decoded messages and remainder is leftover data (which may contain the beginning of another message).

If a message cannot be decoded properly, an exception is added in the message list. Decode should never raise an error, because in this case the remaining data cannot be retrieved.

messages can be instances of:
  • Message
  • Reply (to the previous message with the same id)
  • ErrorReply (to the previous message with the same id)
Message attributes
.method attribute (string), .kwargs attribute (dict), .id, .secinfo (dict)
Reply attributes
.result, .id, .secinfo (dict)
ErrorReply attributes
.exception, .id, .errorcode, .secinfo (dict)
encode(method, kwargs, id=0, sec_out=None)[source]

encodes the call, including trailing newline

encode_error(in_reply_to, exception, errorcode=0, sec_out=None)[source]

encode error caused by the given Message.

encode_reply(in_reply_to, result, sec_out=None)[source]

encode reply to the Message

classmethod fromstring(expression)[source]

terse:

shorthand = 'terse'