My code looks something like this:
io.sockets.on('connection', function(socket) {
player.on('updatePlayer', function(err, result) {
if(result) {
console.log("UPDATING PLAYER");
io.sockets.socket(socket.id).emit('updatePlayer', { player: player });
}
});
}
When I first start the server and load the website everything works fine. If I do an action that triggers the "updatePlayer" event my console looks like this:
UPDATING PLAYER
debug - websocket writing 5:::{DATA IM SENDING}
After I refresh the page, or close it and reload again I only get:
UPDATING PLAYER
Anyone has any idea why the socket doesn't emit anything at all?
It seems to ignore
io.sockets.socket(socket.id).emit('updatePlayer', { player: player });
The problem occurs because when you first visit the page after server start, you register updatePlayer event, and this callback "remembers" the current socket object.
Then you reload the page, that updatePlayer event fires, and its callback tries to access socket that was "remembered". That socket refers to your previous connection that is lost after page reload. That's why it can't send the message.
To solve this problem you have to declare all the variables, that connected somehow with player object, inside io.sockets.on('connection') callback.
Related
I need the socket connection to establish before I can send data from the route to the user (otherwise it is not possible).
In app.js file I have socket connection logic:
app.use(function(req, res, next)
{
req.sio = sio;
next();
});
sio.on('connection',
function(soc)
{
console.log('socket connected');
soc.on('disconnect', function(reason)
{
console.log('socket disconnected');
});
// and more about socket connection here...
});
In index.js file I have route.post logic:
router.post('/route1', function(req, res, next) // user is moved from index.js to route1.js if he fills the form
{
var fromInput = req.body.form_name;
console.log('DATA passed from INDEX.JS: ' + formInput);
if ((formInput !== '') && (formInput !== null) && (formInput !== undefined))
{
function render()
{
//// first we render the page, so the javascript (with socket.io notes) can be read it and then the browser know that socket connection should be established
return new Promise(function(resolve, reject)
{
resolve(res.render('route1'));
});
}
// I need to pass some data AFTER the socked connection is established - cause I move to a different page path - using a **router.post** and cause of that socket connection is disconnected - so I need to wait till its usable again. For simplicity let suppose socket connection is established after 2 seconds (it is a simple check for req.soc.connected):
var soc = false;
setTimeout(function()
{
soc = true; // after 2 sec soc is true (connection is established)
}, 2000);
// Now I want to create an interval that will monitor IF socket connection is established every 100ms (so checking won't happen to often - it is not "resource hungry"). If socket connection is not ready the function should call it self (recursion) if the socket connection is established it (function) should fire a promise.
var arr = [];
arr.push(exe(100, data));
function exe(delay, d)
{
d = data;
return new Promise(function(resolve)
{
if (d === false)
{
setTimeout(function()
{
console.log('wait another ' + delay + ' [ms] - ' + d);
return resolve(exe(delay, d));
}, delay);
}
else
{
console.log('socket connected!');
return resolve(d);
}
});
}
render().then(function()
{
return Promise.all(arr).then(function(arr)
{
console.log(arr);
});
}).then(function()
{
console.log('ALL DONE!');
});
}
});
Comment are in code. If something isn't clear let me know.
#jfriend00
1 - true,
2 - true,
3 - I call render() immediately - so page is loaded and client make a socket connection, then the rest of the code should execute and send the data.
yes I did use POST with a form. There could be socket connection between the server and index page - not a problem I can create one, but I dunno what for.
"or there could be a socket.io connection created in the response to the POST when the browser renders and processes that." I'm trying that one :) I have data in this router.post I want to sent with help of sockets - but first I need to make a connection.
as I understand it... user did use form, so path is changed (socket connection is broken), then I'm in router.post I render the page FIRST - so the browser can read it's JS and make a socket connection, BUT you want to say that my response is not finished? So the browser say - ok you want me to render a page, but what now - cause we are NOT finish yet?!
So I will never establish a socket connection, cause I did not properly response? And cause of this I will not be able to send the data (later code in router.post) cause socket connection is never established cause I did not response properly? Cause my tests show me otherwise - it is working just fine.
you are right - code should works now.
till socket connection is established.
yea, good catch. I will make some kind of database - redis with express session I guess.
So again step by step.
User did fill the form so he is redirect from index.js to route1.js (so it does not make a difference if there is a socket connection BEFORE filling the form or not cause the connection is lost). We are in process of redirecting him (router.post) so I thought I will render the route1 page immediately, so the JS from it can be read by browser, and socket connection can be established (which take time - and IF its possible). So I wait with the data I want to sent to the user (in router.post for example... the form input or whatever) TILL the connection is established, and the send it to the user, with help of socket.io.
The thing is that socket io connection is lost when you change page (path). So I thought (and it could be wrong cause I'm newb) then I wait till it is established, and then send the data. I hope it does make sense.
This structure can never work. Here's what it looks like you're trying to do:
Express server receives a POST request.
Then, you try to wait for a socket.io connection to appear before you process the POST and send a response.
Finally, when you think you've found a socket.io connection, you then call your render() function to "presumably" send a response.
Without really understanding what you're' trying to accompilsh, there are a number of things wrong with the current code:
A POST request comes from either an Ajax call or a form POST. There is no socket.io connection associated directly with either one of those. There could have been a socket.io connection when the page loaded BEFORE the POST request was sent or there could be a socket.io connection created in the response to the POST when the browser renders and processes that.
Even if there was a socket.io connection created when the browser processes the POST response, you're trying to wait for the socket.io connection BEFORE you send the response so you're waiting for something that won't happen until you're done waiting (essentially a deadlock - A won't finish until B finishes, but B can't start until A finishes).
This structure render().then(waitUntil(100, d)) isn't correct. You MUST pass .then() a function reference. You are passing it a promise (the return value form calling waitUntil(...)). This is the least of your problems though because the overall structure of what you're trying to do is wrong.
The whole implementation of waitUntil() is confused and I can't even tell what it's trying to actually wait for.
This is a server that can field lots of connections from lots of clients. You can't just wait for the "next" socket.io connection and assume that connection is from the client you just got a request for. The only way to associate a socket.io connection with an http request is to use some identifying characteristic in both (usually a cookie) and then in the http request, you get the cookie and look up the cookie to see if you currently have a socket.io connection that matches that cookie. This is something that express-socket.io-session helps with.
Unfortunately, you don't describe what you're really trying to accomplish here so I can't point you to a good solution. All, I can really say here is that this scheme will not work. If you want further help with the actual problem, please edit your question to include the problem description in words (not your coding issues). Show the exact sequence of events you want to happen and explain what you're trying to accomplish and why.
I have a function to go out from account:
exports.logout = function(req,res){
req.session.destroy( err => {
if(err)
console.log(err);
res.redirect("/login");
});
};
To use socket.io and express together I have a middleware:
io.use(function(socket, next) {
sessionMiddleWare(socket.request, socket.request.res, next);
});
And I have function where I use socket.io. I need to disconect event fires only when user log out from application. But now my disconect event is emit always when I refresh a page:
exports.someFunction = function (io) {
io.on('connection', function(socket){
console.log(`Client connected socketId = ${socket.id}`);
console.log("session_id: " + socket.request.session.session_id);
usersMap.set(socket.request.session.session_id, socket.id);
});
socket.on('disconnect', function(){
usersMap.delete(socket.request.session.session_id);
console.log('user disconnected');
console.log("Map size: " + usersMap.size);
});
});
};
Please help, how to make to disconect event fires only when users log out from account. Sorry for my English.
You should not use socket.io's builtin disconnect event for that purpose. It will be emitted whenever user's connection to the server drops (that happens when he leaves your site or refreshes it), which is not equivalent to him or her logging out.
Since you have a server side logout function, that's the place you can see somebody logged out.
The disconnect event simply does not work the way you are asking for. That event will fire any time the user navigates to a new page or refreshes the current page. That's how socket.io connections work in the browser. A given connection belongs to a particular page and when a new page is loaded, the prior connection is disconnected and then a new connection is created. There is nothing you can do to change that - that's part of the browser architecture. So, the socket.io disconnect event is simply not the same thing as when your user logs out and can never be the same.
Instead, you need to have your own function that does a logout which the user can trigger by some action in the page. This can be either a socket.io message, an ajax call from your page or by navigating to the logout page. That's how a user can logout and it has nothing to do with the disconnect event.
Similarly, a connect event just means that a user (who may or may not already be logged in) has connected. The login state will be stored in either a cookie or in a server-side session (that is indexed by a cookie).
I use NodeJS with socket.io for my chat application. When client refreshes/closes the window or navigates to different URL I need client to emit "disconnect" event to NodeJS server. All works nice with excpetion of IE8/9. When refresh happens "disconnect" event is not send to server so server is not aware that this particular client is no longer connected.
I managed to use:
window.onbeforeunload = function(e) {
socket.disconnect();
};
and this takes care of clicking back/forward button and then the server is informed about client disconnecting. Refreshing the page or closing the tab however doesn't send disconnect to server. It seems that refreshing the page is too quick so the socket.disconnect() has no chance of executing. It seems so as if I do alert like below, client pauses for alert window and server receives disconnect message.
window.onbeforeunload = function(e) {
socket.disconnect();
alert("hey watchout!");
};
Now, is there any way to make IE8/9 send disconnect event to NodeJS when page is refreshed?
You can send information back and forth and find the time of the last reply, compare it to now and if the difference is greater than a number, disconnect the client, then reconnect when the client starts sending again.
You can use something like:
On client:
socket.on('ping',function(){socket.emit('pong',(new Date()).getTime());});
On server:
socketReferences = new Array();
io.on('connection',function(socket){
socketReferences.push(socket);
socket.on('pong',function(data){
if(new Date()).getTime()>5000){
// disconnect code here
}
});
});
setInterval(function(){
for(socket in socketReferences)
socketReferences[socket].emit('ping','');
},700);
I need to send data to nodejs server via socket.io when the user closes the browser tab .
I tried doing :
var data={};
window.onbeforeunload = function() {
// i have a object to be sent
data.data1='abcd';
data.data2=1234;
socket.emit("senddata",data);
}
This code works when the user navigates around clicking links on the site but doesnot work when the user closes the browser tab
I also tried configuring the socket io on server side as below .. thinking the error may be due to socket connection being closed before emitting data:
var io = require('socket.io').listen(app.listen(port));
io.configure(function () {
io.set('close timeout',12000);
});
It also didnt work most of the time.
I also tried this on client side:
var socket = require('socket.io').listen(80, {
"sync disconnect on unload":false
});
It also did not work
I had tried receiving data like this
var io = require('socket.io').listen(app.listen(port));
io.sockets.on('connection', function (socket) {
socket.on('senddata', function (data) {
// data processing
});
});
please ..help me with this problem..thanks in advance..
When user connects - register on server side the time it happened.
Socket.IO has heart beating and pinging functionality. So just subscribe to disconnect event on server side and once it happens - means client disconnected - and you have on server time when client had connection. So that way you have timespan of client session.
Do not trust client to tell you any time or important data, as client can simply 'lie' - which leads to hacks/cheats/bugs on your server-side.
There is no reliable way to send data just before disconnect from client-side at all. There is nothing in Socket.IO for that, nor in just one of transports (WebSockets). As well as there is too many different scenarios of disconnection (power off, force close, ethernet cable out, wifi lose, etc).
I want to run some code when a a socket is closed but only if the user didn't reload the page...
I have something like
socket.on("close", function() {
//do something here
});
The problem is that this function runs during a reload event as well...Can I somehow pause it to run at a later time with the value at that later time. I tried just using a set timeout within the callback but couldn't access the socket object anymore from within the callback.
Whats the best way to prevent the function from running if a socket connection is regained shortly after?
the main concept of my thought, is that you can never know that a user is reloading or disconnecting and never come back for 1day or so , there are ways to detect that the browser is navigating away from the website, but cant know (in server side) that it will go to the same address, or different..
Instead if any clients disconnect, of course the disconnect event will be fired to socket.io server for that socket, so taking that in account you can set a Session Variable to false you can say that the player is "disconnected" so when the client of that session "reconnects" aka reloads , the socket.io will fire an "connection" event, BUT reading the session variable you can say that the client has previously disconnected and then connected again. Timestamps could apply to this so a reconnection after 15min would have to load some extra data etc..
So you can try this with sessions (assuming that you use express or something)
sockets.on("connection",function(socket){
if(session.isAReload){
// this is a reconnection
}
socket.set("isAReload",session.isAReload /*defaults to false*/);
});
sockets.on('close',function(){
socket.get('isAReload',function(err,isAReload){
if(isAReload){
// closed after reconnecting
}else{
/*
just closed connection, so next time it will be a "reload" or reconnection
a timer of lets say 30s could run to ensure that the client is reloading
*/
session.isAReload=true;
}
});
})