.. _joint-protocol: ###################### Protocol specification ###################### RPC specification is simple enough, and made very close to jsonrpc_ MessagePack RPC Spec ==================== .. sidebar:: Types .. glossary:: msgid :type: integer Client can choose random integer as a msgid. Server must reply with that msgid in reply packet. Usually, msgid used as a sequence number, so msgid for first request will be ``0``, for second ``1`` and so on. method :type: string Method name to be called on server side. params :type: array Arguments for remote function error :type: string or null If set describes error occurred on server side. result :type: any Return value of remote function Request ------- Simple request. Ask server to call some function and return results in blocking fashion. Packet scheme ''''''''''''' :: +---+-------+--------+--------+ | 0 | msgid | method | params | +---+-------+--------+--------+ .. _request-example: Example ''''''' Call ``multiply`` function with one param ``2``. .. code-block:: python >>> msgpack.loads('\x94\x00\x0c\xa8multiply\x91\x02') (0, 12, 'multiply', (2,)) Reply ----- Simple reply. Server sends reply after call was completed. Packet scheme ''''''''''''' :: +---+-------+-------+--------+ | 1 | msgid | error | result | +---+-------+-------+--------+ Example ''''''' This is reply for :ref:`request example above ` .. code-block:: python >>> msgpack.loads('\x94\x01\x0c\xc0\x04') (1, 12, None, 4) Notification ------------ Variant of simple request, for which client dont want to wait result. This way client sends notification, may disconnect immidiately, while servers run requested function in asynchronous way. But client will not be able to receive results (server dont even try to send them). Packet scheme ''''''''''''' :: +---+--------+--------+ | 2 | method | params | +---+--------+--------+ Example ''''''' .. code-block:: python >>> msgpack.loads('\x93\x02\xa8shutdown\x90') (2, 'shutdown', ()) .. force sidebar not to float anymore .. raw:: html
joint Spec ========== .. sidebar:: Types All types for MessagePack RPC Spec apply here as well. .. glossary:: offset :type: integer Offset for all packet id's in joint. By default some weird number used like ``42``. req_opt / rep_opt :type: integer Request/reply option bits kwparams :type: dict Dictionary with keyword arguments data :type: any Just any data exception :type: array (class_name, error_text, traceback_string) Extended server error description All MessagePack RPC above is supported (of course...). But in addition to original specification joint_ has its own extensions. Request ------- Extended request: 1. params can be either :ref:`list or dictionary or both ` and they are not required 2. client may ask server to run meth in :ref:`separate subprocess ` 3. client may ask server to run meth with :ref:`async flow ` Packet scheme ''''''''''''' :: +------------+---------+-------+--------+---------+-----------+ | offset + 0 | req_opt | msgid | method | params? | kwparams? | +------------+---------+-------+--------+---------+-----------+ Options (req_opt) ''''''''''''''''' .. _run-async-yield-param: .. describe:: REQUEST_OPT_ASYNC_FLOW :value: 1 .. _run-subprocess-param: .. describe:: REQUEST_OPT_RUN_SUBPROCESS :value: 2 .. _request-throw-packet-spec: Request throw ------------- Packet scheme ''''''''''''' :: +------------+-------+------+ | offset + 0 | msgid | data | +------------+-------+------+ Reply ----- Packet scheme ''''''''''''' :: +------------+---------+-------+--------+ | offset + 1 | rep_opt | msgid | result | +------------+---------+-------+--------+ Options (rep_opt) ''''''''''''''''' .. describe:: REPLY_ERROR :value: 1 .. describe:: REPLY_OPT_HAS_MORE :value: 2 If remote function returned generator, there will be multiple reply packets with final reply with result set to ``null``. Once client received yield packet it can throw something back using :ref:`request-throw-packet-spec` packet. Pings ----- Pings normally should be asynchronous. Main idea is simple: in classic rpc it is too hard to detect if connection "stucks". You call some meth, but you dont really now how much time it will be executed. Normal scenario:: --> call something <-- ok, calling <-- (after some time) here is a result But what if connection hangs after meth was called, but before result was made:: --> call something <-- ok, calling (connection freezes) Right now we dont know how much to wait. Because we cant detect what's happening on server side. With pings this can be done easily:: --> call something <-- ok, calling (after ping interval) --> ping <-- pong (after ping interval, meanwhile connection freezes) --> ping (wait on client side for pong for hardcoded ping timeout and abort) Pings always issued by client side. Pongs -- by server side. Packet scheme (ping) '''''''''''''''''''' :: +------------+ | offset + 3 | +------------+ Packet scheme (pong) '''''''''''''''''''' :: +------------+ | offset + 4 | +------------+ .. _jsonrpc: http://www.jsonrpc.org/ .. :: .. .. X = offset = 42 (default =)) .. .. 5+ request [0, msgid, method, params] .. 5+ reply [1, msgid, error, result] .. 4+ notification [2, method, params] .. .. 4+ joint-request [X + 0, msgid, method, params?, params_dict?] .. 4+ joint-request-throw [X + 0, msgid, data] .. .. 4+ joint-reply [X + 1, msgid, result] .. 4+ joint-reply-yield [X + 2, msgid, result] .. .. #joint-notification [X + 3, method, params?, params_dict?] .. .. joint-error [X + 3, msgid, error] .. .. joint-ack-wanted [X + 4, seq, original packet] .. joint-ack [X + 4, seq] .. .. joint-split [X + 5, id, idx, total, original_packet_part] .. 3+ joint-seq [X + 6, idx, original_packet] .. .. 2 joint-ping [X + 6] .. 2 joint-pong [X + 7] .. .. 3+ joint-set-offset [X + 8, new_offset] .. .. Example scenarios:: .. .. request - [split reply] - [split reply] .. request - reply-part - request-throw - reply