Skip to content

Instantly share code, notes, and snippets.

@StefanWallin
Created December 4, 2013 18:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StefanWallin/7793282 to your computer and use it in GitHub Desktop.
Save StefanWallin/7793282 to your computer and use it in GitHub Desktop.
LoungeChatProtocol - version 1, draft 9

Protocol Introduction

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.

Envelope

{
	"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"
	}
}

Handshake

Request socket connection

The client initates the websocket connection and waits for the server to open the socket fully.

Request

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] } 
		}
	}
}

Response

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

Channel management

List Channel

Version 1

Request

{
    "c": "list_channels",
    "t": "token",
    "d": {}
}

Response

{
    "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"
            }
        ]
    }
}

Subscribe to a channel

Version 1

Request to a public channel

{
    "c": "subscribe",
    "t": "token",
    "d": {
        "channel": channelId
    }
}

Request to a private channel

{
    "c": "subscribe",
    "t": "token",
    "d": {
        "channel": channelId
        "key": "channel passphrase"
    }
}

Response

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"
    }
}

Publish

{
    "c": "subscribed",
    "t": "token",
    "d": {
        "channel": channelId,
        "user": {
			"name": "Username1",
			"picture": "url1",
			"meetupID": id1
		}
    }
}

Create channels

Version 1

Request to create a open room

  • 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"
    }
}

Request to create a locked room

  • 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"
    }
}

Response

  • 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"
    }
}

Publish

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"
    }
}

List users in channel

Version 1

Request

{
	"c": "listUsers",
	"t": "token",
	"d": {
		"room" : roomId
	}
}

Response

{
	"c": "listUsers",
	"t": "token",
	"d": {
		"users": [{
			"name": "Username1",
			"picture": "url1",
			"meetupID": id1
		},{
			"name": "Username2",
			"picture": "url2",
			"meetupID": id2
		}],
		"room" : roomId
	}
}

Messages

Send normal message

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.

Request

{
	"c": "msg",
	"t": "token",
	"d": {
		"text" : "Message Text Written By User",
		"hash": "hash of the message",
		"user" : userId,
		"room" : roomId
	}
}

Response

{
	"c": "msg",
	"t": "token",
	"d": {
		"result" "OK"/"PERM",
		"hash" : "hash of the message",
		"room" : roomId
	}
}

Publish

{
	"c": "msg",
	"d": {
		"text" : "Message Text Written By User",
		"user" : userId,
		"room" : roomId
	}
}
@flowertwig-org
Copy link

language in specification

  • use may, must and shall not to indicate what is mandatory and what is not.

handshake

- there is no token?
- supports as an array of objects or array of strings.
    - Maybe like this: {'name': 'error', 'versions': [1]}
    - Or like this: [ 'login', 'userlist', 'userlist2' ]

list channels

- request, is "d" needed in this case?
- response, channel_visibility
    - What is it?
    - is it groups of users?
    - can there be more then public, private and staff?

request to channel

- How do i send request to a staff channel?
- how do i send the secret channel key to the people i want to invite? Can it be done so that I can invite user A and user B and they will see the channel directly?

user_list vs listUsers

- Why have different commands for basicly the same use. Retrieving users in channel X, can we not think of the main chat as a public channel that everyone will auto subscribe to?
- listUsers uses "room", why not use "channel_id"?

sending message

- Maybe use "channel_id" here as well?
- Is response needed or is it enough with the publish command?

Request was not successfull

- Why do we not use error command for telling that command/request was not successfull instead of "PERM"?   

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment