Skip to content

Dynamic Call Protocol

Steve Ives edited this page May 18, 2020 · 15 revisions

Harmony Core Logo

Dynamic Call Protocol

The dynamic call protocol is the mechanism employed by Harmony Core to allow interaction between the .NET Core code in the Harmony Core service and traditional Synergy code, either on the same a different server, and is at the very heart of what Harmony Core calls it's Traditional Bridge mechanism.

The actual network protocol that is used is a standard protocol called JSON-RPC 2.0, with added Content-Length and optional Content-Type headers (the addition of these headers is compatible with the additions documented here in the base protocol section.

Initial Handshake

In order to signal that the server process is ready and has opened the standard in/out channel, the server process writes READY followed by CRLF on all platforms.

System Messages

System methods are prefixed with rpc. and are called like other methods.

Shutdown

rpc.shutdown will cause the server to gracefully shut down. Channels will be closed and destructors will be fired. rpc.ping will will cause the server to respond with a normal method response having its return value set to 0 rpc.serializer_protocol will respond with the protocol version, currently 1.0 rpc.set_log_level takes a single numeric parameter and sets the current server log level to the value of its parameter rpc.chain this causes the process to recycle itself, stop chaining back into itself

User Messages

A message sent with a member property Name set to a routine name will either be handled by the dynamic dispatch or by code generated dispatchers. The path it takes is determined by the value of Name and the list of dispatchers that have been registered.

Dynamic Dispatch

Dynamic dispatch, meaning routine dispatch that has not been pre generated requires that passed in metadata is sufficient to populate an arguments list and make an RCB API call with it. This precludes dispatching of structures and Synergy real/pseudo arrays. If you need to pass Synergy structures to a routine for dynamic dispatch, the routine needs to be declared as taking a data object. For collections, an ArrayList should be used.

Argument Encoding

Scalar Primatives, meaning a, d, i, id, are passed as a Json object with the following format. PassedValue is a quoted string for a, d, id and a number for i, d, id. If a numeric value is encoded as a quoted string it should not contain a decimal point. DataType is based on the Synergy defined data type values. Alpha is 1, Decimal is 2, Implied Decimal is 4 Integer is 8. We've added additional data types to the DataType enum in TraditionalBridge\FieldDataDefinition.dbl

{
    "PassedValue":"123456789123456789",
    "DataType":4,
    "ElementSize":10,
    "DecimalPrecision":10
}

Primitive Collections are encoded similarly, but instead of being a scalar value, PassedValue should be an array. It is permissable to put the quoted string or number directly in this array. This is the advised pattern, however you can also put a JSON Object with an unencoded Value Property or a Base64 Encoded Base64Value.

{
    "PassedValue":["12345", "12345", "12345"],
    "DataType":2,
    "ElementSize":5
}

Scalar Complex types, meaning Synergy structures and data objects are passed similarly to primitives with one significant change, the value passed for PassedValue fits the following format. Value is the contents of a non-binary Synergy record/structure area. Base64Value is a base64 encoded Synergy record/structure. GRFA is a base64 encoded grfa or rfa depending on the size of it.

{
    "DataType":"StructureName",
    "Value": "SynergyRecordData",
    "Base64Value":"EncodedRecordData"
    "GRFA":"Base64EncodedGRFA"
}

Collections of Complex types are encoded as follows

{
    "PassedValue":[
        {
            "DataType":"StructureName",
            "Value": "SynergyRecordData",
            "Base64Value":"EncodedRecordData"
            "GRFA":"Base64EncodedGRFA"
        },
        {
            "DataType":"StructureName",
            "Value": "SynergyRecordData",
            "Base64Value":"EncodedRecordData"
            "GRFA":"Base64EncodedGRFA"
        }
    ],
    "DataType":16,
    "ElementSize":10
}

Return Parameter Encoding

Below is an example of the return JSON object for a method that returns a structure and the second argument is a collection of structures.

{
    "result": [{
        "Position": 0,
        "Value": {
            "DataType": 16
            "PassedValue" : {
                "Type": "StructureName",
                "Value": "SynergyRecordData",
                "Base64Value": "EncodedRecordData"
                "GRFA": "Base64EncodedGRFA"
            }
        }
    }, {
        "Position": 2,
        "Value": {
            "DataType": 32
            "PassedValue": [{
                "Type": "StructureName",
                "Value": "SynergyRecordData",
                "Base64Value": "EncodedRecordData"
                "GRFA": "Base64EncodedGRFA"
            }, {
                "Type": "StructureName",
                "Value": "SynergyRecordData",
                "Base64Value": "EncodedRecordData"
                "GRFA": "Base64EncodedGRFA"
            }]
        }
    }]

}

Return parameter encoding for primitives is the same as it is on the way in. So if we had an alpha out parameter at position 1, the parameter JSON object would look like this.

{
   "Position":1,
   "Value":{
        "PassedValue":"this is alpha data",
        "DataType":1,
        "ElementSize":18
    } 
}

Errors

When an unhandled error is encountered it will be trapped by the dispatcher library. If an error is trapped by the dispatcher, the client will receive a JSON object and error member where there is a code, message and data member to represent the error being returned.

Clone this wiki locally