# GAR Protocol
Messages are serialized using an underlying transport — currently ZeroMQ.
Binary or JSON message format is supported by the server.
## Format Detection
- JSON is inferred if the first character of the introduction message is `{`.
- Otherwise, binary is assumed.
## Binary Messages
Start with a `message_type` enum, followed by the appropriate C struct. These are aligned C structures generated by `trscc`. See `gar_proto.h`.
## JSON Messages
JSON messages use the format:
```json
{
"message_type": "<message_type enum name>",
"value": { ... }
}
```
Example:
```json
{
"message_type": "Subscribe",
"value": {
"subscription_mode": "Snapshot",
"nagle_interval": 0,
"name": "S1",
"key_id": 0,
"topic_id": 0,
"_class": "Underlier",
"key_filter": null,
"topic_filter": null
}
}
```
## Session Structure
- The first message must be an Introduction.
- Heartbeats must be sent regularly within `heartbeat_timeout_interval`.
- First heartbeat gets a 10x grace interval.
## Enumeration
- Topics and Keys must be introduced before publishing records.
- Clients and servers may use different enumerations.
- `0` is an invalid ID.
- Clients must map IDs between client and server contexts.
Example:
Client assigns key "AAPL" → ID 2
Server assigns same → ID 3
Client sends `DeleteKey` with ID 2
Receives `DeleteKey` from server with ID 3
## Records
- `NewRecord` must precede updates.
- Records may exist without values.
- Use `DeleteRecord` to remove empty ones.
## Record Updates
### Binary:
- Use `FixedLengthRecordUpdate` or `VariableLengthRecordUpdate`
- Fixed: starts with `record_id` followed by data
- Variable: serializes `binary_record_update`, includes size in first member
### JSON:
```json
{
"message_type": "JSONRecordUpdate",
"value": {
"record_id": { "key_id": 1, "topic_id": 22 },
"value": 0.3
}
}
```
## Example Session
```json
Sent: {"message_type": "Introduction", "value": { "version": 650269, "heartbeat_timeout_interval": 3000, "user": "jonh" }}
Received: {"message_type": "Introduction", "value": { "version": 650269, "heartbeat_timeout_interval": 3000, "user": "jserver" }}
Sent: {"message_type": "Subscribe", "value": { "subscription_mode": "Streaming", "nagle_interval": 0, "name": "S1", "key_id": 0, "topic_id": 0, "_class": "Underlier", "key_filter": null, "topic_filter": null }}
Received: Topic and Key Introductions
Received: NewRecord, JSONRecordUpdate
Received: SnapshotComplete
Sent/Received: Heartbeats
Received: DeleteRecord, DeleteKey
Sent: Logoff
```
## Publication Rules
- Server publishes only subscribed messages.
- Clients may publish any messages but must introduce topics/keys first.
---
## Protocol Schema
```cpp
enum message_type : int64_t {
Introduction = 'A',
Heartbeat = 'B',
Logoff = 'C',
TopicIntroduction = 'D',
KeyIntroduction = 'E',
DeleteKey = 'F',
Subscribe = 'G',
SnapshotComplete = 'H',
Unsubscribe = 'I',
NewRecord = 'J',
DeleteRecord = 'K',
FixedLengthRecordUpdate = 'L',
VariableLengthRecordUpdate = 'M',
JSONRecordUpdate = 'N',
Shutdown = 'O'
};
type u_milliseconds = uint64_t;
struct introduction {
version : int;
heartbeat_timeout_interval : u_milliseconds;
user : string;
schema : optional string;
};
type topic_id = unsigned;
struct topic_introduction {
topic_id;
name : string;
};
type key_id = unsigned;
struct key_introduction {
key_id;
name : string;
_class : optional string;
};
struct delete_key {
key_id;
};
enum subscription_mode { *None, Snapshot, Streaming, Throttled };
type regex text;
struct subscribe {
subscription_mode;
nagle_interval : u_milliseconds;
name : string;
key_id;
topic_id;
_class : optional string;
key_filter : optional regex;
topic_filter : optional regex;
};
struct snapshot_complete {
name : string;
};
struct record_id {
key_id;
topic_id;
};
type byte = unsigned char;
struct json_record_update {
record_id;
value : json;
};
struct binary_record_update {
record_id;
data : byte[];
};
struct unsubscribe {
name : string;
};
```
Raw data
{
"_id": null,
"home_page": "https://www.trinityriversystems.com/docs/gar_protocol/",
"name": "pygar-client",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": null,
"author": "Jon Hill",
"author_email": null,
"download_url": null,
"platform": null,
"description": "# GAR Protocol\n\nMessages are serialized using an underlying transport \u2014 currently ZeroMQ.\n\nBinary or JSON message format is supported by the server.\n\n## Format Detection\n\n- JSON is inferred if the first character of the introduction message is `{`.\n- Otherwise, binary is assumed.\n\n## Binary Messages\n\nStart with a `message_type` enum, followed by the appropriate C struct. These are aligned C structures generated by `trscc`. See `gar_proto.h`.\n\n## JSON Messages\n\nJSON messages use the format:\n```json\n{\n \"message_type\": \"<message_type enum name>\",\n \"value\": { ... }\n}\n```\n\nExample:\n```json\n{\n \"message_type\": \"Subscribe\",\n \"value\": {\n \"subscription_mode\": \"Snapshot\",\n \"nagle_interval\": 0,\n \"name\": \"S1\",\n \"key_id\": 0,\n \"topic_id\": 0,\n \"_class\": \"Underlier\",\n \"key_filter\": null,\n \"topic_filter\": null\n }\n}\n```\n\n## Session Structure\n\n- The first message must be an Introduction.\n- Heartbeats must be sent regularly within `heartbeat_timeout_interval`.\n- First heartbeat gets a 10x grace interval.\n\n## Enumeration\n\n- Topics and Keys must be introduced before publishing records.\n- Clients and servers may use different enumerations.\n- `0` is an invalid ID.\n- Clients must map IDs between client and server contexts.\n\nExample: \nClient assigns key \"AAPL\" \u2192 ID 2 \nServer assigns same \u2192 ID 3 \nClient sends `DeleteKey` with ID 2 \nReceives `DeleteKey` from server with ID 3\n\n## Records\n\n- `NewRecord` must precede updates.\n- Records may exist without values.\n- Use `DeleteRecord` to remove empty ones.\n\n## Record Updates\n\n### Binary:\n\n- Use `FixedLengthRecordUpdate` or `VariableLengthRecordUpdate`\n- Fixed: starts with `record_id` followed by data\n- Variable: serializes `binary_record_update`, includes size in first member\n\n### JSON:\n\n```json\n{\n \"message_type\": \"JSONRecordUpdate\",\n \"value\": {\n \"record_id\": { \"key_id\": 1, \"topic_id\": 22 },\n \"value\": 0.3\n }\n}\n```\n\n## Example Session\n\n```json\nSent: {\"message_type\": \"Introduction\", \"value\": { \"version\": 650269, \"heartbeat_timeout_interval\": 3000, \"user\": \"jonh\" }}\nReceived: {\"message_type\": \"Introduction\", \"value\": { \"version\": 650269, \"heartbeat_timeout_interval\": 3000, \"user\": \"jserver\" }}\nSent: {\"message_type\": \"Subscribe\", \"value\": { \"subscription_mode\": \"Streaming\", \"nagle_interval\": 0, \"name\": \"S1\", \"key_id\": 0, \"topic_id\": 0, \"_class\": \"Underlier\", \"key_filter\": null, \"topic_filter\": null }}\nReceived: Topic and Key Introductions\nReceived: NewRecord, JSONRecordUpdate\nReceived: SnapshotComplete\nSent/Received: Heartbeats\nReceived: DeleteRecord, DeleteKey\nSent: Logoff\n```\n\n## Publication Rules\n\n- Server publishes only subscribed messages.\n- Clients may publish any messages but must introduce topics/keys first.\n\n---\n\n## Protocol Schema\n\n```cpp\nenum message_type : int64_t {\n Introduction = 'A',\n Heartbeat = 'B',\n Logoff = 'C',\n TopicIntroduction = 'D',\n KeyIntroduction = 'E',\n DeleteKey = 'F',\n Subscribe = 'G',\n SnapshotComplete = 'H',\n Unsubscribe = 'I',\n NewRecord = 'J',\n DeleteRecord = 'K',\n FixedLengthRecordUpdate = 'L',\n VariableLengthRecordUpdate = 'M',\n JSONRecordUpdate = 'N',\n Shutdown = 'O'\n};\n\ntype u_milliseconds = uint64_t;\n\nstruct introduction {\n version : int;\n heartbeat_timeout_interval : u_milliseconds;\n user : string;\n schema : optional string;\n};\n\ntype topic_id = unsigned;\n\nstruct topic_introduction {\n topic_id;\n name : string;\n};\n\ntype key_id = unsigned;\n\nstruct key_introduction {\n key_id;\n name : string;\n _class : optional string;\n};\n\nstruct delete_key {\n key_id;\n};\n\nenum subscription_mode { *None, Snapshot, Streaming, Throttled };\n\ntype regex text;\n\nstruct subscribe {\n subscription_mode;\n nagle_interval : u_milliseconds;\n name : string;\n key_id;\n topic_id;\n _class : optional string;\n key_filter : optional regex;\n topic_filter : optional regex;\n};\n\nstruct snapshot_complete {\n name : string;\n};\n\nstruct record_id {\n key_id;\n topic_id;\n};\n\ntype byte = unsigned char;\n\nstruct json_record_update {\n record_id;\n value : json;\n};\n\nstruct binary_record_update {\n record_id;\n data : byte[];\n};\n\nstruct unsubscribe {\n name : string;\n};\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "A Python client for the GAR protocol",
"version": "1.7.8",
"project_urls": {
"Homepage": "https://www.trinityriversystems.com/docs/gar_protocol/"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "892beb8ed7810f1e5c1bf09ca3485a17e9aaae3f655f3383118037c41cb81630",
"md5": "4062cb2fe2365d7374c14fd2617f5fd9",
"sha256": "011a0f6b92f6cea8cad5c7cc6fe1e1fa5edbe5b037b13e2f9c2db85a96c7fc94"
},
"downloads": -1,
"filename": "pygar_client-1.7.8-py3-none-any.whl",
"has_sig": false,
"md5_digest": "4062cb2fe2365d7374c14fd2617f5fd9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 12355,
"upload_time": "2025-07-09T13:56:45",
"upload_time_iso_8601": "2025-07-09T13:56:45.308627Z",
"url": "https://files.pythonhosted.org/packages/89/2b/eb8ed7810f1e5c1bf09ca3485a17e9aaae3f655f3383118037c41cb81630/pygar_client-1.7.8-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-09 13:56:45",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "pygar-client"
}