Trimsock is a stream-based communication protocol that:
- is easy to implement
- is human-readable
- supports binary
- can support most use cases via conventions
It is intended for situations where most common protocols ( e.g. HTTP, WebSockets ) are overkill, yet a structured way for exchanging data is still needed. This can mean, among others, cases where pulling in a full-fledged HTTP / WebSocket / other implementation would increase binary sizes too much, or cases where most of the protocol's features would be unused.
Warning
The specification is still work in progress
Implementing the core specification is enough for conformance. Additional features may be built on top of it as conventions.
Trimsock exchanges commands, with each command consisting of the command name, a single space, the command data and a single newline character, delimiting the command:
[command name] [command data]\n
An example command:
login [email protected]:ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f
A command may omit the command data:
[command name] \n
Note that even without command data, the space character is required.
Commands must be parsed as UTF-8 strings.
TODO
- newline ->
\n
- space ->
\s
To support transmitting binary data, command data may be prefixed with the
string \b
( backspace ), and a number declaring the size of the binary data.
The receiving party must consider the next n bytes after the prefix sequence as binary. Once the binary data has been received, the command is terminated with the newline character.
[command name] \b[data size in bytes][binary data]\n
Implementations may impose their own limits on the size of binary data, for security reasons.
Example:
set-picture \b1524...\n
In case a command needs multiple parameters instead of a single command data blob, implementations may split the command data into multiple command parameters.
This is done by splitting the command data at every space character:
[command name] [command parameter] [command parameter] [...]\n
For example:
set-user-details Tom Acme [email protected]
A common use case is requesting some data, and then receiving it in a response message.
To support this, command names may be extended with a request id that uniquely identifies the request-response exchange:
[command name]:[request-id] [command data]\n
Note that to an implementation that does not handle request-response pairs, this is still a valid command.
The request id must be a string unique to the connection. Implementations are free to choose their own approach, for example sequential IDs, UUIDs, or nanoids.
A request-response exchange happens by both peers using the same request id across multiple commands, for example:
>>> login:i6QhjOtphK2m [email protected]:ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f\n
<<< login:i6QhjOtphK2m OK\n
TODO: Does the response have to use the same command, or is it enough to have the same request id?
Large amounts of data can be impractical to transmit in one large command. Instead, implementations may use request ID's as outlined in Request-response pairs and use them for streaming.
In this case, each request ID is used to identify a stream. Multiple commands are sent with this request ID, each transmitting a chunk of command data. Once all the data has been streamed, a command is sent omitting command data:
[command name]:[request-id] [command data]\n
[command name]:[request-id] [command data]\n
[command name]:[request-id] \n
An example stream exchange, combined with request-response pairs:
>>> get-file:AUygn0OwMgYu big-video.mp4
<<< get-file:AUygn0OwMgYu \b1024...\n
<<< get-file:AUygn0OwMgYu \b1024...\n
<<< get-file:AUygn0OwMgYu \b1024...\n
<<< get-file:AUygn0OwMgYu \n