Stay Connected to Socket.io while switching pages - javascript

I have a phonegap app in which i connect to my node.js socket like so:
var socket = io.connect('http://54.213.92.113:8080');
It works fine but when I go to a different page, the socket gets disconnected.
I could just write the same code in the javascript on the next page but that's messier than I think it needs to be - as it would open up a new connection when it could have just stayed connected in the first place.
Is there any way to stay connected to the socket even if I switch pages?

suppose you have a multi-page application then ,here you can do a trick that when your socket gets connected first time when the page loads then you can assign the session id to that particular connection like this.and then bind that connection to that session.
io.on('connection', function(socket) {
socket.on('start-session', function(data) {
console.log("============start-session event================")
console.log(data)
if (data.sessionId == null) {
var session_id = uuidv4(); //generating the sessions_id and then binding that socket to that sessions
socket.room = session_id;
socket.join(socket.room, function(res) {
console.log("joined successfully ")
socket.emit("set-session-acknowledgement", { sessionId: session_id })
} else {
socket.room = data.sessionId; //this time using the same session
socket.join(socket.room, function(res) {
console.log("joined successfully ")
socket.emit("set-session-acknowledgement", { sessionId: data.sessionId })
})
}
});
Now you had binded the socket connection to a session now you are sending an acknowledgement too at the client side also .There what you can do is that store the session id to the web browsers session storage like this
At client side code
socket.on("set-session-acknowledgement", function(data) {
sessionStorage.setItem('sessionId', data.sessionId);
})
This will store the session id in the browsers session storage.Now when the page is navigated from page1 to page2 and so on. then send that session id to the server so that you will be connected to the same session logically like this
var session_id;
// Get saved data from sessionStorage
let data = sessionStorage.getItem('sessionId');
console.log(data)
if (data == null) {
session_id = null//when we connect first time
socket.emit('start-session', { sessionId: session_id })
} else {
session_id = data//when we connect n times
socket.emit('start-session', { sessionId: session_id })
}
So basically the logic behind is that we can use same session for multiple socket connections by doing this as every time the socket will be joined to that particular room only and emit the events which you can listen on server side and vice a versa.

Only if you build it as a single page application where the actual page doesn't reload load when navigating. However it would probably be better to design your socket.io code and your server side to be resilient to frequent socket connect / disconnect. This is especially true for code written to run on a cell phone.

Related

Socket.io respond to sender

What I'm trying to do is have socket respond to the sender ONLY. What I'm currently doing:
When user visit webpage I included js so he connects on server (on all webpages) but i'm not sure here when user reload page or just switch pages will he be reconnected every time or connection stays the same ?
Now I'm sending data to my node.js app that do something with it but in case of error/success How can I emit to specific client that send data (now i emit data for every user that is connected)
You have to call emit on the socket object :
io.on('connection', (socket) => {
socket.on('event', () => {
socket.emit('otherEvent', { data : ... });
});
});

Socket.io - Cant stop passing all data to all clients

I am having a issue where I am pulling data from a DB via node mysql & Express and passing it via socket.io.... but there's an issue am running into.
All users are updating with the same data rather than unique data per user.
For example:
If user A has just logged in he can see all his account details. But when user B logs in right after he can then see all his details....but it then updates user A details to show user B details as well.
I am trying to ensure user A can can only see his own and same for user B.
I have tried numerous things to stop this happening via JQuery but cant seem to find a resolution.
Below I have trimmed down a the code to a basic example:
HTML
<span id="id-val">User A</span>
<span id="user-val"></span>
Server side
server = http.createServer(app),
io = require('socket.io').listen(server);
function SQLuserData(userval) {
connection.getConnection(function (err, connection) {
connection.query('SELECT val FROM test WHERE name= ?;',
[userval],
function (err, rows) {
var accountval = rows[0]['val'];
if (accountval) {
console.log("Val : " + accountval);
UserVal(accountval);
} else {
console.log("Error | Val: " + err);
}
});
connection.release();
});
}
//Socket.io connection socket
io.sockets.on('connection', function (socket) {
socket.on('sqluser', function (userval) {
SQLuserData(userval);
});
});
//Pass val client side.
function UserVal(accountval) {
io.sockets.emit("valsocket", accountval);
}
Client side
var socket = io.connect();
//Used to grab information for that user from serverside.
$(document).ready(function () {
var userval = $('#id-val').text();
socket.emit('sqluser', userval);
});
//Grabs user value being passed from serverside and updates HTML.
socket.on("valsocket", function (accountval) {
$("#user_val").val(accountval);
});
Does anyone have any advice or potential solutions?
you need to grab and store the socket.id for each connected user
var users = {};
//Socket.io connection socket
io.sockets.on('connection', function (socket) {
socket.on('sqluser', function (userval) {
// 'userval' must be unique for each user
users[userval] = socket.id;
SQLuserData(userval);
});
});
and then use the same id to emit data ti single socket
//Pass val client side.
function UserVal(accountval, userval) {
io.sockets.socket(users[userval]).emit("valsocket", accountval);
}
for socket.io version 1.0 and above
io.to(users[userval]).emit("valsocket", accountval);
I think you want to avoid emitting the account data to all connected users, which is what Socket.IO's emit method does. It might be better have the client send a GET request to the server and respond with the account details to the individual client.
Here are some resources if you choose to use an HTTP request over Socket.IO:
jQuery GET
Express Respond
So basically the problem with your code is that you are not distinguishing between users . Since you are sending data through socket you need to be careful to whom you are sending data.
You can use socketio-auth to create a type of authentication . And then send the data as socket.emit(event, data); Where socket is an individual object per user . You can also use a cookie based session to help you with this .

Node.js - Redis - PHP : refresh and quit between browsers close the wrong room

I'm new to stakoverflow, but I swear that I really searched a lot before ask here. In short, I've two browsers opened, and two PHP sessions, redis takes care of the session, but when I try to refresh the page the online user that refreshed the node.js server take the (maybe socket id?) of the refreshed one, and if I do a logout on the not refreshed one, the connection will close as the refreshed one.
I know, it's messy. I have to set a socket id array with also session together?
Currently, I am storing each new connection in a room (to have private sockets), but I become to think that maybe I've to change something for make all work properly.
How you handle a refreshed page? Also because can happen that a user open another tab of same website, or a friend give a link and you visit that link, and you need the session id (ok) the saved user (ok) and the socket io socket (wrong in my case?). Maybe its because I don't know how to get the cookie outside this:
socket.on('connection', function(client) {
cookieManager = new co.cookie(client.request.headers.cookie);
clientSession.get("sessions/"+cookieManager.get("PHPSESSID"), function(error, result) {
if (error) {
console.log("error : "+error);
}
if (result != "") {
// if (result.toString() != "") {
console.log("PHP session id: " + cookieManager.get("PHPSESSID"));
//console.log(result.toString());
//console.log("print result: " + result); //warning! this will parse entire session, test only!
userData = JSON.parse(result);
}
}
}
By default, the nodejs server does not send back the php cookie.
When I used php + redis + socket.io, i used the configuration present in this answer: here (edit: I used memcache & a custom class, now I use redis + publish/subscribe to broadcast events!)
to connect, i read the cookie with javascript from the page and sent it in the beginning of the connection.
/** C "cookie" function, gets the cookie string.
* #param {string} [k] - key, the cookie to get
*/
function C(k){return(document.cookie.match('(^|; )'+k+'=([^;]*)')||0)[2]}
s = io.connect("//io."+ window.location.host +"/", {query: "id=" + C('PHPSESSID')});
from the nodejs side:
io.sockets.on("connection", function (socket) {
var cookie = socket.handshake.query.id;
...
});
I stored the data formatted in json in the redis database, with phpsessid as key.
Hope it helps!

get tab's socket instance on server

I have to get socket instance in my ajax request on server in node.js module. Here is my code.
app.js
io.set('authorization', function (handshake, callback) {
if (handshake.headers.cookie) {
cookieParser(handshake, null, function(err) {
handshake.sessionID = handshake.signedCookies['express.sid'];
});
} else { return callback('No cookie transmitted.', false); }
});
io.sockets.on('connection', function(socket) {
var session = socket.handshake.session;
var userid = session.userid;
socket.join("room");
//make user offline
socket.on('disconnect', function() {
//my code goes here...
//make user offline
})
});
Now in one of my ajax request, I want socket instance
app.post('/logout', function (req, res) {
//here i want socket instance, so I can emit message to all socket, accept this.
});
As I know, each tab creates it's own new socket connection, but session is unique between all tabs of browser. So, How Do I store socket for each tab on server side, where I can find easily socket instance, and then broadcast message to all sockets, excluding that socket which is creating events. (means user's active tab's socket connection)
any guess.
thanks
In my app, I can do what you say because i use namespace and room and so in a room i can find every socket of someone.
io.of('/user').clients(idRoom);
So that i can remove every socket of the user. But if you cannot use this, i think in your app you will have to implement outside socket.io a class for someone (using session as a way to see if it's already have a socket open or if you have to create a new instance). And in this class, have a socket table so that you will be able to handle socket of someone.
In my case, i do the same except that i use the room of socket.io to do that.
And to broadcast to every socket, it depends what is your app. If your app send to anyone in the same namespace, it doesn't change anything because the socket of the same session will also receive the message. But if not, you will have to implement a function to emit to every socket of the table i suggested above.
In my case i use the 'exclude' to ensure the current socket doesn't receive the message but usually you can use broadcast.
io.of('/user').in(this.id).except(socket.id).emit('msg', { text: text,type:person});
To conclude, socket.io will not help you to handle session and several socket for one user/session but you can manage to deal with it using room feature (in my case it was the best way), or implement a user class where you will manage a table of your session sockets.

Socket.io add two clients to room

I'm trying to implement private messaging in an app im creating using express 3 and socket.io
When a client connects a room with the clients userid is automatically created and joined. This is mainly for notifications and that sort of stuff. Now im trying to make this work for private chat too.When a user clicks the send button, the message gets sent along with the userid of the sender (from session userid) and the userid of the owner thats grabbed from a hidden field or attribute of element. And the sender joins the room with the owners userid namespace. The problem with this is that when the sender goes to another page or refresh the browser he is diconnected from the room, and doesnt recieve any further messages from the owner. He has to send a new message to rejoin the owners room. Now how do i percist the connection to the owners room? Or am i doing this all wrong? Is there a better or standard way to achieve this?
SERVER:
io.on('connection', function (socket) {
var sh = socket.handshake;
socket.join(sh.session.userid);
socket.on('chat', function (data) {
if (data.user) {
socket.join(data.owner);
}
io.sockets.in(data.owner).emit('chat',
{user: sh.session.user, message: data.message});
});
});
CLIENT:
var socket = io.connect('https://localhost/');
$('#send_message').click(function (e) {
socket.emit('chat',{message: $('.message').val(),
user:$('#user'), owner:$('#owner')} //Get this from hidden fields in chat form );
e.preventDefault();
});
socket.on('chat', function (data) {
$('ol').prepend('<li>' + data.user + '<br />' + data.message + '</li>');
});
Right. Because when you reload the page, the server gets a "client disconnected" message and unsubscribes the socket. The client will need to re-emit a 'chat' message (with same owner id) in order to get back onto the private feed.
One way is to have the client save the owner id in a cookie and recall it on every page load. Alternatively, you could have the server store and recall this info using a session cookie (http://www.senchalabs.org/connect/session.html), which, in essence, is much like the first option.

Categories

Resources