set username in socket io connection - javascript

I have a chat application where I have to handle online users.
How can i send user name in:
var myIoSocket = io.connect();
So i can make a list at the backend.
currently i am doing like this.
Socket.on("connect",function(){
Notification.primary('Connected');
Socket.emit('iamonline',{
username: $rootScope.username
});
});
Backend :
var onlineUsers = {};
io.sockets.on('connection', function(socket){
socket.on('iamonline',function (data) {
console.log(data.username," connected.")
onlineUsers[data.username] = socket;
Users[data.username] = socket;
currentUser = data.username;
console.log(socket)
io.sockets.emit("liveusers",Object.keys(onlineUsers));
});
socket.on('disconnect', function(){
delete onlineUsers[currentUser];
console.log(currentUser," disconnected.");
io.sockets.emit("liveusers",Object.keys(onlineUsers));
});
});

I had same issue for a different project and found out the best way to do it with query and get value on handshake.
server.js
io.on('connection' , function(socket){
if(typeof socket.handshake.name!="undefined"){
user = {
name : socket.handshake.query.name,
id : socket.handshake.query.id,
email : socket.handshake.query.email,
}
}
});
on client side,
if(typeof io != "undefined"){
var visitor = io.connect('ws://127.0.0.1:8000' , {
'query': $.param({token: '<?=Session::$instance->session['id']?>'}) + '&name=<?=Session::get("username")?>&id=<?=Session::get("ID")?>&email=<?=Sesion::get("Email")?>'
});
}

Related

Sending Data to Target Client with socket.io

For example, in the client side, i have two registred and online user.
UID 1 : Leon
UID 2 : Albert
Leon wants to know how much have credit.
for example, Leon hit the button to get credit, so:
socket.emit('my_credit', 1);
And in the server side, i use this code:
Example:
var express = require('express');
var server = express();
var app = require('http').createServer(server);
var io = module.exports.io = require('socket.io')(app);
io.on('connection', function(socket){
socket.on('my_credit', function(uid){
getUserCredit(uid, (result) => {
socket.emit('my_credit', result);
})
});
});
Now, in the client side, all users receive this value!
If I want only Leon to receive this value, how can i do ?
How can i do in the server side to find currect id ?
For sending message to target client, use to function:
Eg:
io.sockets.to(/* Unique ID */).emit('message');
Or:
io.on('connection', function (socket) {
socket.on('check', function(){
io.sockets.to(socket.id).emit('check', 'Just You: ' + socket.id);
});
});
Yo!
So basically, at the moment, I dont know any other solutions than checking socket id.
Example to emit client side:
socket.emit('my_credit', {user: 1, id: socket.id});
Receiving server side :
var express = require('express');
var server = express();
var app = require('http').createServer(server);
var io = module.exports.io = require('socket.io')(app);
io.on('connection', function(socket){
socket.on('my_credit', function(uid){
getUserCredit(uid.user, function(result){
socket.emit('my_credit', {res: result, id: uid.id});
})
});
});
And receiving client side :
socket.on('my_credit', (message) => {
if (message.id !== socket.id) return;
// your code here
})

Working with multiple tabs with Socket.io

I've the following code working in my server-side, it's all ok. But, I want to keep the same connection between n tabs, because when I open a new tab, looks like I've disconnected from the first tab... So, how can I keep the same connection?
client.js
socket.emit("connected", {user: inputUser.val()};
app.js
var express = require("express"),
app = express(),
http = require("http").Server(app),
io = require("socket.io")(http),
users = {};
io.on("connection", function(socket) {
socket.on("connected", function(data) {
socket.user = data.user;
users[socket.user] = socket;
updateUsers();
});
function updateUsers() {
io.emit("users", Object.keys(users));
}
socket.on("typing", function(data) {
var userMsg = data.user;
if(userMsg in users) {
users[userMsg].emit("typing", {user: socket.user});
}
});
socket.on("disconnect", function(data) {
if(!socket.user) {
return;
}
delete users[socket.user];
updateUsers();
});
});
var port = Number(process.env.PORT || 8000);
http.listen(port, function() {
console.log("Server running on 8000!");
});
Update:
The typing event above works fine... So I tried the typing event according to the answer:
var express = require("express"),
app = express(),
http = require("http").Server(app),
io = require("socket.io")(http),
users = {};
io.on("connection", function(socket) {
socket.on("connected", function(data) {
socket.user = data.user;
// add this socket to the Set of sockets for this user
if (!users[socket.user]) {
users[socket.user] = new Set();
}
users[socket.user].add(socket);
updateUsers();
});
function updateUsers() {
io.emit("users", Object.keys(users));
}
socket.on("typing", function(data) {
var userMsg = data.user;
if(userMsg in users) {
users[userMsg].emit("typing", {user: socket.user});
}
});
socket.on("disconnect", function(data) {
if(!socket.user) {
return;
}
// remove socket for this user
// and remove user if socket count hits zero
if (users[socket.user]) {
users[socket.user].delete(socket);
if (users[socket.user].size === 0) {
delete users[socket.user];
}
}
updateUsers();
});
});
var port = Number(process.env.PORT || 8000);
http.listen(port, function() {
console.log("Server running on 8000!");
});
But it is giving the following error:
users[userMsg].emit("typing", {user: socket.user});
^
TypeError: users[userMsg].emit is not a function
Update²:
To fix the typing event error, I just changed to:
socket.on("typing", function(data) {
var userMsg = data.user;
if(userMsg in users) {
for(let userSet of users[userMsg]) {
userSet.emit("typing", {user: socket.user});
}
}
});
There is no simple way to share a single socket.io connection among multiple tabs in the same browser. The usual model for multiple tabs would be that each tab just has its own socket.io connection.
The opening of a new tab and a new socket.io connection should not, on its own, cause your server to think anything was disconnected. If your code is doing that, then that is a fault in your code and it is probably easier to fix that particular fault.
In fact, if you want to explicitly support multiple tabs and be able to recognize that multiple tabs may all be used by the same user, then you may want to change your server side code so that it can keep track of multiple sockets for a single user, rather than how it is currently coded to only keep track of one socket per user.
If your server code is really just trying to keep track of which users online, then there's probably an easier way to do that by referencing counting each user. I will post a code example in a bit.
var express = require("express"),
app = express(),
http = require("http").Server(app),
io = require("socket.io")(http),
users = {};
io.on("connection", function(socket) {
socket.on("connected", function(data) {
socket.user = data.user;
// increment reference count for this user
if (!users[socket.user]) {
users[socket.user] = 0;
}
++users[socket.user];
updateUsers();
});
function updateUsers() {
io.emit("users", Object.keys(users));
}
socket.on("disconnect", function(data) {
if(!socket.user) {
return;
}
// decrement reference count for this user
// and remove user if reference count hits zero
if (users.hasOwnProperty(socket.user)) {
--users[socket.user];
if (users[socket.user] === 0) {
delete users[socket.user];
}
}
updateUsers();
});
});
var port = Number(process.env.PORT || 8000);
http.listen(port, function() {
console.log("Server running on 8000!");
});
If you need the users object to have the socket object in it, then you can change what is stored in the users object to be a Set of sockets like this:
var express = require("express"),
app = express(),
http = require("http").Server(app),
io = require("socket.io")(http),
users = {};
io.on("connection", function(socket) {
socket.on("connected", function(data) {
socket.user = data.user;
// add this socket to the Set of sockets for this user
if (!users[socket.user]) {
users[socket.user] = new Set();
}
users[socket.user].add(socket);
updateUsers();
});
function updateUsers() {
io.emit("users", Object.keys(users));
}
socket.on("disconnect", function(data) {
if(!socket.user) {
return;
}
// remove socket for this user
// and remove user if socket count hits zero
if (users[socket.user]) {
users[socket.user].delete(socket);
if (users[socket.user].size === 0) {
delete users[socket.user];
}
}
updateUsers();
});
});
var port = Number(process.env.PORT || 8000);
http.listen(port, function() {
console.log("Server running on 8000!");
});
For anyone still having this issue. here is how i fixed it.
let me explain.
once the page refreshes or a new tab is opened, socket dosen't really care so it opens a new connection every time . this is more of a advantage than disadvantage. the best way to tackle the issue is on the server side, once a user logs in with his or her user name , you can send that name along with the query options on the client so it can be used as a unique identifier. in my case i used a token
this.socket = io.connect(`${environment.domain}` , {
query: {token: this.authservice.authToken}
});
then on the server side you can create an empty array to a key and an array of values. the username of the user will be used as a key and the corresponding array of socket as the value. in my own case like i said i used a token
const users = [ ]
socket.nickname = (decoded token username);
users[socket.nickname] = [socket];
then you can perform a simple logic to check if a user already exists in an array, if it does, push the new socket to the array of the user
if ( user.username in users) {
console.log('already exists')
users[user.username].push(socket);
}
if it dosent, just create a new key and add the socket as the key.(make sure its an array because a user can always refresh or open a new tab with the same account and you dont want the chat message to deliver in one tab and not deliver in another)
else {
socket.nickname = username;
users[socket.nickname] = [socket];
}
then to emit a message you simply loop through the array and emit the message accordingly. this way each tab gets the message
socket.on('chat', (data) => {
if (data.to in users) {
for(let i = 0; i < users[data.to].length; i++) {
users[data.to][i].emit('chat', data)
}
for(let i = 0; i < users[data.user].length; i++) {
users[data.user][i].emit('chat', data)
}
}
})
you can add a disconnect logic to remove the socket from the users array too to save memory, so only currently open tabs acre active and closed tabs are removed. i hope it solved your problem
My solution is joining socket to a room with specific user Id.
io.on('connection', async (socket) => {
socket.join('user:' + socket.handshake.headers.uid) // The right way is getting `uid` from cookie/token and verifying user
})
One advantage is sending data to specific user (sending to all tabs)
io.to('user:' + uid).emit('hello');
Hope it's helpful!
I belive the best way is create a channel for the user and unique it by their ID, so, when you need to receive or send something you use the channel and every socket connected to it will receive.
Another solution is to save the flag to localStorage and use eventListener to change localStorage.
Do not connect when another connection exists.
and save message in local storage for send with master tab.

How to push notification to specific user Node + AngularJS + Laravel

I need help how to push notification to specific user. I can now push notifcation but all user will get that notification. I can filter it on clinet side but I think it is unsecure...
First I send data with laravel 5:
$redis = Redis::connection();
$redis->publish('update.answer', json_encode($events));
here is my node.js i emite data:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();
redis.subscribe('update.group', function(err, count) {
});
redis.subscribe('update.question', function(err, count) {
});
redis.subscribe('update.answer', function(err, count) {
});
redis.subscribe('update.comment', function(err, count) {
});
redis.on('message', function(channel, message) {
message = JSON.parse(message);
console.log(message);
io.emit(channel, message);
});
http.listen(3000, function(){
console.log('Listening on Port 3000');
});
and with angularjs I take data and push to the client.
socket.on('update.answer',function(data){
if($scope.remove){
$scope.remove = false;
}
$scope.feed = $("#feed").val();
if(parseInt($scope.feed) === parseInt(data.userID)){
$scope.answers.push(data);
$scope.$digest();
}
});
WIth this part:
$scope.feed = $("#feed").val();
if(parseInt($scope.feed) === parseInt(data.user_id) && data.admin_id !== null){
}
I check if client should get notification but it is unsecure...
Any way to improve this?
To push message to specific user , you must store his/her reference somewhere.
for ex
io.on('connection', function(socket) {
socket.on('add-user', function(data){
clients[data.username] = socket;
});
});
now to push message to specific user just use his username to retrive his socket
clients[data.username].emit(channel, message);
Update : Explanation
This Assume that each user who uses you web app is having some sort of authentication.
As soon as user login into your application , let him join on the nodejs backend socket.
on client side
socket.emit('add-user',userObj);
});
userObj is object that contains user details,you can send the username alone too
socket.emit('add-user',username);
in your nodejs first decalre one array that contains the socket of all the users who joins the website
var clients = [];
now in your nodejs application write this additional code
io.on('connection', function(socket) {
socket.on('add-user', function(data){
clients[data.username] = socket;
});
});
up to this moment the user who login into your website will call add-user event from client side which will in turn call add-user on nodejs and there socket will be added into the clients array
now to send message to any particular user you must know there username,so if you know the username of the user then you can simply emit message to them using
clients[data.username].emit(channel, message);

How to listen with node.js and redis Laravel 5 events

In Laravel 5 not implemented ShouldBroadCast method, any idea how I can implement it manualy?
Here is my try.
This is handler for ProjectNotificationEvent:
<?php namespace App\Handlers\Events;
use App\Events\ProjectNotificationEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;
use App\Notification;
use Illuminate\Support\Facades\Redis;
class NotifyUserAboutGroup {
CONST CHANNEL = 'update.group';
public function handle(ProjectNotificationEvent $event)
{
foreach ($event as $events){
$redis = Redis::connection();
$redis->publish(self::CHANNEL, $events->name);
}
}
}
This is node.js:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();
redis.subscribe('update.group', function(err, count) {
});
redis.on('message', function(channel, message) {
console.log('Message Recieved: ' + message);
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
http.listen(3000, function(){
console.log('Listening on Port 3000');
});
And on client side in my view I have this:
var socket = io.connect('127.0.0.1:3000');
socket.on("update.group:App\\Events\\ProjectNotificationEvent", function(message){
// increase the power everytime we load test route
console.log(message);
});
Problem is on client side console.log don't return anything.
Any solution for this?
var socket = io.connect('127.0.0.1:3000');
socket.on('message', function (data) {
console.log(data);
});
Please try this

how to get session id of socket.io client in Client

I want to get session id of client in my socket.io client.
here is my socket.io client :
var socket = new io.Socket(config.host, {port: config.port, rememberTransport: false});
// when connected, clear out display
socket.on('connect',function() {
console.log('dummy user connected');
});
socket.on('disconnect',function() {
console.log('disconnected');
});
socket.connect();
return socket;
I want to get session id of this client , how can i get that ?
Have a look at my primer on exactly this topic.
UPDATE:
var sio = require('socket.io'),
app = require('express').createServer();
app.listen(8080);
sio = sio.listen(app);
sio.on('connection', function (client) {
console.log('client connected');
// send the clients id to the client itself.
client.send(client.id);
client.on('disconnect', function () {
console.log('client disconnected');
});
});
On socket.io >=1.0, after the connect event has triggered:
var socket = io('localhost');
var id = socket.io.engine.id
I just had the same problem/question and solved it like this (only client code):
var io = io.connect('localhost');
io.on('connect', function () {
console.log(this.socket.sessionid);
});
* Please Note: as of v0.9 the set and get API has been deprecated *
The following code should only be used for version socket.io < 0.9
See: http://socket.io/docs/migrating-from-0-9/
It can be done through the handshake/authorization mechanism.
var cookie = require('cookie');
io.set('authorization', function (data, accept) {
// check if there's a cookie header
if (data.headers.cookie) {
// if there is, parse the cookie
data.cookie = cookie.parse(data.headers.cookie);
// note that you will need to use the same key to grad the
// session id, as you specified in the Express setup.
data.sessionID = data.cookie['express.sid'];
} else {
// if there isn't, turn down the connection with a message
// and leave the function.
return accept('No cookie transmitted.', false);
}
// accept the incoming connection
accept(null, true);
});
All the attributes, that are assigned to the data object are now accessible through the handshake attribute of the socket.io connection object.
io.sockets.on('connection', function (socket) {
console.log('sessionID ' + socket.handshake.sessionID);
});
On Server side
io.on('connection', socket => {
console.log(socket.id)
})
On Client side
import io from 'socket.io-client';
socket = io.connect('http://localhost:5000');
socket.on('connect', () => {
console.log(socket.id, socket.io.engine.id, socket.json.id)
})
If socket.id, doesn't work, make sure you call it in on('connect') or after the connection.
For some reason
socket.on('connect', function() {
console.log(socket.io.engine.id);
});
did not work for me. However
socket.on('connect', function() {
console.log(io().id);
});
did work for me. Hopefully this is helpful for people who also had issues with getting the id. I use Socket IO >= 1.0, by the way.
Try from your code
socket.socket.sessionid
ie.
var socket = io.connect('http://localhost');
alert(socket.socket.sessionid);
var sendBtn= document.getElementById('btnSend');
sendBtn.onclick= function(){
var userId=document.getElementById('txt1').value;
var userMsg = document.getElementById('txt2').value;
socket.emit('sendto',{username: userId, message: userMsg});
};
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
socket.on('message',function(data){ console.log(data);});
Try this way.
var socket = io.connect('http://...');
console.log(socket.Socket.sessionid);

Categories