How the shoutbox client sockets work
-
This is about the following file: sockets.js
We need more posts, why not write something about how the shoutbox works? Could be interesting for some people I suppose :P
The fun thing about the recent refactor of the client sockets is that you can call them by simple doing
Shoutbox.sockets.<action>(data, callback);. This is possible because we add each message to the globalShoutbox.socketsobject. Doing this for every single message would take a lot of time and code, especially with the recent addition of commands. So how do we do this?As you can see at the beginning of the file there are 2 objects with a bunch of method names as key and socket events as value, these names will later be used as the
<action>:var Messages = { getShouts: 'plugins.shoutbox.get', sendShout: 'plugins.shoutbox.send', removeShout : 'plugins.shoutbox.remove', editShout: 'plugins.shoutbox.edit', notifyStartTyping: 'plugins.shoutbox.notifyStartTyping', notifyStopTyping: 'plugins.shoutbox.notifyStopTyping', getOriginalShout: 'plugins.shoutbox.getOriginalShout', saveSettings: 'plugins.shoutbox.saveSetting', getSettings: 'plugins.shoutbox.getSettings', getUsers: 'user.loadMore', getUserStatus: 'user.isOnline' }; var Events = { onUserStatusChange: Messages.getUserStatus, onReceive: 'event:shoutbox.receive', onDelete: 'event:shoutbox.delete', onEdit: 'event:shoutbox.edit', onStartTyping: 'event:shoutbox.startTyping', onStopTyping: 'event:shoutbox.stopTyping' };These are the default messages and events we work with. Extra events or messages required for commands etc are defined by the command itself (we get to this later).
After that we have a
Handlersobject, which essentially has all the default socket handlers required for the shoutbox to actually work. You can see some basic stuff ilkeonReceive,onDeleteetc. You can pretty much guess by their name what their function is. Interesting here is thedefaultSocketHandler:var Handlers = { onReceive: ..., onDelete: ..., onEdit: ..., onUserStatusChange: .., onStartTyping: ..., onStopTyping: ..., defaultSocketHandler: function(message) { this.message = message; var self = this; return function (data, callback) { if (typeof data === 'function') { callback = data; data = null; } socket.emit(self.message, data, callback); }; } };In the next bit I explain how the
defaultSocketHandlerworks.At the very end of the file we find what we actually “expose” to the public/global
Shoutboxobject.Shoutbox.sockets = { messages: Messages, events: Events, registerMessage: function(handle, message) { if (!Shoutbox.sockets.hasOwnProperty(handle)) { Shoutbox.sockets[handle] = new Handlers.defaultSocketHandler(message); } }, registerEvent: function(event, handler) { if (socket.listeners(event).length === 0) { socket.on(event, handler); } }, initialize: function() { for (var e in Events) { if (Events.hasOwnProperty(e)) { this.registerEvent(Events[e], Handlers[e]); } } for (var m in Messages) { if (Messages.hasOwnProperty(m)) { this.registerMessage(m, Messages[m]); } } } };The first two keys,
messagesandeventssimply expose the default messages and events that we talked about at the beginning.registerMessageis more interesting. Let’s take a closer look at it.registerMessage: function(handle, message) { if (!Shoutbox.sockets.hasOwnProperty(handle)) { Shoutbox.sockets[handle] = new Handlers.defaultSocketHandler(message); } },registerMessagefirst checks if we don’t already have the requested key in theShoutbox.socketsobject, if we don’t it adds a new key with a newdefaultSocketHandleras value. We pass the message from the second argument to thedefaultSocketHandlerconstructor, which, if you scroll up, is stored in the newly created object withthis.message = message;. If you look at the return value ofdefaultSocketHandleryou can see that it returns a function that takes 2 arguments. This function essentially just emits a socket message with the data and callback as arguments. Because we store this newly created function as the value of theShoutbox.sockets[handle]key, this allows us to do theShoutbox.sockets.<action>(data, callback);from the beginning of this post.registerEventjust registers a new event withsocket.iofor the passed in event and handler.intializesimply loops over all theEventsandMessagesand calls the appropriate functions to register all the default events and messages.Because we expose
registerMessageandregisterEventcommands and actions can easily add their own methods and event handlers to theShoutbox.socketsobject.Hopefully this post was somewhat interesting to read ;)