Thinking about the protocol, I'm thinking about extendability. The client should be able to present commands it knows during handshake. Each feature of the API should have a version that is supported.
All commands should have three top level entries in it's envelope:
- c — command is a string representation of the command you whish to execute through RPC. Max length of this parameter is 20 byte characters
- t — a server generated token specific for each connected client that is passed out on each response and consumed for each client request. TODO: Specify the data type of the token and length
- d — arbitrary data in a json object that the command for this version should know how to execute.
{
"c": "string command name",
"t": "string token",
"d": {
"arbitrary data that the command of this version should be able to parse"
}
}
For all unknown command and version combinations the server should respond with this message. The token should be expected to be renewed on each subsequent request.
{
"c": "error",
"t": "token",
"d": {
"message": "free text description of error",
"code": "error code"
}
}
The client initates the websocket connection and waits for the server to open the socket fully.
Client sends all possible versions and commands i supports. This command has no token. If the client is successfully authenticated it will receive it's first token in the response.
- v — version is a integer represenation of the version of said command you wish to execute. The server will state which versions it supports.
{
"c": "handshake",
"t": "token",
"d": {
"v": 1,
"supports" : {
"error": { "versions": [1] },
"handshake": { "versions": [1] },
"login": { "versions": [1,2] },
"logout": { "versions": [1,2,3] },
"userlist": { "versions": [1] },
"message": { "versions": [1] },
"plug-github": { "versions": [1,2,3,4,5] }
}
}
}
The server should now respond with the preferred versions(usually latest) and commands it intends to support. Say this server supports version 2 of userlist, it will still honor the client and answer 1. The server response is more compact since it decides an agreement of which versions to use.
Since the server does not recognize the github-plugin it responds with false as a boolean value.
User visibility implies the permissions that this user has on the chat server in the global scope.
{
"c": "handshake",
"t": "token",
"d": {
"supports" : {
"error": 1,
"handshake": 1,
"login": 2,
"logout": 3,
"userlist": 1,
"message": 1,
"plug-github": false
},
"mainchat": chatroomId_for_main_chat
}
}
Now the server knows which versions of which commands that the client supports and will honor those
Version 1
{
"c": "list_channels",
"t": "token",
"d": {}
}
{
"c": "list_channels",
"t": "token",
"d": {
"channels": [
{
"channel_name": "human readable name of channel 0",
"channel_id": idnumber0,
"channel_visibility": "public"/"private"/"staff"
},
{
"channel_name": "human readable name of chanel 1" ,
"channel_id": idnumber1,
"channel_visibility": "public"/"private"/"staff"
}
]
}
}
Version 1
{
"c": "subscribe",
"t": "token",
"d": {
"channel": channelId
}
}
{
"c": "subscribe",
"t": "token",
"d": {
"channel": channelId
"key": "channel passphrase"
}
}
The result field returns OK if connection is okay, or PERM if the user is not authorized to join this channel.
{
"c": "subscribe",
"t": "token",
"d": {
"channel": channelId,
"name": "human readable name of channel",
"result": "OK"/"PERM"
}
}
{
"c": "subscribed",
"t": "token",
"d": {
"channel": channelId,
"user": {
"name": "Username1",
"picture": "url1",
"meetupID": id1
}
}
}
Version 1
- visibility dictates which user groups can see and connect to the channel.
{
"c": "create_channel",
"t": "token",
"d": {
"name": "name of room",
"visibility": "public"/"private"/"staff"
}
}
- visibility dictates which user groups can see and connect to the channel.
- psk is a pre shared key in a arbitrary string format.
{
"c": "create_channel",
"t": "token",
"d": {
"name": "name of room",
"psk": "pre shared key",
"visibility": "public"/"private"/"staff"
}
}
- psk will not be returned due to security reasons.
- result will be either OK or PERM.
- If result is not OK then that is the only data-param that is returned.
{
"c": "create_channel",
"t": "token",
"d": {
"result": "OK"/"PERM",
"channel_id": id_number_of_chat_room,
"name": "name of room",
"visibility": "public"/"private"/"staff"
}
}
Only published to relevant visibility levels(public or staff
{
"c": "create_channel",
"t": "token",
"d": {
"result": "OK"/"PERM",
"channel_id": id_number_of_chat_room,
"name": "name of room",
"visibility": "public"/"private"/"staff"
}
}
Version 1
{
"c": "listUsers",
"t": "token",
"d": {
"room" : roomId
}
}
{
"c": "listUsers",
"t": "token",
"d": {
"users": [{
"name": "Username1",
"picture": "url1",
"meetupID": id1
},{
"name": "Username2",
"picture": "url2",
"meetupID": id2
}],
"room" : roomId
}
}
Version 1
I'm thinking this might be a bit talkative for one of the most passed messages but not sure how to make it work with resending, history and all the other demands.
{
"c": "msg",
"t": "token",
"d": {
"text" : "Message Text Written By User",
"hash": "hash of the message",
"user" : userId,
"room" : roomId
}
}
{
"c": "msg",
"t": "token",
"d": {
"result" "OK"/"PERM",
"hash" : "hash of the message",
"room" : roomId
}
}
{
"c": "msg",
"d": {
"text" : "Message Text Written By User",
"user" : userId,
"room" : roomId
}
}
language in specification
handshake
list channels
request to channel
user_list vs listUsers
sending message
Request was not successfull