Socket IO client does not emit when used outside initial connection - node.js

I have a Vue app that sets up a socket connection when the user logs in.
My component has a method that accesses an outer variable socket I made so that I can emit events in other methods..
onLoginSuccess() {
socket = io(`${process.env.SERVER_URL}`);
socket.emit('login', localStorage.getItem('username'));
socket.on('login-response', (response) => {
if (!response.status) {
alert(response.message);
return false;
} else {
this.$router.push("/home");
this.$refs.form.reset();
}
});
}
However, when I try to do socket.emit in another event it doesn't work:
onSocketLogout() {
console.log('socket logout call', socket)
socket.emit('delete_username_from_array', localStorage.getItem('username') );
},
Socket doesn't seem to be null/undefined on the console and I tried putting the same event emitter on the onLoginSuccess function and it works fine. It just doesn't work when I use socket in other functions or places outside the initial connection.
Here's my socket io server code:
let logged_in_users = [];
const io = require('socket.io')(http);
io.on('connection', function(socket){
console.log(`Socket ${socket.id} connected`);
socket.on('login', function(username){
// check duplicates
if(logged_in_users.includes(username)){
socket.emit('login-response', {
message: 'It seems that you have already logged in on another browser. Please logout first.',
status: false
});
return false;
}else{
socket.emit('login-response', {status: true});
console.log(`${username} logged in`)
logged_in_users.push({ username, id: socket.id });
}
});
// for logout
socket.on('delete_username_from_array', function(username){
console.log('removing username from array')
// delete the username from the array of logged in users
logged_in_users.splice( logged_in_users.indexOf(username), 1 );
});
socket.on('test', () => {
console.log("TEST")
})
socket.on('disconnect', () => {
console.log(`Socket ${socket.id} disconnected`);
console.log(logged_in_users)
})
});

Related

socket io on client side only runs after I save the file containing the connection

Hey super new to socket io and web sockets in general. I have a chatting app scenario with socket io where client emits to the server and the server emits back to the client.
In my case the emits from the client side are picked up on the server side so far no problems.
However on the client side there are some socket.on statements there to pick up stuff from the server. A generic console.log after connection fires, but the other socket.on statements do not.
My thought was that maybe the server side emits aren't firing. Where it gets weird though is that when I change something in the client side file with the socket.on statements, the client side statements will pick up the emits from the server until the next time I refresh the page.
It is also work noting that these client on statements work with the info that was gathered before the save: if something is like
Client-side:
socket.on("message", (data) => {
console.log(foo)
});
and I change it to
socket.on("message", (data) => {
console.log(bar)
});
and then trigger the chain of emits,
the socket.on("message... will fire properly but it will log "foo". My guess is that saving the client side socket file is creating a new connection or something, but I'm curious as to why only the old connection is picking up things from the server and not the new one?
My code for reference:
(client)
const token = localStorage.getItem("messenger-token");
const socket = io.connect('http://localhost:3001', {
query: {token}
});
//const socket = io('http://localhost:3001');
socket.on("connect", () => {
console.log("connected to server");
socket.on("new-message", (data) => {
console.log(data.message)
store.dispatch(setNewMessage(data.message, data.sender));
});
socket.on("mark-as-read", (data) => {
store.dispatch(markedAsRead(data.convoToUpdate,'socket'));
});
});
(server)
//www
const server = http.createServer(app);
app.io.attach(server,{'pingInterval': 2000, 'pingTimeout': 50000});
//app
app.io = require('socket.io')();
require('./sockets')(app)
app.io.use(function(socket, next){
const token = socket.handshake.query.token
if (token) {
jwt.verify(token, process.env.SESSION_SECRET, (err, decoded) => {
if (err) {
return next(new Error('Authentication error'));
}
User.findOne({
where: { id: decoded.id },
}).then((user) => {
return next();
});
});
} else {
return next();
}
})
//sockets module
module.exports = (app) => {
app.io.on("connection", (socket) => {
console.log("connected")
socket.on("new-message", (data) => {
socket.broadcast.emit("new-message", {
message: data.message,
sender: data.sender,
});
socket.on("mark-as-read", (data) => {
socket.broadcast.emit("mark-as-read", {
convoToUpdate:data.convoId
});
});
});
I don't know if this is appropriate but it turns out I didn't have a problem.
the server logic:
socket.broadcast.emit("mark-as-read", {
convoToUpdate:data.convoId
});
});
uses broadcast.emit instead of regular emit. This sends the new info to everyone except the sender as seen in the docs. oops

nodejs socket.io socket on is not a function

I got a middlware to validate my socket by jwt
but I have a problem making new events in other folders
Not to get everything in my app.js
I did this to authenticate my socket:
let io = require('socket.io')(server);
app.set("io", io);
io.use(verify.passportJwtAuth);
io.on('connection', function(socket) {
console.log('Authentication passed!');
// now you can access user info through socket.request.user
// socket.request.user.logged_in will be set to true if the user was authenticated
socket.emit('success', {
message: 'success logged in!'
});
});
midd:
async passportJwtAuth(socket,next) {
const secret = config.jwt.secret;
const token = socket.handshake.query.token;
jwt.verify(token, secret, function(err, decoded) {
if(err) {
return next(err);
}
console.log("sucess");
return next();
});
}
I've tried to make a new event:
const socketRouter = require('./routes/socket');
io.use(verify.passportJwtAuth);
io.on('connection', function(socket) {
console.log('Authentication passed!');
// now you can access user info through socket.request.user
// socket.request.user.logged_in will be set to true if the user was authenticated
socket.emit('success', {
message: 'success logged in!'
});
});
socketRouter.configuration();
my socketRouter.configuration:
const socketController = require ('../controllers/SocketController');
const verify = require('../auth/index');
const socket = require('socket.io');
module.exports = {
configuration: () => {
socket.on ('message', (message) => {
socket.emit ('myevent', {message: 'Ok, You are signed in'});
console.log (message);
console.log (`Socket $ {socket.id}`)
});
}
}
error:
C:\Users\SpiriT\Documents\Projetos\FtcJokenPo\back\src\routes\socket.js:6
socket.on ('message', (message) => {
^
TypeError: socket.on is not a function
at Object.configuration (C:\Users\SpiriT\Documents\Projetos\FtcJokenPo\back\src\routes\socket.js:6:14)
at Object.<anonymous> (C:\Users\SpiriT\Documents\Projetos\FtcJokenPo\back\src\app.js:36:14)
I didn't want to have to leave all my socket logic in my app.js
Also this way soon when I turn on the server I already call this module (I wanted it to call only when I use socket.on on the front end
Could someone give me a hand?
my front end:
verify = () => {
let socket = null;
var token = 312312312;
socket = io('http://localhost:8080', {
query: {token: token}
});
socket.on('error', function(err) {
console.error(err);
});
// Connection succeeded
socket.on('success', function(data) {
console.log(data.message);
})
}
In your socketRouter.configuration file, with this code below, your socket variable is not what you need it to be. It looks like you want it to be a specific connected socket that you can listen for incoming messages on. You are trying to use:
const socket = require('socket.io');
to get that socket, but that's simply the export object from the socket.io module and has nothing to do with an existing connected socket.
What it appears you need to do is to pass a particular socket to your configuration function and then use that argument in your function. First change the configuration module to this:
const socketController = require ('../controllers/SocketController');
const verify = require('../auth/index');
module.exports = {
configuration: (socket) => {
socket.on ('message', (message) => {
socket.emit ('myevent', {message: 'Ok, You are signed in'});
console.log (message);
console.log (`Socket $ {socket.id}`)
});
}
}
This removes the require('socket.io') line and adds a socket argument to the configuration function.
Then, where that configuration() function is called, you need to pass that socket argument:
const socketRouter = require('./routes/socket');
io.use(verify.passportJwtAuth);
io.on('connection', function(socket) {
console.log('Authentication passed!');
// now you can access user info through socket.request.user
// socket.request.user.logged_in will be set to true if the user was authenticated
socket.emit('success', {
message: 'success logged in!'
});
// let the socketRouter add any message handlers it wants to for this socket
socketRouter.configuration(socket);
});

Send specific message to specific socket.id with socket.io

I'm having problem finding the right answer for my problem. I want to had private messaging for every user like Telegram if I may say. Or like notifications on StackOverflow the socket event are only send to specific user.
io.on('connection', function (socket) {
// this will be only sent to a user that just connected
socket.emit('news', { hello: 'world' });
});
But how to send specific message with custom id?
Here my socket.js
const socketio = require('socket.io')
const { redis, saveUser } = require('./redis')
module.exports.listen = function(app){
io = socketio.listen(app)
io.on('connection', socket => {
console.log('connected user', socket.id)
socket.on('join', (payload) => {
redis.get(payload.email (err, socket_id) => {
socket.broadcast.to(socket_id).emit('join', `Hello ${payload.whoChat.name} Chat you`)
})
})
})
return io
}
but this doesn't send anything to my user, if using rooms it will send directly to the rooms and when i look for docs io.to() and io.broadcast.to() can be use with sockets rooms.
so i decided to take it simple but wrong here my server.js rigth now.
io.on('connection', function (socket) {
socket.on('join', payload => {
socket.emit('join', payload)
})
and on client-side
socket.on('join', (payload) => {
// Compare data from socket with local data if match then push the message
// to users who recieve
if ( payload.userId === localData.userId ) {
this.message.push(payload.message)
}
})
but with that actually I send it to all users... how to do it properly and right? and how to save the users socket.id? since socket.id are generated randomly how do you save it for the future request when user disconnect?
You need to maintain a map of _socket_id/user_id_
Server
const sessionsMap = {};
io.on('connection', (socket) => {
socket.emit('askForUserId');
socket.on('userIdReceived', (userId) => {
sessionsMap[userId] = socket.id;
});
socket.on('send', (message) => {
const receiverId = sessionsMap[message.receiverId];
const messageData = message.data;
socket.broadcast.to(receiverId).emit('my message', messageData);
});
});
Client
const userId = 'FOO';
io.on('askForUserId', () => {
io.emit(userId);
});
io.on('send', (message) => {
console.log('You received a message');
console.log(message.data);
});
Note
Make sure to check out the Socket.IO cheatsheet it covers a lot of commands and use cases.

Create separate rooms based on Pin code in the URL in socket io

I'm new in node js and socket io, I'm trying to create interactive quizzes based on pin code given in the url for ex: http://domain/start/5555 should create a quiz page with name 5555 and when clients have the pin code they can connect to this quiz. So it means i have to have a quiz page which shows all connected clients for example but i have some prblems with io.sockets.in(pincode).emit()
because i don't know if i'm creating rooms correctly or not!
here is my code
Client.js
var socket = io();
socket.on('connect', function () {
var params = jQuery.deparam(window.location.search);// To get the name and the room
socket.emit('join', params, function (err) {
if (err) {
alert(err);
window.location.href = '/join.html';
} else {
console.log('No error');
}
});
});
Server.js
app.get('/start/:pincode', (req, res) => {
io.on('connection', (socket) => { // to rigester connection listener
console.log('New user is connected');
// When somebody connects it verifies if the name and the room are valid strings
socket.on('join', (params, callback) => {
if (!isRealSrting(params.name) || !isRealSrting(params.pincode)) {
return callback('Name and pincode are required');
}
socket.join(params.pincode);
users.removeUser(socket.id);//Remove the user from other places
users.addUser(socket.id, params.name, params.pincode);
var x = users.getUserList(params.pincode);
console.log(x);
io.sockets.in(params.pincode).emit('updateUserList', { //here it doesn't work i don't know why!
users: users.getUserList(params.pincode),
pincode: params.pincode
});
socket.emit('newMessage', {
user: params.name,
pincode: params.pincode,
readyMessage: 'You are connected'
});// when the user connect to the server he gets this message
callback();
});
socket.on('disconnect', () => {
var user = users.removeUser(socket.id);
if (user) {
io.emit('updateUserList', users.getUserList(user.pincode));
//io.to(user.room).emit('newMessage', generateMessage('Admin', `${user.name} has left`));
}
});
});
res.render('start.hbs', {
pincode: req.params.pincode
});
});
and the main page
Start.js
var socket = io();
var pincode;
socket.on('updateUserList', function (users) {
console.log('here');
var ol = jQuery('<ol></ol>');
var usercount = users.users.length; // Players number
pincode = users.pincode;
});
Any help or suggestion please?

Socket.io is closed before the connection is established

I use in my app mongoose.js and socket.io. I try to emit an event in a mongoose callback. But my client (angular) does not seem to receive anything. Besides, it is continuously disconnected every time an event is emitted server side, in the callback and with 'user' data.
To be precise, my User model is wrapped in the following manner :
const mongoose = require('mongoose')
class DBReader {
constructor(name, schema) {
this.Model = require(`./models/${name}`)
}
find(params, callback) {
this.Model.find(params, callback)
}
findOne(params, callback) {
this.Model.findOne(params, callback)
}
findById(id, callback) {
this.Model.findById(id, callback)
}
}
module.exports = DBReader
And I instantiate my user like this :
const User = new DBReader('user')
The following code works, that is to say my client is not disconnected and receives the two events (It works because I don't emit 'user' data in the callback)...
function socket(httpServer) {
const io = require('socket.io')(httpServer)
io.on('connection', socket => {
console.log('User connected')
socket.emit('hello', 'Hello World !')
User.findOne({}, (err, user) => {
console.log(err)
console.log(user) // Displays the requested user
})
socket.emit('hello', 'Wooorld !')
socket.on('disconnect', () => {
console.log('User disconnected')
})
})
}
This code works too (because I don't emit 'user' data).
function socket(httpServer) {
const io = socketio(httpServer)
io.on('connection', socket => {
console.log('User connected')
socket.emit('hello', 'Hello World !')
User.findOne({}, (err, user) => {
console.log(err)
console.log(user)
socket.emit('hello', 'hellooo !')
})
socket.emit('hello', 'Wooorld !')
socket.on('disconnect', () => {
console.log('User disconnected')
})
})
}
But this code does not work (event emitted in the callback with 'user' data)...
function socket(httpServer) {
const io = socketio(httpServer)
io.on('connection', socket => {
console.log('User connected')
socket.emit('hello', 'Hello World !')
User.findOne({}, (err, user) => {
console.log(err)
console.log(user)
socket.emit('hello', user)
})
socket.emit('hello', 'Wooorld !')
socket.on('disconnect', () => {
console.log('User disconnected')
})
})
}
Do you have any explanation ? Do you need further information ?
I found the answer -_- !
Actually, it turned out I could not send accents (é, è, à...). And that is because my client side socket.io package was older than the server side one (1.7.? against 2.0.3).
I hope this answer will at least help the next person trying to emit an object with accents...
you can only emit something that can be stringified via JSON.stringify ( -> no circular references). As you are trying to send down the whole mongooseDocument, that will fail.
Either you can do a mongooseModel.find({...}).lean().exec(function callback(err, user){...}) which will return you a plain javascript object instead of the mongooseDocument (which can be serialized) or you can use the mongoose.toJSON method to convert it yourself.
regarding the problems of socket.io/angular, I can't help as you provided not enough code

Resources