Socket io not working without refreshing page - Vue js - node.js

I established a chat between client and server.everything is fine but chat page needs to refresh to show recent messages.I tested using two different logins but the page which i refreshed is working fine but the other one not updating with recent messages
Server.js
io.on('connection', (socket) => {
console.log("---- client connected ----");
// send messages on every event
sendStatus = function (data) {
socket.emit('messages', data);
}
// get messages from the server
socket.on('send_message', function (data) {
new Chat({
user_id: data.user_id,
message: data.message,
date: data.date,
}).save(function(err, chat_data){
if (!err) {
Chat.findOne({ _id: chat_data._id }).populate('user_id').exec(function (err, chat) {
sendStatus(chat);
})
}
});
})
// send messages on load
Chat.find({}).populate('user_id').exec(function (err, chat) {
console.log('chattttttttt', chat)
socket.emit('onload_chat', chat);
})
})
Client.vue
mounted () {
this.getUsers()
this.$socket.on('messages', (data)=> {
this.chats.push(data)
console.log('on send message', data)
});
},
beforeMount () {
this.$socket.on('onload_chat', (data)=> {
this.chats = data
});
},

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

Socket.io and React: Warning: Can't perform a React state update on an unmounted component

I am a relative newcomer to React and implementing a chat app with react, socket.io, and node.
When the user is chatting with someone, he would connect to a socket. It works fine, but if the user leaves to another page, and RE-ENTERS the same chat again, a second socket is connected(bad), and I get the "Can't perform a React state update on an unmounted component" error.
I did implement code to have socket leave the room (on the second useEffect), if the user leaves the page. But that doesn't seem to work.
Thanks in advance,
Error:
Partial React frontend code:
useEffect(() => {
socket.emit("enter chatroom", { conversationId: props.chatId });
setChatId(props.chatId);
getMessagesInConversation(props.chatId, (err: Error, result: any) => {
if (err) {
setCerror(err.message);
} else {
setMessages(buildMessages(result.messages).reverse());
}
});
socket.on("received", (data: any) => {
setMessages((messages: any) => {
console.log("messages");
console.log(messages);
return [...messages.slice(-4), ...buildMessages(data.newMsg)];
});
});
}, []);
useEffect(() => {
return () => {
socket.emit("leaveChatroom", {
conversationId: chatId,
});
};
}, [chatId]);
simplified nodejs code
private ioMessage = () => {
this._io.on("connection", (socket) => {
console.log("socket io connected");
const socketUser = socket.request.user;
socket.on("enter chatroom", (data) => {
const room_status = Object.keys(socket.rooms).includes(
data.conversationId
);
if (!room_status) { // should only join if socket is not already joined.
socket.join(data.conversationId);
}
});
socket.on("leaveChatroom", (data) => {
socket.leave(data.conversationId);
});
socket.on("chat message", async (msg) => {
const database = getDB();
const newMessage = {
...msg,
createdAt: Date.now(),
};
await database.collection("message").insertOne(newMessage);
const messages = await database
.collection("message")
.find({ conversationId: msg.conversationId })
.toArray();
this._io.to(msg.conversationId).emit("received", {
newMsg: [messages[messages.length - 1]],
});
});
socket.on("disconnect", (socket) => {
delete this._users[socketUser.userId];
console.log("--- disconnect : ", socketUser);
console.log("--- active users: ", this._users);
});
});
};
detailed error log:

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.

io.to('socketId') not emitting the event

I want to send message to specific socket . I have saved the socketId in mongoo db . when i emit the event its not emitting the event . its works fine if i emit without specific socket what could be the issue ./ please help me
here is my code
io.on('connection', function (socket) {
socket.on('save-message-private',function(data){
console.log('private messgae ')
OnlineUsers.find({username:data.receiver},function(err,res){
if(!err){
// console.log(res)
console.log(res[0].socketId)
io.to(res[0].socketId).emit('new-message-private', { message: res });
}
else
console.log(err)
})
})
});
And here is my front end in angular 4
ngOnInit() {
var user = JSON.parse(localStorage.getItem("user"));
console.log(user)
if(user!==null) {
this.socket=io('http://localhost:4000',{query:"username="+user.nickname});
this.getChatByRoom(user.room);
this.msgData = { room: user.room, nickname: user.nickname, message: '',receiver:'group' }
this.joinned = true;
this.scrollToBottom();
this.getOnlineUsers();
this.socket.on('new-message', function (data) {
if(data.message.room === JSON.parse(localStorage.getItem("user")).room) {
this.chats.push(data.message);
this.msgData = { room: user.room, nickname: user.nickname, message: '' }
this.scrollToBottom();
}
}.bind(this));
this.socket.on('new-message-private',function(data){
console.log('private new')
console.log(data);
}.bind(this));
}
}
new-private-message not working
My socketId saved in db was different from client side socketId . so I updated the socketId on db and problem solved

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