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 global Shoutbox.sockets
object. 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 Handlers
object, which essentially has all the default socket handlers required for the shoutbox to actually work. You can see some basic stuff ilke onReceive
, onDelete
etc. You can pretty much guess by their name what their function is. Interesting here is the defaultSocketHandler
:
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 defaultSocketHandler
works.
At the very end of the file we find what we actually “expose” to the public/global Shoutbox
object.
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, messages
and events
simply expose the default messages and events that we talked about at the beginning. registerMessage
is 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);
}
},
registerMessage
first checks if we don’t already have the requested key in the Shoutbox.sockets
object, if we don’t it adds a new key with a new defaultSocketHandler
as value. We pass the message from the second argument to the defaultSocketHandler
constructor, which, if you scroll up, is stored in the newly created object with this.message = message;
. If you look at the return value of defaultSocketHandler
you 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 the Shoutbox.sockets[handle]
key, this allows us to do the Shoutbox.sockets.<action>(data, callback);
from the beginning of this post.
registerEvent
just registers a new event with socket.io
for the passed in event and handler.
intialize
simply loops over all the Events
and Messages
and calls the appropriate functions to register all the default events and messages.
Because we expose registerMessage
and registerEvent
commands and actions can easily add their own methods and event handlers to the Shoutbox.sockets
object.
Hopefully this post was somewhat interesting to read ;)