I'm using socket io in two places in the app:
emiting offers on the main page that everyone can see
emiting chat messages only between two users based on order_id
I was able to set up first use case but not the second. When creating a new message, response status is 500 after hitting the socket part in the controller.
index.js
const serverIO = server.listen(
port,
console.log(`Listening on Port ${port}`)
);
const io = require("./socket").init(serverIO);
io.on("connection", (socket) => {
socket.join("some room");
console.log("cient connected");
});
socket.js
let io;
module.exports = {
init: (httpServer) => {
io = require("socket.io")(httpServer);
return io;
},
getIO: (socket) => {
if (!io) {
throw new Error("Socket.io not initialized!");
}
console.log("socket", socket());
return io;
},
};
chatController.js
const io = require("../socket");
const chatModel = require("./chatModel.js");
exports.createChat = async (req, res) => {
try {
const savedMessage = await chatModel.saveMessage(req.body);
if (!savedMessage) {
return res.status(400).json({
errorMessage: "Something went wrong with your chat request",
});
}
io.getIO().socket.to(req.body.order_id).emit("newMessage", { action: "create", message: savedMessage });
return res.status(200).json(savedMessage);
} catch (error) {
return res.status(500).json({
errorMessage: error,
});
}
};
on the client, I'm listening like this:
Chat.js
useEffect(() => {
const socket = openSocket(baseURL);
socket.on("newMessage", ({ room, data }) => {
console.log("room", room); //not being reached
if (data.action === "create") {
dispatch(addMessage(...data.message));
}
});
}, []);
I tried adding the boilerplate code from documentation but that didn't seem to work.
io.on('connection', socket => {
socket.join('some room');
});
How can I join rooms based on orderId and listen to said room on the client?
Was able to reach a working solution (chat messages are being broadcast only to the intended recipients)but don't know if it's optimal or efficient.
added socket.join in my index.js file
io.on("connection", (socket) => {
socket.on("joinRoom", (room) => {
console.log("joined room");
socket.join(room);
});
console.log("cient connected");
});
modified my controller
io.getIO().to(req.body.order_id).emit("newMessage", {
action: "create",
message: savedMessage,
});
And on the front end, on mount, I'm joining a room and listening for newMessage from server.
useEffect(() => {
const socket = openSocket(baseURL);
socket.emit("joinRoom", orderId);
socket.on("newMessage", (data) => {
console.log("data", data);
if (data.action === "create") {
dispatch(addMessage(...data.message));
}
});
}, []);
Related
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:
Im try in to create a little app and wanted to add websockets to it but im having some issues getting a connection. Im using the nuxt-socket-io and socket io.
const socket = require('socket.io')
// Options can be host, port, ioSvc, nspDir:
module.exports = (app) => {
let server = null
let io = null
app.use('/ws', (req, res) => {
if (!server) {
server = res.connection.server
io = socket(server)
io.on('connection', function (socket) {
console.log('Made socket connection')
socket.on('msg', (msg) => {
console.log('Recived: ' + msg)
setTimeout(() => {
socket.emit('msg', `Response to: ${msg}`)
}, 1000)
})
socket.on('disconnect', () => console.log('disconnected'))
})
}
res.json({ msg: 'server is set' })
})
}
this is being used to create the sockets on the server
and my nuxt-config is
['nuxt-socket-io', {
sockets: [ // Required
{ // At least one entry is required
name: 'main',
url: 'http://localhost:3000/api/ws',
path: 'ws',
default: true
}
],
server: false
}],
then in my .vue file
mounted () {
this.socket = this.$nuxtSocket({
path: '/api/ws'
})
},
methods: {
callSocket () {
console.log('trying to call socket')
this.socket.emit('msg', 'test message', (resp) => {
console.log(resp)
this.resp = resp
})
}
}
I get a response from the server
{"msg":"server is set"}
but I never get to the connection
console.log('Made socket connection')
but I can't seem to get connected to run any of the emits and i'm not sure why
you can see the full code repo at https://github.com/Chris9540/mappertron
if that will help give you more of an idea of what going on
This is my first time trying to add sockets so I may may done this completely wrong feel free to fork my branch with any alterations you suggest if I'm doing this completely wrong
I've manage to get it working by just using socket-io and socket.io-client see the I mainly followed this guide https://stackoverflow.com/a/65226573/7805726 see the repo for more details (https://github.com/Chris9540/mappertron) I would still like to get it working with nuxt-socket-io but I have sockets so im happy
for my fix I abstracted out some of the app set up to a new file
const app = require('express')()
const socket = require('socket.io')
const bodyParser = require('body-parser')
let server = null
let io = null
app.all('/ws', (req, res) => {
if (!server) {
server = res.connection.server
io = socket(server)
io.on('connection', function (socket) {
console.log('Made socket connection')
socket.on('msg', (msg) => {
console.log('Recived: ' + msg)
setTimeout(() => {
socket.emit('msg', `Response to: ${msg}`)
}, 1000)
})
socket.on('disconnect', () => console.log('disconnected'))
})
}
res.json({ msg: 'server is set' })
})
app.use(bodyParser.json())
module.exports = app
got rid of the nuxt-socket-io configs
and in my vue
this.$axios.$get('/api/ws')
.then((resp) => {
// eslint-disable-next-line no-undef
this.socket = io()
this.socket.on('msg', function (msg) {
console.log('socket responce', msg)
this.resps += `${msg}\n`
})
})
and
this.socket.emit('msg', JSON.stringify({ id: 1, x: 1, y: 1 }))
I am using socket.io-client in a react native chat application. The socket connects fine and it responds to on('connection') but it doesn't respond to messages. What is the proper way to configure socket.io-client to handle custom events? All the documentation I find looks like my implementation. My messaging module:
import io from 'socket.io-client';
Messenger = (props) => {
const [data, setData] = useState([]);
const [test, setTest] = useState('');
const socket = io('https://test.com', {
autoConnect: false,
});
const getCredentials = async () => {
await socket.connect();
await fetchMessages();
}
useEffect(() => {
socket.connect();
socket.on('connect', function() {
setTest('connected!');
});
socket.on('message', function(message) {
setTest('message!');
});
socket.on('typing', function(typing) {
setTest('typing');
});
getCredentials();
}, []);
return (...);
}
My server:
var socket_io = require( 'socket.io' );
const io = socket_io();
io.use((socket, next) => {
sessionMiddleware(socket.request, {}, next);
});
io.on( "connection", function( socket )
{
if (socket.request.session.auth_user) {
redisClient.set(socket.request.session.auth_user._id.toString(), socket.id);
socket.on( "disconnect", function() {
console.log( "A user disconnected" );
redisClient.del(socket.request.session.auth_user._id);
});
}
});
It's really hard to say without seeing your server but if comparing your case to my case it should be something like that:
useEffect(() => {
const socket = io('https://test.com', {
autoConnect: false,
});
socket.on('connect', function () {
setTest('connected!');
socket.on('message', function (message) {
setTest('message!');
});
socket.on('typing', function (typing) {
setTest('typing');
});
});
}, []);
I am trying to write an integration test for socket io. I am using try-catch for server event when the error is catched I emit an event for the client to handle the error
io.of('/rooms').on('connection', socket => {
const socketId = socket.id;
console.log('server socketid', socketId);
const userRepository = getCustomRepository(UserRepository);
const conversationToUserRepository = getCustomRepository(ConversationToUserRepository);
socket.on('initGroupChat', async (users_id, fn) => {
try {
const [user, listConversationToUser] = await Promise.all([
userRepository.findOne({
where: {
users_id,
},
}),
conversationToUserRepository.find({
where: {
users_id,
},
}),
]);
if (!user) {
throw new NotFoundError('User not found with id: ' + users_id);
}
console.log(2);
user.socket_id = socket.id;
await userRepository.save(user);
for (const item of listConversationToUser) {
socket.join(item.conversation_id.toString());
}
fn('init group chat success');
} catch (error) {
io.to(socketId).emit('error', errorHandlerForSocket(error));
console.log(10);
}
});
});
but on the socket client, nothing happens. here is the code socket client:
it.only('Init Group Chat with error', done => {
socket = io.connect(`http://localhost:${env.app.port}/rooms`, {
transports: ['websocket']
});
const id = 11111;
socket.emit('initGroupChat', id, (response: any) => {
console.log('response', response);
});
socket.on('error', (error: any) => {
console.log('error3', error);
done();
});
});
on the error event, the console.log did not show on the terminate. it didn't catch the event I emit on the server.
can anyone help me fix this issue
Every time the client Refresh socketId changes.
Server :
io.emit("send_to_client", {
userId: 112233,
data: "Hello user 112233"
});
Client :
var userLogin = 112233;
socket.on("send_to_client", function(res) {
if(res.userId === userLogin)
//somethingElse
});
im building a chat app using express and react and socket.io, and everything works, except that when I emit message from my server, it doesn't catch it in the client. Why is that? My code is:
index.js (server)
const io = require('socket.io')(server);
io.on('connection', socket => {
socket.on('join-room', data => {
console.log(`Joining room ${data.room}`);
socket.join(data.room);
});
socket.on('leave-room', data => {
console.log(`Leaving room room ${data.room}`);
socket.leave(data.room);
});
socket.on('new-message', data => {
console.log(`Sending message to room ${data.room}`);
socket.to(data.room).emit('new-message', data.message);
});
});
JoinRoom.js (react)
useEffect(() => {
socket.on('new-message', data => {
console.log('getting new message');
setMessages([...messages, data]);
});
}, [messages]);
useEffect(() => {
socket.emit('join-room', { room: id });
async function fetchData() {
const response = await req.get('/api/room/' + id);
setRoom(response.data);
const _messages = await req.get('/api/messages/' + id);
setMessages(_messages.data.docs);
}
fetchData();
}, [id]);
const send = e => {
e.preventDefault();
socket.emit('new-message', {
room: id,
message: newMessage
});
const data = {
message: newMessage,
user: 'Mikolaj',
roomId: id
};
req.post('/api/messages/send', data);
setNewMessage('');
};