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 to src/socket.io
. In this folder we see some files. You can quickly see that index.js
is controlling everything, and that all the other files are socket "namespaces" (e.g. all the socket calls that have the user
prefix will be handled by the user.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 another js
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", like SocketModules.composer
. At the very end you can see that this file sets the module.exports
to the SocketModules
object. This means that when you require(..)
this file, you'll have access to everything in the SocketModules
object, but nothing outside of it. This gave me an idea.
#Exploring the Idea
From your plugin you can require(..)
files from NodeBB using module.parent.require(..)
. In this way you can also require the modules.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, the SocketModules
object, which includes everything that was defined in the modules.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 is require
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