Local eventEmitter listening to global eventEmitter - node.js

I almost wrote the question title as - Communicating between eventEmitters
I have a node.js module (X) that is on the global scope (it uses eventEmitter). I then have code that is local to each socket (user connected).
right now i am carrying X through the process on a global variable G={'X':X} so that the socket can then access X like this:
G.X.on('someEvent',doSomething);
This is dumb! Now every time i start my server it seems to act fine (I receive the event), but then if I refresh the page and emit an event I get it twice. If I refresh the page again I get the event 3 times.
I think that I am binding the listener to the same eventEmitter that is global.
How can I make a separate local eventListener to listen for the emits of the global eventEmiter?
I know how to set up an eventEmiter:
var events = require('events');
var ee = new events.EventEmitter();
ee.on('someEvent',function(){console.log('hello');});
but it does not catch the event of another...
I have also tried copying the module using the eventEmitter
var ee = G.X;
ee.on('someEvent',function() { console.log('hello'); });
But it still receives multiples of an event.
hello
hello
hello

This question was asked quite some time ago, but here's my answer anyways, seeing as there's no answer for it yet.
Listen to the socket object's "close" event, then remove the callbacks to your global. So it would look like:
X.addListener("someEvent", callback);
X.on("someEvent", function(socket){
socket.on("close", function(){
X.removeListener("someEvent", callback);
});
});

Related

Change Socket for another user

I'm trying to develop an API for multiplayer online using socket programming in node js
I have some basic questions:
1. How to know which connection is related to a user?
2. How to create a socket object related to another person?
3. When it's opponent turn, how to make an event?
4. There is a limited time for move, how to handle the time to create an event and change turn?
As it is obvious I don't know how to handle users and for example list online users
If you can suggest some articles or answering these questions would be greate
Thanks
Keep some sort of data structure in memory where you are saving your sockets to. You may want to wrap the node.js socket in your own object which contains an id property. Then you can save these objects into a data structure saved in memory.
class User {
constructor(socket) {
this.socket = socket;
this.id = //some random id or even counter?
}
}
Then save this object in memory when you get a new socket.
const sockets = {}
server = net.createServer((socket) => {
const user = new User(socket);
sockets[user.id] = user
})
I am unsure what you mean by that, but maybe the above point helps out
This depends on when you define a new turn starts. Does the new turn start by something that is triggered by another user? If so use your solution to point 2 to relay that message to the related user and write something back to that socket.
Use a timeout. Maybe give your User class an additional property timeout whenver you want to start a new timeout do timeout = setTimeout(timeouthandler,howlong) If the timeouthandler is triggered the user is out of time, so write to the socket. Don't forget to cancel your timeouts if you need to.
Also, as a side note, if you are doing this with pure node.js tcp sockets you need to come up with some ad-hoc protocol. Here is why:
socket.on("data", (data) => {
//this could be triggered multiple times for a single socket.write() due to the streaming nature of tcp
})
You could do something like
class User {
constructor(socket) {
this.socket = socket;
this.id = //some random id or even counter?
socket.on("data", (data) => {
//on each message you get, find out the type of message
//which could be anything you define. Is it a login?
// End of turn?
// logout?
})
}
}
EDIT: This is not something that scales well. This is just to give you an idea on what can be done. Imagine for some reason you decide to have one node.js server instance running for hundreds of users. All those users socket instances would be stored in the servers memory

ws.onclose event does not get called on nodejs exit

i use web sockets and the onclose method does not get triggert when the server is down.
i tried to close the ws connections manually with progress.exit but it seems this only gets triggert on a clean exit.
is their a way to catch a stopped nodejs app and execute code before the stop?
it should trigger on ctr+c and any other crash/exit.
basicly i want to tell the client when the connection is not alive anymore before he is trying to do something, since onclose does not handel every case, what can i do to check the connection?
the only solution i came up with is to ping the server from time to time.
since this is not possible i started sending pings as a workarround:
var pingAnswer = true;
pingInterval = setInterval(function(){
if(pingAnswer){
ws.send(JSON.stringify({type:'ping'})); //on the serverside i just send a ping back everytime i recive one.
pingAnswer = false;
}else{
clearInterval(pingInterval);
//reload page or something
}
},1000);
ws.onMessage(function(e){
m = JSON.parse(e.data);
switch(m.type){
....
case 'ping':
pingAnswer=true;
return;
}
}
);
You don't provide a snippet showing how you're defining your on('close',...) handler, but it's possible that you're defining the handler incorrectly.
At the time of this writing, the documentation for websocket.onclose led me to first implement the handler as ws_connection.onclose( () => {...});, but I've found the proper way to be ws_connection.on('close', () => {...} );
Maybe the style used in the ws documentation is some kind of idiom I'm unfamiliar with.
I've tested this with node 6.2.1 and ws 1.1.1. The on.('close',...) callback is triggered on either side (server/client) when the corresponding side is shutdown via Ctrl+c or crashes for whatever reason (for example, for testing, JSON.parse("fail"); or throw new Error('');).

Pushing changes to all clients with Node.js and Socket.io

I have a working server that's using sockets. My server-side code looks like this:
io.sockets.on('connection', function(socket) {
socket.emit('status', { counter: count });
});
In this example, I'm simply incrementing a counter by 1 every minute. When the counter updates, I'd like to send the current count to all clients. My index.html file looks like this:
<script>
var socket = io.connect('http://localhost');
socket.on('status', function (data) {
console.log(data);
});
</script>
When I start up my server, I can see the first data send to the client {'counter': 0}, however when the value of the counter increments, I don't see the new value being updated on the client. Why isn't new data being sent to my clients?
You emit the information only upon connection. For instance, if you just want to broadcast the information every minute - just change your code to:
io.sockets.on('connection', function(socket) {
setInterval(function() {
socket.emit('status', { counter: count });
}, 60 * 1000);
});
This will create an interval upon connection, and then emit the message every minute.
If you want something more advanced, such as listening to the change in count you need to subscribe to changes from it using a more advanced mechanism.
Update
Another way to achieve this is to emit on counter change (using the same function that updates it).
Yet another way is to use the experimental observe feature on a javascript object.
This question was already answered.
See: Update all clients using Socket.io?
The basic info is: you need to emit the message form the global socket io not the individual socket.
The socket.emit() only emits to one socket. Where as io.socket.emit() will emit the message to all sockets (broadcast message).

Implementing listeners in Pusher when all there is to work with is bindings?

I'm trying to create a modular application in javascript using pusher. Different modules need to bind to the same pusher event and sometimes that event is nested in another event. Furthermore, these modules get loaded at different times depending on DOM events triggered by the user.
So, if one module has some code like
env.pusher.connection.bind('connected', function() {
env.my_channel.bind('private_message',function(data){ ... }
}
And another module comes along and wants to listen to the same private_message event. What happens if I write the same code is that the first bind gets overwritten.
What I'm looking for is a way to implement some kind of listeners, possibly with the option of removing a listener from a channel event.
I've thought of a solution myself. It comprises of the following steps:
keep a dictionary of pusher events
every module that wants to make use of a pusher event should search the dictionary first to see if that event exists and if not, write the code that creates the bind for the first time and add it to the dictionary
when a module creates the bind for the first time, it should also trigger a custom event and pass to it the data that pusher sends at the completion of the pusher event
every module that wants to make use of a pusher event should add a handler to the custom event that is triggered when the pusher event is triggered
If that looks hard to follow, here's some code inside a module that is a rewrite of the code in my question(I've used jQuery because jQuery is succint and has custom events already implemented):
if (typeof(env.pusher_events['my_channel']['private_message']) == 'undefined'){
env.pusher_events['my_channel']['private_message'] = true;
// 'pusher-connected' is defined in another module
// this module depends on that event but for brevity
// I'm not defining the 'connected' event here
$(document).on('pusher-connected', 'body', function(){
env.my_channel.bind('private_message', function(data){
$('body').trigger('pusher-my_channel-private_message', data);
})
})
}
$(document).on('pusher-my_channel-private_message', 'body', function(data){
// do something useful with the data
}
Would love to get some feedback on this (drawbacks etc.)

Nodejs event handling

Following is my nodejs code
var emitter = require('events'),
eventEmitter = new emitter.EventEmitter();
eventEmitter.on('data', function (result) { console.log('Im From Data'); });
eventEmitter.on('error', function (result) { console.log('Im Error'); });
require('http').createServer(function (req, res) {
res.end('Response');
var start = new Date().getTime();
eventEmitter.emit('data', true);
eventEmitter.emit('error', false);
while(new Date().getTime() - start < 5000) {
//Let me sleep
}
process.nextTick(function () {
console.log('This is event loop');
});
}).listen(8090);
Nodejs is single threaded and it runs in an eventloop and the same thread serves the events.
So, in the above code on a request to my localhost:8090 node thread should be kept busy serving the request [there is a sleep for 5s].
At the same time there are two events being emitted by eventEmitter. So, both these events must be queued in the eventloop for processing once the request is served.
But that is not happening, I can see the events being served synchronously as they are emitted.
Is that expected? I understand that if it works as I expect then there would be no use of extending events module. But how are the events emitted by eventEmitter handled?
Only things that require asynchronous processing are pushed into the event loop. The standard event emitter in node will dispatch an event immediately. Only code using things like process.nextTick, setTimeout, setInterval, or code explicitly adding to it in C++ affect the event loop, like node's libraries.
For example, when you use node's fs library for something like createReadStream, it returns a stream, but opens the file in the background. When it is open, node adds to the event loop and when the function in the loop gets called, it will trigger the 'open' event on the stream object. Then, node will load blocks from the file in the background, and add to the event loop to trigger data events on the stream.
If you wanted those events to be emitted after 5 seconds, you'd want to use setTimeout or put the emit calls after your busy loop.
I'd also like to be clear, you should never have a busy loop like that in Node code. I can't tell if you were just doing it to test the event loop, or if it is part of some real code. If you need more info, please you expand on the functionality you are looking to achieve.

Resources