How To: Using websockets in your plugin
-
I wrote this on our forum, thought it'd be nice to share it with you guys as well.
Source: link#The Problem
Say you want your plugin to communicate between client and server using websockets. There isn't a documented (or "official") way on how to hook into the websockets API of NodeBB.
I was facing this issue with the Shoutbox plugin, and had to find a clever way to get it to work. The way I found is a bit "hackish" but actually works really well and is now actually being used by a core developer in one of his plugins.#The Process of finding a Solution
When digging around a bit in the NodeBB source you can see how their socket implementation works. For this we navigate tosrc/socket.io
. In this folder we see some files. You can quickly see thatindex.js
is controlling everything, and that all the other files are socket "namespaces" (e.g. all the socket calls that have theuser
prefix will be handled by theuser.js
file. I won't go into too many details on how this works, you'll just have to believe me on this
When playing around with this, you find out that when you add anotherjs
file in that folder, you'll have working sockets on that namespace! But we don't want to change anything in core... We want to do this from a plugin!We will further investigate one of these files. I chose the modules file because I thought it would fit a Shoutbox the most.
It's some pretty basic stuff in here.SocketModules
is defined as a new object, and so is every "module", likeSocketModules.composer
. At the very end you can see that this file sets themodule.exports
to theSocketModules
object. This means that when yourequire(..)
this file, you'll have access to everything in theSocketModules
object, but nothing outside of it. This gave me an idea.#Exploring the Idea
From your plugin you canrequire(..)
files from NodeBB usingmodule.parent.require(..)
. In this way you can also require themodules.js
file like so:var ModulesSockets = module.parent.require('./socket.io/modules');
ModulesSockets
will now be whatever this file has given us as their export. In our case, theSocketModules
object, which includes everything that was defined in themodules.js
file, which are basically all the socket handlers for the composer, chat, etc...
Here I enter my idea: What happens if I add my own custom sockets to this object? I simply tested this with something like this (from within my plugin):var ModulesSockets = module.parent.require('./socket.io/modules'); ModulesSockets.test = function(socket, data, callback) { console.log("Working?"); console.log(data); callback(null, "It worked!"); }
Then, on the client, I entered something like this in the console:
socket.emit('modules.test', {data: "Some data"}, function(err, result) { alert(result); });
And hit enter.
And it worked! I saw the logs in the NodeBB log and was alerted with "It worked!".
Using all this information I came up with the following solution.#The Solution
So the solution is quite easy. All you have to do isrequire
the namespace you want to extend, and add your custom handlers. You could even replace the default handlers with your own in this way!
In a bit of code:var ModulesSockets = module.parent.require('./socket.io/modules'); ... //I prefer to execute this in the "action:app.load" handler method ModulesSockets.shoutbox = Shoutbox.sockets; //in this case, my handlers will listen to "modules.shoutbox.*" ... Shoutbox.sockets = { //Bunch of socket handlers here }
I hope you guys learned something from this If you have any corrections or enhancements please call me out on it
-
Hey @Mr_Waffle would you like this guide to be a guest post on our blog? Maybe omit the initial bits and get straight to the solution etc.
Thanks for the guide
-
@psychobunny said:
Hey @Mr_Waffle would you like this guide to be a guest post on our blog? Maybe omit the initial bits and get straight to the solution etc.
Thanks for the guide
Sure, go ahead
-
-
Thanks @Mr_Waffle !
I started implementing this method in my static page plugin. I actually saw it in your shoutbox code on github (and stole it ) before you wrote this how to.
-
I was just about to ask about this, thanks for the guide! Just to be thorough, maybe include how to send a message in the other direction, server to client? If plugin authors are starting to append to existing modules in the core, maybe we should establish some namespacing conventions?
-
Server can do
socket.emit
and client can listen tosocket.on
without too much extra work. Keep me up to date with what you're doing and I can lend you a hand if you run into any problems -
Yeah, I know, I was able to figure that part out I was just saying for the sake of anyone starting out. It's not as straightforward as socket.io demonstrates...
@Mr_Waffle 's Shoutbox plugin was a good example of using something likevar socketIndex = module.parent.require('./socket.io/index'); socketIndex.server.sockets.emit('event:imgbed.server.rcv.end', { id: id, url: url, alt: alt} );
to send a message to the client, whereas simply using
socket.emit('event:imgbed.server.rvc.end', { id: "this is the id" });
will crash the server. -
@BDHarrington7 said:
Yeah, I know, I was able to figure that part out I was just saying for the sake of anyone starting out. It's not as straightforward as socket.io demonstrates...
@Mr_Waffle 's Shoutbox plugin was a good example of using something likevar socketIndex = module.parent.require('./socket.io/index'); socketIndex.server.sockets.emit('event:imgbed.server.rcv.end', { id: id, url: url, alt: alt} );
to send a message to the client, whereas simply using
socket.emit('event:imgbed.server.rvc.end', { id: "this is the id" });
will crash the server.Ye this is a little bit tricky, but you can figure this out by looking at some of the core code, especially the chat and new topic/reply sockets. Because you can already figure this out by looking at core code, I didn't think it'd be that important to write a guide on that as well Creating your own sockets isn't something that you can figure out from looking at core code!
-
@Schamper lol dat
NaN
tho