Welcome to my (embarassingly) new Github projects page. For now there's only the one project.

Chatterbox is a toy project intended to test the feasibility of WebSockets across mobile platforms (Android and iPhone) and modern browsers, with a server built in Ruby. I expect the project to look decent before March of 2012. If all goes well, my new wisdom will get folded into a commercial project. As the code gets integrated into a larger ecosystem, I expect namespacing revisions to propagate into this codebase to facilitate such integration for others and myself in the future. Any architectural changes, however, will probably remain in a private fork.

Update: I've been dissapointed by the fragility of Ruby's Goliath webserver. I'm sure that I would eat those words with properly aligned versions of the MongoDB drivers, but with a single process the server's stability is especially important, so I've put the Ruby implementation on hold until the codebase goes inert for a while. As an alternative, I've begun implementing for the Warp server built on top of Haskell. I'm still bending my mind around functional programming, but I've been impressed thus far with the language's community. I only hope the server itself proves as impressive.

I'm moving project documentation here until competing projects require better organization. Most would put protocol documents under the server, I realize. Maybe once client development begins such an organization may emerge.

Chatterbox

Chatterbox is a N-person messaging application distributed across iOS, Android, and desktop browsers. The project explores WebSockets protocol feasiblity, with an eye toward generalization. The protocol has been chosen for its low power consumption on mobile platforms and for its ability to generalize to much broader uses within an application framework.

I feel that the Rails framework provides just enough structure on top of the Ruby programming language for implementing web services. The EM-WebSocket gem has been chosen for Chatterbox's server. Under Haskell, the Warp server's stack looks designed from top to bottom for asynchronicity, hopefully yielding a stable, performant server.

Apache 2.0 licensed client libraries exist for both Android and iPhone. On the iPhone platform, the unitt project's UnittWebSocketClient has been chosen because it adopts iOS design idioms and there exist no other viable alternatives. On the Android platform, Autobahn WebSockets for Android has been chosen because it adopts Android design idioms and it appears more active and professionally maintained than any of its alternatives.

Conversant Permissions

Every conversant has a default permission that governs how conversations begin with all other conversants. Additionally, any conversant can override the default permission for any specific conversant. So for any potential conversation partner, there exists a permission from the following: Accept by Default, Accept by Individual, Ask by Default, and Ask by Individual. The `by Default' variant always exists as a catch-all.

Conversant permissions do not appear anywhere in the Chatterbox protocol, however. Assuming that some facility outside the protocol exists for changing the permissions, a conversation's permission data could fall out of sync with the database. That external facility will be provided by a ReSTful interface. At the invitation stage of a conversation, the server will reconcile user permissions to auto-initialize as many clients as possible. If a client chooses to alter any permissions after this stage, though, the client is responsible for initializing any relevant conversations.

Connection States

The Initiater proposes a conversation amongst a set of Target Conversants and himself, creating a conversation with connections to each potential conversant, including himself. Each connection has two possible states:

Closed
The associated Target Conversant has neither accepted nor rejected the proposed conversation.
Open
The associated Target Conversant has accepted the proposed conversation. The Initiater's never exists in a Closed state.
Terminated connections require no third state, as the server immediately purges any conversation rejecters.

Actions

Invite Conversants

An Initiater sends an invitation to a set of Target Conversants, creating a conversation. The server creates an Open connection between the Initiater and the new conversation. The server is free to choose a set of conversant connections that share mutually applicable Accept by Default or Accept by Individual permissions to construct in the Open state as well. The remaining invited conversants have their connections constructed in the Closed state.

Initialize Connection

The Initiater instigates this action by inviting the would-be Initializer to a conversation. The server constructs a subset of connections in the Open state, including the Initiater's. The conversants with connections in the Closed state must send an initialization message to join the conversation, transitioning the corresponding connection state to Open.

Handle Conversation Initializations

If a Target Conversant has confirmed conversation with the Instigator or if such confirmation is pending, then any connections to the same conversation with Open state and Ask by Default or Ask by Individual permission require additional confirmation. Connections governed by Accept by Default or Accept by Individual are confirmed entirely on the serverside.

Eject Conversant

Any conversant can attempt to eject any other conversant (including the Initiater or himself). If the Ejectee is also the Ejector, then this action is interpreted as a resignation from the conversation. Otherwise, in conversations with N conversants and N > 2, N-1 conversants can agree to eject the Nth conversant, while any ejection request where N = 2 destroys the conversation.

PURGE USER FROM CONFIRMATION QUEUES on the serverside.

Conversant Sends a Message

Messages are sent to the conversation itself, not individuals. If a conversant wants a subset of conversants to see a message, then he needs to explicitly build a conversation with only those conversants.

Conversation Negotiation

Server to User Messages

conversation
messages

User to Server Messages

invite
speak
initialize
eject
close
command "invite"
targetConversants 2 3 4
message "Let us talk."
notice "conversation"
conversationId 18
self
userId 1
connectionState "open"
ejectionState
votes 0
requiredVotes 1
others
userId 2
connectionState "open"
ejectionState
votes 0
requiredVotes 1
...
...
...
...
...
command "speak"
conversationId 18
message "Hello?"
notice "messages"
conversationId 18
messages
userId 1
timeStamp 128474849
message "Hello?"
command "initialize"
notice "conversation"
conversationId 18
self
userId 1
connectionState "open"
ejectionState
votes 0
requiredVotes 2
others
...
userId 3
connectionState "open"
ejectionState
votes 0
requiredVotes 2
...
...
...
...
command "speak"
conversationId 18
message "sudo make me a sandwich."
command "speak"
conversationId 18
message "sudo Sudoer isn't welcome here."
notice "messages"
conversationId 18
messages
userId 3
timeStamp 12847593
message "sudo make me a sandwich."
userId 2
timeStamp 12847998
message "sudo Sudoer isn't welcome here."
command "eject"
conversationId 18
ejecteeId 3
notice "conversation"
conversationId 18
self
userId 1
connectionState "open"
ejectionState
votes 0
requiredVotes 2
others
...
userId 3
connectionState "open"
ejectionState
votes 1
requiredVotes 2
...
...
...
command "initialize"
notice "conversation"
conversationId 18
self
userId 1
connectionState "open"
ejectionState
votes 0
requiredVotes 3
others
...
...
userId 4
connectionState "open"
ejectionState
votes 0
requiredVotes 3
...
...
...
command "eject"
conversationId 18
ejecteeId 3
notice "conversation"
conversationId 18
self
userId 1
connectionState "open"
ejectionState
votes 0
requiredVotes 3
others
...
userId 3
connectionState "open"
ejectionState
votes 2
requiredVotes 3
...
...
...
...
command "speak"
conversationId 18
message "I'm still here. Mwah hahaha."
notice "messages"
conversationId 18
messages
userId 3
timeStamp 12847693
message "I'm still here. Mwah hahaha."
command "eject"
conversationId 18
ejecteeId 1
notice "conversation"
conversationId 18
self
userId 1
connectionState "open"
ejectionState
votes 1
requiredVotes 3
others
...
...
...
...
...
...
command "eject"
conversationId 18
ejecteeId 3
notice "conversation"
conversationId 18
self
userId 1
connectionState "open"
ejectionState
votes 0
requiredVotes 2
others
...
...
...
...
command "close"
conversationId 18
notice "conversation"
conversationId 18
self
userId 2
connectionState "open"
ejectionState
votes 0
requiredVotes 1
others
userId 4
connectionState "open"
ejectionState
votes 0
requiredVotes 1
...
command "speak"
conversationId 18
message "Looks like its just the two of us, then?"
notice "messages"
conversationId 18
messages
userId 2
timeStamp 12863425
message "Looks like its just the two of us, then?"
command "speak"
conversationId 18
message "Speak for yourself, Spidey."
notice "messages"
conversationId 18
messages
userId 4
timeStamp 12857235
message "Speak for yourself, Spidey."
...
command "close"
conversationId 18
notice "conversation"
conversationId 18
self
userId 2
connectionState "open"
ejectionState
votes 0
requiredVotes 0