aboutsummaryrefslogtreecommitdiff
path: root/protocol.md
blob: 549ac01e1dfac8497707394312a3f052d2af47d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# tomsg protocol (version 3)

The underlying transport of the protocol is a plain TCP socket. However,
because private information is communicated, the recommended transport is an
encrypted and authenticated wrapper around a TCP socket; examples are an SSH
connection, or something built on a TLS connection.

The individual messages are all line-based; this means that a single message,
both client->server and server->client, always ends with a newline (ASCII 10)
character.

Preliminary definitions:
- A _string_ is a series of non-zero bytes that are not newlines (ASCII 10). To
  allow for clients written in programming languages that automatically parse
  strings as UTF-8, argument strings should always be valid UTF-8. However, the
  server currently does not care.
- A _word_ is a string without spaces (ASCII 32) (and also without newlines).
  Note that the empty string is also a valid word.

There are three kinds of messages: commands from the client, command responses
from the server, and push messages from the server (not to be confused with push
_notifications_). These three kinds are described below.

Note that the first message the client must send is the `version` command, with
which server and client can agree (or not) on a protocol version; if a `version`
message has not yet been replied to with an `ok` response, no other commands are
valid. See the definition of the `version` command for more information.

In the syntax descriptions below, `<name>` indicates an argument called "name";
the angle brackets are not part of the syntax. The type of the argument may be
indicated with the notation `<name:type>`; possible types are `i64` (a 64-bit
signed integer in decimal notation), `word` (a word), and `string...` (a string
stretching until the end of the line).

A message from client to server consists of a _tag_, a space, the command name,
a space, and finally the arguments to the command. The tag is a word, and may be
arbitrarily chosen by the client; it will be returned by the server in its
response to the client's message, so that the client can easily link requests
and responses.

All client commands, if not syntactically invalid, will be replied to with a
server response.

A _response_ from the server will be in one of the following forms:
- `<tag> ok`
  - The message from the client was successfully processed.
- `<tag> number <num:i64>`
  - A numeric value was returned.
- `<tag> error <message:string...>`
  - The client's message was successfully parsed, but handling resulted in an
    error described in the message.
- `<tag> name <name:word>`
  - A name was returned, probably the name of the room in `create_room`.
- `<tag> list <count:i64> words...`
  - A list of words was returned. The number of words returned is given in
    `<count>`; the words themselves are space-separated further arguments to
    `list`.
- `<tag> pong`
  - Response to the client's `ping` command.
- `<tag> history <count:i64>`
  - Response to the client's `history` command; is followed by exactly `<count>`
    messages of type `history_message` with the same tag. The messages are
    returned in chronological order (oldest first).
- `<tag> history_message <index:i64> <roomname:word> <user:word> <timestamp:i64> <msgid:i64> <replymsgid:i64> <message:string...>`
  - Part of the response to the client's `history` command. Index 0 is the
    oldest message; index (`<count>` - 1) (from the `history` response) is the
    newest message in the fragment requested. Timestamps are microseconds since
    the UNIX epoch. The reply message id is -1 if the message is a normal
    message, or nonnegative if it is a reply to the referenced message in the
    same room.
- `<tag> message <roomname:word> <user:word> <timestamp:i64> <msgid:i64> <replymsgid:i64> <message:string...>`
  - Response to the client's `get_message` command. This contains the
    information for a single message, as in `_push message` and the
    `history_message` response.

A command is identified by its name, which can be found in the list below. Its
arguments are zero or more words, except if for the command in question the last
argument is of type `string...` (in which case it may contain spaces and
ranges until the end of the line).

Note: all messages on the server have an ID that is globally unique on a single
tomsg server.

- `<tag> version <version:word>`
  - Indicates that the client wishes to speak the protocol with the specified
    version. For the version of the protocol described in this document, see the
    header at the top of the file.

    After the server has replied to this command with `ok`, the rest of the
    protocol of (only) the specified version may be used. Before that, or if the
    server replies with `error`, no commands other than `version` are valid.

    If the client sends subsequent `version` messages after the first one, the
    server may choose to handle those subsequent messages and switch versions,
    or always return `error`, or some arbitrary mix. However, sending multiple
    `version` messages is always valid (though not recommended).

    It is probable that the server can only speak one version of the protocol,
    but it may support multiple versions. Note also that the version is a
    _word_, not an integer; though this document describes an integer-versioned
    protocol, future versions may use other printable ASCII characters (but not
    any outside that range).
  - Returns `ok` or `error`.
- `<tag> register <user:word> <pass:string...>`
  - Register a new user on the server. The password may contain spaces.
  - Returns `ok` or `error`.
- `<tag> login <user:word> <pass:string...>`
  - Logs in as the specified user.
  - Returns `ok` or `error`.
- `<tag> change_password <pass:string...>`
  - Changes the password of the current user to the given string.
  - Returns `ok` or `error`.
- `<tag> logout`
  - Logs out of the user the client is currently logged in as. If the client is
    not logged in, does nothing.
  - Returns `ok`.
- `<tag> list_rooms`
  - Lists all rooms the user is a member of.
  - Returns `list` or `error`.
- `<tag> list_members <roomname:word>`
  - Lists all members of the given room, if the user is also a member. (This
    includes the user themselves.)
  - Returns `list` or `error`.
- `<tag> create_room`
  - Creates a new room, and enters the room. The id of the room is returned to
    the client. Returns an error if the client is not logged in.

    If successful, all other sessions of the current user get a `_push invite`
    push message for the new room with the current user (itself) as the
    inviter.

    Also marks the current session as active.
  - Returns `name` or `error`.
- `<tag> leave_room <roomname:word>`
  - Leaves the room. Returns an error if the client is not logged in, or not in
    that room.

    If successful, a `_push leave` push message is sent to all remaining room
    members, as well as all other sessions of the current user. The message
    contains the room left and the name of the current user.

    Also marks the current session as active.
  - Returns `name` or `error`.
- `<tag> invite <roomname:word> <user:word>`
  - Invites the given user to the given room, if the client is currently a
    member of that room. The invited user is immediately added to the room.

    If the invite succeeds, the invited user receives a `_push invite` push
    message on all its sessions, and all current room members receive a
    `_push join` push message on all their sessions (except the session the
    `invite` message was sent from).

    Also marks the current session as active.
  - Returns `ok` or `error`.
- `<tag> send <roomname:word> <replymsgid:i64> <message:string...>`
  - Sends a message to the given room. All room members receive a
    `_push message` push message on all their sessions (except the session the
    `send` message was sent from).

    If `<replymsgid>` is -1, this sends a normal message. Otherwise,
    `<replymsgid>` must be the id of a message in the given room, in which case
    the sent message is a reply to the indicated earlier message. If
    `<replymsgid>` is not a message in this room, `error` is returned.

    Also marks the current session as active.

    The returned `number` response contains the message id of the message sent.
    This number will be non-negative.
  - Returns `number` or `error`.
- `<tag> history <roomname:word> <number:i64>`
  - Requests the last `<number>` messages in the given room, if the client is a
    member of the room. In the `history` response, `<count>` will be at most
    `<number>`, and may be less if the room does not yet have `<number>`
    messages. Each message will be returned in a `history_message` response
    after the `history` response, in chronological order.
  - Returns `history`, followed by zero or more `history_message`.
- `<tag> history_before <roomname:word> <number:i64> <msgid:i64>`
  - Same as `history`, except the returned messages are the last `<number>`
    strictly before the timestamp of the message with id `<msgid>`.
  - Returns `history`, followed by zero or more `history_message`.
- `<tag> get_message <msgid:i64>`
  - Retrieves the message with the given id.
  - Returns `message` or `error`.
- `<tag> ping`
  - Asks for a `pong` response.
  - Returns `pong`.
- `<tag> is_online <user:word>`
  - Returns with how many sessions the given user is currently online.
  - Returns `number` or `error`.
- `<tag> firebase_token <token:word>`
  - Adds the given Firebase token to the account of the current user. This is
    used for new-message push notifications for Android-based clients.
  - Returns `ok` or `error`.
- `<tag> delete_firebase_token <token:word>`
  - Removes the given Firebase token from the account of the current user.
  - Returns `ok` or `error`.
- `<tag> user_active <active:i64>`
  - Marks the user as active (if `active` > 0) or inactive (if `active`
    <= 0) on the current session. This does not influence whether the user is
    marked active on any of the other sessions on which they are currently
    logged in.

    A session is automatically marked inactive 2 minutes after the latest
    activity on that session.

    This is used for Firebase notifications: a user will only receive Firebase
    notifications if they are marked inactive on all their sessions, or if they
    have no active sessions.
  - Returns `ok` or `error`.

Push messages from the server are formatted like responses with tag `_push`.
These are not sent in response to a particular client message, but are sent by
the server due to other events. Some have already been mentioned above, but all
are listed below.

- `_push online <numonline:i64> <user:word>`
  - When user X logs in or logs out in a session, all sessions of all members
    (excluding user X) of all rooms user X is a member of receive a `_push
    online` push message stating that `<user>` (user X) is now online with
    `<numonline>` sessions.
- `_push message <roomname:word> <user:word> <timestamp:i64> <msgid:i64> <replymsgid:i64> <message:string...>`
  - Sent to all sessions of all members of a room in which a message is
    posted, except the session that sent the message. `<replymsgid>` is -1 if
    the message is a normal message, and references the replied-to message
    otherwise.
- `_push invite <roomname:word> <user:word>`
  - Sent to all sessions of the invited user after an `invite` command. The
    `<user>` parameter indicates who invited you to the given room.
- `_push join <roomname:word> <user:word>`
  - Sent to all sessions of all members of a room (except the session sending
    the `invite` command and all sessions of the invited user) in which a new
    user entered.
- `_push leave <roomname:word> <user:word>`
  - When user X leaves room R, this push message is sent to: 1. all sessions of
    all remaining users in room R, and 2. all sessions of user X that were not
    the one to send the initiating `leave_room` command.
- `_push ping`
  - Sent by the server once in a while. Please ignore.