Protocol Details
All VRPC agents and clients technically are MQTT clients to a single logical broker. They use the MQTT 3.11 standard to realize all RPC functionality.
Instead of being message oriented, VRPC uses a protocol on top of MQTT fixing the topic as well as the payload structure.
General topic pattern:
<domain>/<agent>/<class>/<instance>/<function>
General RPC request payload pattern:
{
"c": "<context>",
"f": "<function>",
"a": ["<arguments>"],
"i": "<correlationId>",
"s": "<sender>",
"v": "<protocolVersion>"
}
General RPC response payload pattern:
{
"a": ["<arguments>"],
"r": "<return value>",
"e": "<error message>",
"i": "<correlationId>",
"v": "<protocolVersion>"
}
Agent Details
Initialization Time
User configures
<domain>
and<agent>
VRPC generates an MQTT client ID like so:
va3<agentInstance>
where
<agentInstance>
reflects a 20 characters long hash generated out of domain and agent name.VRPC publishes the (retained) agent info message:
<domain>/<agent>/__agentInfo__ JSON PAYLOAD { "status": "online" "hostname": <hostname> "version": <userAgentVersion> }
VRPC iterates all registered classes and subscribes to their static functions using the following pattern:
<domain>/<agent>/<class>/__static__/<method>
VRPC then publishes a class info message for each registered class:
<domain>/<agent>/<class>/__classInfo__ JSON PAYLOAD { "className": <className>, "instances": [<instance1>, <instance2>, ...], "staticFunctions": [<function1>, <function2>, ...], "memberFunctions": [<function1>, <function2>, ...], "meta": { <function1>: { description, params, ret } <function2>: { description, params, ret } } }
Runtime
After receiving an RPC message on topic:
<domain>/<agent>/<class>/__static__/__createIsolated__
VRPC creates and names a new instance, iterates all of its member functions and subscribes to each one using:
<domain>/<agent>/<class>/<instance>/<method>
After receiving an RPC message on topic
<domain>/<agent>/<class>/<instance>/<method>
VRPC executes the RPC call and then replies to the sender instance by publishing to the topic that was provided in the
<sender>
property.
Destruction Time
Either by explicitly calling the end()
function or by MQTT last will VRPC publishes the (retained) agent info message:
<domain>/<agent>/__agentInfo__
JSON PAYLOAD {
status: 'offline'
hostname: <hostname>
version: <userAgentVersion>
}
Client Details
Initialization time
User (optionally) configures
<domain>
and<agent>
, those will be the defaults for later remote instancesVRPC generates an MQTT client ID like so:
vc3<random><processInfo>
where
<random>
are 8 random characters and<processInfo>
is a 12 character long string composed of host specific properties (i.e. stays the same on the same host)VRPC then listens for available agents and classes by subscribing to
<domain>/<agent>/__agentInfo__
and
<domain>/<agent>/+/__classInfo__
Finally, VRPC listens to RPC responses by subscribing to
<domain>/<host>/<random>
which can be regarded as VRPC client ID. This information is packed into the
<sender>
property of the RPC payload.
Runtime
VRPC publishes a single message per RPC request to
<domain>/<agent>/<class>/<instance>/<method>
where
<instance>
is replaced with__static__
in case of static method calls, and<class>
is replaced with__global__
in case of global method calls.In case an argument of the remotely called method is of function type (i.e. a callback), the corresponding data argument will be a string that reads:
__f__<methodName>-<index>-<event|invokeId>
Depending on the callback type (continuous or re-registered) either the event name or an invoke id is used as last identifier.
Destruction Time
Either by explicitly calling the end()
function or by MQTT last will VRPC publishes the (non-retained) client info message:
<domain>/<host>/<random>/__clientInfo__
JSON PAYLOAD {
status: 'offline'
}
Adapter Details
With respect to the remote procedure calls the Adapter is a passive component. Besides registering the to-be-remotified functions, the user does not directly interact with this component. It however intercepts the regular RPC traffic in two distinct ways.
Resolving all VRPC internal functions
Those are the function to manage the lifetime of the remotely created objects:
__createShared__
__createIsolated__
__callAll__
__delete__
all of them use double underscores both as prefix and as postfix.
Intercepting promises
The adapter will intercept all remotified functions that return a promise. The original promise return value is changed to a string that reads:
__p__<method>-<invokeId>
At the time of promise resolution the adapter will send another RPC response containing the actual return value and the above mentioned string as <id>
.
Last updated