Reputation: 2209
So I got an app in node.js to read CSGO demos, it parse the file, and I wanted to emit an event with socket.io to a client every time an entity is updated. It works, but it only fires "client.emit('tick', 'a');" but the console.log fires corretly, anyone can help me find out why socket.io is preventing the emit???
Server Code
var server = require('http').createServer();
var io = require('socket.io')(server);
var fs = require('fs');
var jsgo = require('jsgo');
io.on('connection', function(client){
fs.readFile('train.dem', function (err, data) {
var demo = new jsgo.Demo();
demo.on('entity_updated', function (entity) {
console.log('entity_updated');
client.emit('tick', 'a');
});
demo.parse(data);
});
});
server.listen(3000);
Client Code
var socket = io('http://localhost:3000');
socket.on('connect', function() {
console.log('connected');
});
socket.on('tick', function (data) {
console.log('entity_updated');
});
socket.on('disconnect', function() {
console.log('disconnect');
});
Upvotes: 1
Views: 1770
Reputation: 9818
I was able to reproduce this issue by using the file (train.dem) you provided. The reason why the socket.io is not able to send more than one message is due to this statement:
demo.parse(data);
node.js is a single threaded environment and the above statement is blocking the event loop. When I run the above statement, it is taking forever to complete. I ran the code for more than 15 minutes but this function didn't exit probably due to the amount of processing it's doing. Due to the event driven single thread environment, node is not able to send messages. All the messages are buffered and waiting for this loop to exit.
I added some more logs to your code and you can observe the writable flag:
socket.io:server initializing namespace / +0ms
socket.io:server creating engine.io instance with opts {"path":"/socket.io"} +5ms
socket.io:server attaching client serving req handler +4ms
engine:socket sending packet "open" ({"sid":"SFD8FKG2G_MjW78SAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000}) +0ms
engine:socket flushing buffer to transport +2ms
engine:socket executing batch send callback +6ms
socket.io:server incoming connection with id SFD8FKG2G_MjW78SAAAA +7s
engine:socket sending packet "message" (0) +5ms
new client
engine:socket might upgrade socket transport from "polling" to "websocket" +36ms
engine:socket flushing buffer to transport +2ms
engine:socket executing batch send callback +5ms
engine:ws received "2probe" +15ms
engine:ws writing "3probe" +2ms
readFile done null
started
server --> entity_updated for 1client.conn.transport.writable true
engine:socket sending packet "message" (2["tick","a"]) +258ms
engine:socket flushing buffer to transport +1ms
server --> entity_updated for 2client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +2ms
server --> entity_updated for 3client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +1ms
server --> entity_updated for 4client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 5client.conn.transport.writable false
The same can be reproduce using a for..loop. Check the code below:
for (i=0; i<10; i++)
{
console.log('server --> entity_updated for ' + count + 'client.conn.transport.writable ' + client.conn.transport.writable);
count++;
client.emit('tick', 'a');
}
and the log below:
socket.io:server initializing namespace / +0ms
socket.io:server creating engine.io instance with opts {"path":"/socket.io"} +7ms
socket.io:server attaching client serving req handler +3ms
engine:socket sending packet "open" ({"sid":"b86YJD0sGGawVZseAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000}) +0ms
engine:socket flushing buffer to transport +2ms
engine:socket executing batch send callback +6ms
socket.io:server incoming connection with id b86YJD0sGGawVZseAAAA +2s
engine:socket sending packet "message" (0) +6ms
new client
engine:socket might upgrade socket transport from "polling" to "websocket" +23ms
engine:socket flushing buffer to transport +4ms
engine:socket executing batch send callback +2ms
engine:ws received "2probe" +8ms
engine:ws writing "3probe" +5ms
readFile done null
started
ended
server --> entity_updated for 1client.conn.transport.writable true
server --> entity_updated for 1client.conn.transport.writable true
engine:socket sending packet "message" (2["tick","a"]) +100ms
engine:socket flushing buffer to transport +0ms
server --> entity_updated for 2client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +1ms
server --> entity_updated for 3client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 4client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 5client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 6client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +1ms
server --> entity_updated for 7client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 8client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 9client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 10client.conn.transport.writable false
engine:socket sending packet "message" (2["tick","a"]) +0ms
engine:ws received "5" +3ms
engine:socket got upgrade packet - upgrading +0ms
engine:socket flushing buffer to transport +1ms
engine:ws writing "42["tick","a"]" +0ms
engine:ws writing "42["tick","a"]" +1ms
engine:ws writing "42["tick","a"]" +0ms
engine:ws writing "42["tick","a"]" +0ms
engine:ws writing "42["tick","a"]" +0ms
engine:ws writing "42["tick","a"]" +0ms
engine:ws writing "42["tick","a"]" +0ms
engine:ws writing "42["tick","a"]" +1ms
engine:ws writing "42["tick","a"]" +1ms
engine:socket executing batch send callback +0ms
Once the for loop ends, the socket/io layer writes the data over socket. The same will happen to your code once demo.parse() completes processing.
You will have to figure out an alternate way of getting the data from jsgo in order to unblock the event loop and feeding the same to socket.io. Probably you can raise an enhancement request on jsgo github.
Upvotes: 1
Reputation: 2045
You have to save socket in some storage to emit every time enitity is updated.
for now you can try saving socket when connected in a variable but this wont work for many client because each time new socket is connected variable will be updated with new socket id.
var server = require('http').createServer();
var io = require('socket.io')(server);
var fs = require('fs');
var jsgo = require('jsgo');
var socketId; // this will only store one id. store it in some data storage or create room for each user and emit in room
io.on('connection', function(client){
socketId = client.id;
fs.readFile('train.dem', function (err, data) {
var demo = new jsgo.Demo();
demo.on('entity_updated', function (entity) {
console.log('entity_updated');
if(io.sockets.connected[socketId]) //check if socket is still connected.
{
io.sockets.to(socket.socketId).emit('tick', 'a');
}
});
demo.parse(data);
});
});
server.listen(3000);
Upvotes: 0