Release event handlers on disconnection of Socket.IO client - javascript

I'm using Socket.IO like in this sample:
io.sockets.on("connection", function (socket) {
myService.on("myevent", function() {
socket.emit("myevent", { /* ... */ });
// some stuff happens here of course
});
});
myService is a singleton and a subclass of EventEmitter which triggers the myevent over the time. Anything works fine, however I guess that I create some kind of leak in this case. How does my service know that it doesn't need to call the handler once the connection is destroyed? Is there some kind of destroy event I can catch and then remove the handler from myService?

Listen to the socket disconnect event and when you get a disconnect event, remove the relevant event handler from the myService object.
You should be able to do that like this:
io.sockets.on("connection", function (socket) {
function handler() {
socket.emit("myevent", { /* ... */ });
// some stuff happens here of course
}
myService.on("myevent", handler);
socket.on("disconnect", function() {
myService.removeListener("myevent", handler);
});
});
If what you're trying to do is to broadcast to all connected sockets, you could just install one "myevent" listener (not one per connection) and use io.emit() to broadcast to all sockets too and not have to handle the connect or disconnect events for this purpose.

If you are planning to send data to all sockets when some other event fires, you don't need to add/remove another listeners every time a client connects/disconnects.
It is a lot more efficient and easier to simply fire the socket.io event to all sockets that are connected right now using io.sockets (which is a reference to the default namespace with all clients on it by default) and io.sockets.emit:
myService.on('myevent', () => {
io.sockets.emit('myevent', {/*...*/});
});
If you only need to fire this event to some subset of your users, try using specific namespaces or rooms:
myService.on('myevent', () => {
//with namespaces
io.of('namespace').emit('myevent', {/*...*/});
//with rooms
io.to('room').emit('myevent', {/*...*/});
});

Related

socket.on inside socket.on server side api socket.io in nodejs

Why do we require to put socket.on inside socket.on here? What does this represent? Is there any other way of writing this?
This is the code of server.js in nodejs.
var objExpress = require('express')()
var objHttp = require('http').createServer(objExpress)
var objSocketIO = require('socket.io')(objHttp)
objExpress.get('/', (request, result) => result.send('hello'))
objSocketIO.on('connection', (argSocket) => {
console.log('A user connected!');
argSocket.on('message', (argMsg) => {
console.log(argMsg);
argSocket.broadcast.emit('message-broadcast-xyz', argMsg)
})
})
objHttp.listen(3000, () => {
console.log("Listening on port 3000")
})
Inside of this:
objSocketIO.on('connection', argSocket => {
// here's where you know the socket for a newly connected socket
});
is the only place where you get notified of a newly connected socket. If you want to listen for events on that newly connected socket, then this is the place to install those event listeners.
objSocketIO.on('connection', argSocket => {
// here's where you know the socket for a newly connected socket
// and where you can install event listeners on that newly connected socket
argSocket.on('message', (argMsg) => {
// here's where you get a message on that connected socket
// from the previously installed event handler
argSocket.broadcast.emit('message-broadcast-xyz', argMsg)
});
});
Why do we require to put socket.on inside socket.on here?
Well, that's how event driven programming works. You listen for an event by installing an eventListener. In this case, when you get an event from your server that a new socket has connected, then you install event listeners on that new socket so you can get events from it.
Is there any other way of writing this?
Other ways could be dreamed up, but they'd have to be doing something like this under the covers because listening for events is the way you program with servers and sockets in node.js.

How to add additional handlers to an existing connection?

Within my MVC 5 application, I am setting up a Signal R connection on the client end upon page load, this works as expected.
At some point later on I want add an additional handler and make a server side call, I can see that the server recieves this call which then initiates some client side calls, the handlers at the client don't get invoked.
Connection setup upon page load
function initialiseRealTimeDataRetrieval() {
var hub = $.connection.autoGeneratedProxyForHub;
hub.client.recieveRealTimeData = function (data) {
//Do Stuff
};
$.connection.hub.start().done(function () {
hub.server.getRealTimeData();
});
}
Additional calls made later on
function initialiseFeed () {
var hub = $.connection.autoGeneratedProxyForHub;
hub.client.recieveRealTimeDataFeed = function (data) {
//Do stuff
};
if ($.connection.hub.state == $.connection.connectionState.connected) {
hub.server.getRealTimeDataFeed();
}
else {
$.connection.hub.start().done(function () {
hub.server.getRealTimeDataFeed();
});
}
}
So far I have tried the following:
Made sure that calls made from the client to server are being invoked on the server.
Made sure that the additional calls are work as expected if they were made along with the calls and handlers executing upon page load.
Reviewd documentation to see if a connection must be restarted to register the new handlers.
Attempted various methods of restarting the connection after new handlers were added
The below works as expected for the additional calls however makes everything done for the connection upon page load redundant:
function initialiseFeed () {
var hub = $.connection.autoGeneratedProxyForHub;
hub.client.recieveRealTimeDataFeed = function (data) {
//Do stuff
};
$.connection.hub.stop();
$.connection.hub.start().done(function () {
hub.server.getRealTimeDataFeed();
});
}
Inspecting the hub object through the debugger does show that all clients are connected, including the additional ones.
According to the Signal R JS API Docs, the automaically generated proxy for the hub can't be used to register multiple event handler:
When to use the generated proxy
If you want to register multiple event handlers for a client method
that the server calls, you can't use the generated proxy. Otherwise,
you can choose to use the generated proxy or not based on your coding
preference. If you choose not to use it, you don't have to reference
the "signalr/hubs" URL in a script element in your client code.
Also to register new handlers for an existing connection, that connection must have at least one handler associated with it prior to establishing a connection, upon registering new handlers you must call start():
Note
Normally you register event handlers before calling the start method
to establish the connection. If you want to register some event
handlers after establishing the connection, you can do that, but you
must register at least one of your event handler(s) before calling the
start method. One reason for this is that there can be many Hubs in an
application, but you wouldn't want to trigger the OnConnected event on
every Hub if you are only going to use to one of them. When the
connection is established, the presence of a client method on a Hub's
proxy is what tells SignalR to trigger the OnConnected event. If you
don't register any event handlers before calling the start method, you
will be able to invoke methods on the Hub, but the Hub's OnConnected
method won't be called and no client methods will be invoked from the
server.

Best practice for handling Socket.io events?

I am switching from ajax polling to socket.io live data pushing but have a question about best practice of managing events.
Let's say I have a basic server like this:
var Clients = [];
// Event fired every time a new client connects:
io.on('connection', function(socket) {
Clients.push(socket);
// What else should go in here?
// Individual functions for each event?
socket.on('chat message', function(msg){
console.log(':> '+msg);
io.emit('chat message', msg);
});
// When socket disconnects, remove it from the list:
socket.on('disconnect', function() {
var index = Clients.indexOf(socket);
if (index != -1) { Clients.splice(index, 1); }
});
});
In the example there is a chat message event, but ideally there are many other events I'd like to push to clients in real-time, such as:
User sends message, user starts/stops typing, user likes a post, user invites you to become friends/group member, and so on.
There are many events that I'd like to capture in real-time but it seems like there has to be a better way than cramming the io.on() statement full of them all.
I've looked into Node OOP but not sure if it would necessarily help in this application.
So where we have the socket.on() statements, what would the best practice be for including event catching like I described?
There are many events that I'd like to capture in real-time but it
seems like there has to be a better way than cramming the io.on()
statement full of them all.
Nope. Inside the io.on('connection', ...) is where you have a closure with the socket variable that pertains to a new connection. So, any event handler you want to respond to from that socket goes in there or in some function you call from there and pass the socket to. That's just how it works.
FYI, in the interest of modularity, you don't have to put all the event handlers inside of one io.on('connection', ...). If you export the io object to other modules or pass it to them in a module constructor, you can have other modules create their own io.on('connection', ...) listeners and install their own event handlers inside their own io.on('connection', ...). io is an EventEmitter so it can support as many listeners for the connection event as you want and all will be notified.

Nodejs JavaScript Events

Given the code above:
binaryServer = BinaryServer({port: 9001});
binaryServer.on('connection', function(client) {
console.log("new connection");
client.on('stream', function(stream, meta) {
console.log('new stream');
stream.on('data', function('data'){
//actions
stream.on('end', function() {
//actions
});
});
});
I can say that client inherits the features of binaryServer. So if I make console.log(client.id) in the events of stream I can see, which client generate the given event. Now I want to know if every single event is exclusive of one client, in other words I want to know if data happens for every single client (that generates data) and no data event will be generated while the actions is happening.
You're registering a listener to the "connection" event which can happen within binaryServer. When a "connection" event happens, the registered listener will receive an argument, which you choose to call client. client in this case is an object, and doesn't inherit features of binaryServer.
"data" happens for every client, but will have unique results for each clientsince you register an event listener for every client.
If two events are triggered after each other, the callback function of the first event will be called, and after that the second events callback function will be called. See the following example code:
var event = new Event('build');
var i = 0;
// Listen for the event.
document.addEventListener('build', function (e) {
console.log(i++);
}, false);
// Dispatch the event.
document.dispatchEvent(event);
document.dispatchEvent(event);
JSFiddle (watch console)
Information about JavaScript inheritance
Information about JavaScript event loop

socket.io code structure: where to place methods?

When using the socket.io library, I am a little confused about how to place the different methods.
In a very simple chat application I have server.js:
io.sockets.on('connection', function(socket) {
//some methods to handle when clients join.
socket.on('text', function(msg) {
socket.broadcast.emit('text', msg);
});
});
and client.js:
var socket = io.connect();
socket.on('connect', function() {
//some methods to fire when client joins.
socket.on('text', function(msg) {
console.log(msg)
});
});
Right now, the methods that handle when a client joins AND the methods that handle the sending and receiving of messages afterwards, are placed within the connect / connection event methods, both on the server and the client side, but this structure seems to work as well on the client side:
var socket = io.connect();
socket.on('connect', function() {
//some methods to fire when client joins.
});
socket.on('text', function(msg) {
console.log(msg)
});
+potentially many more methods...
My question is, what is the fundamental difference between placing a method inside the connect method and outside, and what is considered the best option?
When you call this,
socket.on('xyz', function listener() {});
you listen for event xyz and add function listener as event handler. It is executed whenever xyz occurs. So when you do :
socket.on('connect', function() {
socket.on('text', function(msg) {
console.log(msg)
});
});
Event handler/listener for text is added only when connect event happens (connect event handler is executed). There is only one listener before connect happens and two (one more) when connect happens. But when you do :
socket.on('connect', function() {
//some methods to fire when client joins.
});
socket.on('text', function(msg) {
console.log(msg)
});
There are two listeners at any time, before/after connect happens.
The previous method is more efficient and logical. Logical because text cannot happen before connect happens, so why listen to it. Efficient as in the event-loop does not have unnecessary events to look for. Adding too many events may not hurt very much, but for performance-critical applications it can be a drag. The latter one just looks good, all event handlers placed one by one.

Categories