Socket.io is closed before the connection is established - node.js

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

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

Error: "disconnect" is a reserved event name, why am I getting this error?

I am building a chat application using react, node.js and socket.io.
I have the following hook that I use for connecting and disconnecting
useEffect(() => {
const { name, room } = queryString.parse(location.search)
socket = io(ENDPOINT)
setRoom(room)
// New user joins room
socket.emit('join', { name, room }, (userNamesPresent, error) => {
setUsersPresent(userNamesPresent.userNamesPresent)
})
return () => {
// User leaves room
socket.emit('disconnect')
socket.off()
}
}, [ENDPOINT, location.search])
and I handle it in node like this
io.on("connection", socket => {
socket.on("join", ({ name, room }, callback) => {
const { error, user } = addUser({id: socket.id, name, room})
if(error) {
return callback({error})
}
// Emitting a welcome message
socket.emit('message', {user: 'admin', text: `Welcome to the chat ${user.name}`})
// Broadcasting to everyone except the connecting user
socket.broadcast.to(user.room).emit('message', {user: 'admin', text: `${user.name} has joined ${user.room}`})
socket.join(user.room)
// Get the users in room
const usersPresent = getUsersInRoom(user.room)
const userNamesPresent = usersPresent.map(user => {
return {name: user.name}
})
callback({userNamesPresent})
})
socket.on('message-sent', (message, callback) => {
console.log(socket.id)
const user = getUser(socket.id)
io.to(user.room).emit('message', {user: user.name, text: message} )
callback()
})
socket.on("disconnect", () => {
console.log("User has disconnected")
removeUser(socket.id)
})
})
When I leave the page (go back to the previous page for example) I get the following error
As per the docs, instead of doing socket.emit('disconnect') in your cleanup function of useEffect since disconnect is a reserved event name in Socket.io, you can use socket.disconnect().
As per socket.io website there is disconnect is reserved keyword so you cannnot use it as socket.emit('disconnect') instead of it use it as socket.disconnect() and it will work.

Socket IO client does not emit when used outside initial connection

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)
})
});

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?

Resources