Node.js, Socket.io emit in React not working - node.js

I just try to emit and listen socket in client and server:
As below, I only emit a message from the client to the server.
But I only get the message "connected socket" but data emit from client and server is not received.
import React, { useEffect, useState } from 'react'
import InputMainComponent from '#components/InputMainComponent'
import UserService from '../../service/user.service'
import socket from '../../socket/index.js'
import { io } from 'socket.io-client'
function InputMain() {
const [chat, setChat] = useState({
content: "",
error: "",
success: false
});
const handleChange = (e) => {
setChat({
...chat,
content: e.target.value
});
}
const handleSubmit = (idRoom, content, e) => {
e.preventDefault();
socket.connect("connection", (socket) => {
socket.emit('chat', {content: content});
socket.on("chat", (data) => {
console.log(data)
})
})
UserService.createChat(idRoom, content)
.then((res) => {
setChat({
content: "",
error: "",
success: true
});
})
.catch((error) => {
setChat({
...chat,
content: "",
error: error.message,
success: false
});
});
}
return (
<InputMainComponent handleSubmit={handleSubmit} handleOnChange={handleChange} chat={chat}/>
)
}
export default InputMain
And this is in server
//socket
const io = new Server(server, {
cors: {
origin: "http://localhost:3000",
}
});
io.on('connection', (socket) => {
console.log(`User is connected: ${socket.id}`);
socket.on("chat", (data) => {
console.log("Hi");
console.log(data);
io.sockets.emit('chat', msg)
// ...
});
socket.disconnect("disconnect", () => {
console.log(`User is disconnected: ${socket.id}`)
})
});
Finally, I only got this result below
Blockquote
Connected with MongoDB
Hi port:8080
User is connected: ixC-WnX6pzpDE82qAAAB
User is connected: kpQuAqAI2X1CraQjAAAD
User is connected: qJ69YgP4jbVN7w3TAAAF
Thanks a lot.

Related

Even if peer connection is establish but not getting the remote stream?

import React, { useEffect, useContext, useRef } from 'react';
import { SocketContext } from "../../contexts/socketContext";
const Call = ({ myId, otherId, init }) => {
const socket = useContext(SocketContext);
const localStream = useRef();
const remoteStream = useRef();
const _pc = useRef(new RTCPeerConnection());
useEffect(() => {
navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then((stream) => {
localStream.current.srcObject = stream;
stream.getTracks().forEach((track) => {
_pc.current.addTrack(track, stream);
});
}).catch((err) => {
console.log(err);
});
if (init) {
createAndSendOffer()
}
_pc.current.onicecandidate = (e) => {
if (e.candidate) {
socket.emit("candidate", { from: myId, to: otherId, candidate: e.candidate });
}
}
_pc.current.ontrack = (e) => {
console.log("Hello");
if (e.streams) {
console.log(e.streams);
}
}
});
useEffect(() => {
socket.on("offer", (data) => {
createAndSendAnswer(data);
});
socket.on("answer", (data) => {
setAnswer(data.answer);
});
socket.on("candidate", (data) => {
_pc.current.addIceCandidate(new RTCIceCandidate(data.candidate));
});
});
async function setAnswer(answer) {
_pc.current.setRemoteDescription(new RTCSessionDescription(answer));
}
async function createAndSendOffer() {
const offer = await _pc.current.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true });
socket.emit("offer", { from: myId, to: otherId, offer });
_pc.current.setLocalDescription(new RTCSessionDescription(offer));
}
async function createAndSendAnswer({ from, to, offer }) {
_pc.current.setRemoteDescription(new RTCSessionDescription(offer));
const answer = await _pc.current.createAnswer();
_pc.current.setLocalDescription(new RTCSessionDescription(answer));
socket.emit("answer", { from: myId, to: otherId, answer });
}
return (
<div>
<video autoPlay muted ref={localStream} />
<video autoPlay muted ref={remoteStream} />
</div>
)
}
export default Call
``
I am trying to make a video calling app but remote peer video is not getting.

I can send message to socket server and its print the output but can't recieve from the socket server to client in nodejs

I am Creating a chat application everything is almost done I can send messages and the server is receiving the data but can't receive the data from the socket.io server
basically, I created a separate server that connects the clients it didn't connect to the database. I tried everything but couldn't help
SocketServer.js
const io = require('socket.io')(9739, {
cors: {
origin: "*",
}
})
let activeUsers = [];
io.on('connection', (socket) => {
console.log('New user connected');
socket.on('login', (data) => {
console.log(data);
if (!activeUsers.some((user) => user.id === data)) {
activeUsers.push({
id: data,
socketId: socket.id
});
}
// remove the active user that id is null
activeUsers = activeUsers.filter((user) => user.id !== null);
console.log(activeUsers);
io.emit('activeUsers', activeUsers);
});
socket.on("sendMessage",(data)=>{
const { receiverId } = data;
const receiver = activeUsers.find((user) => user.id === receiverId);
console.log("Sending Message to : ", receiver);
console.log(data);
if(receiver){
console.log("comming")
console.log(receiver.socketId);
// send message to the receiver
const RSocketId = receiver.socketId;
console.log("RSocketId", RSocketId);
io.to(RSocketId).emit("getMessage", {
data: data,
});
}
});
socket.on("end", () => {
console.log("end");
socket.disconnect();
});
socket.on('disconnect', () => {
console.log('User disconnected');
activeUsers = activeUsers.filter((user) => user.socketId !== socket.id);
console.log(activeUsers);
io.emit('activeUsers', activeUsers);
});
});
Client Side
import axios from "axios";
import React, { useRef } from "react";
import nookies from "nookies";
import Index from "./index";
import FriendsHolder from "../../components/Holders/FriendsHolder";
import FriendsDetails from "../../components/Holders/details-chats-holders/FriendsDetails";
import { useRouter } from "next/router";
import DmsComponent from "../../components/Holders/details-chats-holders/DmsComponent";
import { userDetails } from "../../libs/chats";
import SetUserName from "../../models/SetUserName";
import { io } from "socket.io-client";
const friends = ({ token }: any) => {
const router = useRouter();
const [isLoading, setIsLoading] = React.useState(false);
const [username, setusername] = React.useState(false);
const [sendMsg, setSendMsg] = React.useState(null);
const [receivedMsg, setReceivedMsg] = React.useState(null);
const socket = useRef<any>();
React.useEffect(() => {
const init = async () => {
const { data } = await userDetails(token);
if (
data &&
(data.data.username.length > 20 || data.data.username === "")
) {
setusername(true);
} else {
setusername(false);
socket.current = io("ws://localhost:9739");
socket?.current.emit("login", data.data?.id);
socket?.current.on("activeUsers", (users: any) => {
console.log("active users", users);
});
}
};
if (token) {
init();
}
}, []);
const handleLoading = () => {
setIsLoading(true);
};
const handleNotLoading = () => {
setIsLoading(false);
};
React.useEffect(() => {
handleNotLoading();
}, [isLoading]);
// Sending message through the socket server
React.useEffect(() => {
if (sendMsg !== null) {
socket.current?.emit("sendMessage", sendMsg);
}
}, [sendMsg]);
// Recieving Message through the socket server
React.useEffect(() => {
socket.current?.on("getMessage", (data: any) => {
setReceivedMsg(data);
});
}, []);
React.useEffect(() => {
console.log(receivedMsg);
}, [receivedMsg]);
return (
<Index>
{username ? (
<SetUserName />
) : (
<>
<FriendsHolder data={token} handleLoading={handleLoading} />
{router.asPath === "/app/friends" && <FriendsDetails token={token} />}
{router.asPath === `/app/friends?id=${router.query.id}` &&
!isLoading && (
<DmsComponent token={token} setSendMsg={setSendMsg} />
)}
</>
)}
</Index>
);
};
export default friends;
export const getServerSideProps = async (ctx: any) => {
const cookies = nookies.get(ctx);
const token = cookies.token;
if (!token) {
return {
redirect: {
destination: "/?login",
permanent: false,
},
};
}
return {
props: {
token: token || null,
},
};
};

How to use socketio inside controllers?

I have a application created with Reactjs,Redux,Nodejs,MongoDB. I have created socketio in backend side.
server.js
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const app = express();
const routes = require('./routes/api/routes');
var server = require('http').Server(app);
const io = require('./socket').init(server);
app.use(express.json());
require('dotenv').config();
mongoose.connect(process.env.MONGO_DB).then(console.log('connected'));
const corsOptions = {
credentials: true, //access-control-allow-credentials:true
optionSuccessStatus: 200,
};
app.use(cors(corsOptions));
app.use(routes);
if (
process.env.NODE_ENV === 'production' ||
process.env.NODE_ENV === 'staging'
) {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
io.on('connection', (socket) => {
console.log('New client connected');
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});
server.listen(process.env.PORT || 5000, () => {
console.log('socket.io server started on port 5000');
});
socket.js
let io;
module.exports = {
init: (httpServer) => {
return (io = require('socket.io')(httpServer, {
cors: {
origin: 'http://localhost:3000',
methods: ['GET', 'POST'],
},
}));
},
getIO: () => {
if (!io) {
throw new Error('Socket.io is not initialized');
}
return io;
},
};
In controller.js I am creating new item to inside mongodb and also using socketio. I am emitting new Item that I created. It looks like that
controller.js
const createTeam = async (req, res) => {
const userId = req.user.id;
const newItem = new Item({
name: req.body.name,
owner: userId,
});
await newItem.save((err, data) => {
if (err) {
console.log(err);
return res.status(500).json({
message: 'Server Error',
});
}
});
await newItem.populate({
path: 'owner',
model: User,
select: 'name',
});
await User.findByIdAndUpdate(
userId,
{ $push: { teams: newItem } },
{ new: true }
);
io.getIO().emit('team', {
action: 'creating',
team: newItem,
});
res.json(newItem);
};
In frontend side I am listening the socketio server with socket.io-client. In my App.js I can see data that come from backend side when I console.log(data). My app working perfect until this stage. I can take the data from socketio, I can see the new client that connected. But when I send the data with dispatch, I app start to add infinite new items to database. Take a look at my App.js
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import { AppNavbar } from './components/AppNavbar';
import { TeamList } from './components/TeamList';
import { loadUser } from './Store/Actions/AuthActions';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { io } from 'socket.io-client';
import { addItems } from './Store/Actions/itemActions';
function App() {
const dispatch = useDispatch();
useEffect(() => {
dispatch(loadUser());
const socket = io('http://localhost:5000');
socket.on('team', (data) => {
if (data.action === 'creating') {
dispatch(addItems(data.team));
}
// console.log(data);
});
}, []);
return (
<div className="App">
<AppNavbar />
<TeamList />
</div>
);
}
export default App;
My itemAction in redux side is also like that
export const addItems = (input) => (dispatch, getState) => {
axios
.post('/api/items/createTeam', input, tokenConfig(getState))
.then((res) =>
dispatch({
type: ADD_ITEM,
payload: res.data,
})
)
.catch((err) =>
dispatch(
returnErrors(err.response.data, err.response.status, 'GET_ERRORS')
)
);
};
My problem is how to stop infinite callling of api after implement socketio. How to stop infinite loop efficiently?
Infinite loop is steming from not dispatching "type: ADD_ITEM" once.This issue cause that your itemAction always would dispatch "type: ADD_ITEM" and payload with it when after every fetching then your react would re-render page again and again.
You should get rid of your dispatching action inside of addItems function and dispatch your action only inside of useEffect in App.js file .
Your code snippet should look like this in App.js:
useEffect(() => {
//...
const socket = openSocket('http://localhost:5000');
socket.on('postsChannel', (data) => {
if (data.action === 'creating') {
dispatch({ type: ADD_ITEM, payload: data.team });
}
});
}, [dispatch]);

Multiple listeners & removeListener removes everything Socket.io

Folks! I am writing a socket.io chat. When the user sends a message, the socket.on event occurs. Everything works, but the amount of listeners is growing exponentially. I tried to remove the listener with socket.off/socket.remove..., take out the event socket.on separately from connection - nothing works. Please, please help me figure it out. I`m using react, node, socket & mongoDB
Server part:
const express = require("express");
const app = express();
const cors = require("cors");
const { UserModel } = require("./models");
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.options("http://localhost:3000", cors());
const mongoose = require("mongoose");
require("dotenv").config();
const http = require("http").createServer(app);
const io = require("socket.io")(http, {
cors: {
origin: ["http://localhost:3002"],
},
});
http.listen(3001, function () {
console.log("Server is running");
});
io.on("connection", (socket) => {
console.log("Socket connected", socket.id);
socket.on("message:send", (data) => {
console.log("Пришло в socket.onMessage", data);
socket.emit("message:fromServer", data);
// socket.removeListener("message:fromServer");
});
});
const { userApi } = require("./api/userApi");
app.use("/", userApi);
app.use((err, _, res, __) => {
return res.status(500).json({
status: "fail",
code: 500,
message: err.message,
});
});
const { PORT, DB_HOST } = process.env;
const dbConnection = mongoose.connect(DB_HOST, {
useNewUrlParser: true,
useFindAndModify: false,
useCreateIndex: true,
useUnifiedTopology: true,
});
dbConnection
.then(() => {
console.log("DB connect");
app.listen(PORT || 3000, () => {
console.log("server running");
});
})
.catch((err) => {
console.log(err);
});
Client part:
io.js
import { io } from "socket.io-client";
export const socket = io("http://localhost:3001/");
Message component
import React from "react";
import { useState } from "react";
// import { useSelector } from "react-redux";
// import { getMessages } from "../../Redux/selectors";
import { socket } from "../helpers/io";
import Message from "../Message/Message";
import { nanoid } from "nanoid";
export default function MessageFlow() {
const [message, setMessage] = useState([]);
socket.on("message:fromServer", (data) => {
console.log("На фронт пришло сообщение: ", data);
setMessage([...message, data]);
// setMessage((message) => [...message, data]);
console.log("Массив сообщений компонента MessageFlow", message);
console.log(socket.io.engine.transports);
// socket.off();
// getEventListeners(socket)['testComplete'][0].remove()
// socket.removeListener("message:fromServer");
});
// const dispatch = useDispatch();
// const allMessages = useSelector(getMessages);
return (
<div id="mainDiv">
{message &&
message.map((i) => {
// return <Message />;
return <Message content={i.userId} id={nanoid()} />;
})}
</div>
);
}
Message Form - the beginning of emitting process
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { sendMessage } from "../../Redux/Chat/Chat-operations";
import { getUser } from "../../Redux/selectors";
import { getToken } from "../../Redux/Auth/Auth-selectors";
import { socket } from "../helpers/io";
import { useEffect } from "react";
import styles from "./MessageForm.module.css";
export default function MessageForm() {
const [message, setMessage] = useState("");
const dispatch = useDispatch();
const userId = useSelector(getUser);
const currentToken = useSelector(getToken);
// const getAll = useSelector(allContacts);
const updateMessage = (evt) => {
setMessage(evt.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
if (message) {
socket.emit("message:send", { userId: message });
dispatch(
sendMessage(
{
_id: userId,
text: message,
},
currentToken
)
);
} else {
alert(`Молчать будем?`);
}
};
return (
<div className={styles.messageInputContainer}>
<form>
<input
type="text"
value={message}
onChange={updateMessage}
required
className={styles.messageInput}
placeholder="Type message to send"
/>
<button
type="submit"
className={styles.messageAddBtn}
onClick={handleSubmit}
>
Send
</button>
</form>
</div>
);
}
You add a listener on every render, you should use useEffect hook
export default function MessageFlow() {
useEffect(()=>{ // triggered on component mount or when dependency array change
const callback = (data) => {
// what you want to do
}
socket.on("message:fromServer", callback);
return () => { // on unmount, clean your listeners
socket.removeListener('message:fromServer', callback);
}
}, []) // dependency array : list variables used in your listener
// [...]
}

NestJS Socket.Io left room but still receiving messages

I have three rooms General, TypeScript and Nest. I'am joining General room in the first and second browser tab. When I decide to leave General from the second tab and join TypeScript room I still get the messages from General even though I should have left it. The bug occures when you switch to room that has been in use by other client and leave it. I'am using NodeJs, Socket.io, NestJS and React.
Server
#WebSocketGateway()
export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
#WebSocketServer() server: Server;
private logger: Logger = new Logger('ChatGateway');
#SubscribeMessage('msgToServer')
handleMessage(client: Socket, message: { sender: string, room: string, message: string }): void {
this.server.to(message.room).emit('msgToClient', message);
this.logger.log(`msgToClient: ${message}`);
}
#SubscribeMessage('joinRoom')
handleRoomJoin(client: Socket, room: string ) {
client.join(room);
client.emit('joinedRoom', room);
this.logger.log(`Client joined ${room}`);
}
afterInit(server: Server) {
this.logger.log('Init');
}
handleDisconnect(client: Socket) {
this.logger.log(`Client disconnected: ${client.id}`);
}
handleConnection(client: Socket, ...args: any[]) {
this.logger.log(`Client connected: ${client.id}`);
}
#SubscribeMessage('leaveRoom')
handleRoomLeave(client: Socket, room: string ) {
console.log(client.id);
/* console.log(client.rooms);
console.log(client.adapter.rooms); */
client.leave(room);
/* console.log(room); */
/* client.rooms = {};
delete client.adapter.rooms[room]; */
client.emit('leftRoom', room);
this.logger.log(`Client left ${room}`);
/* console.log(client.adapter.rooms);
console.log(client.rooms); */
// console.log(client.adapter.rooms)
}
}
Client
const [state, setState] = useState({ sender: "", room: "", message: "" });
const [chat, setChat] = useState([
{ sender: "Peter", room: "General", message: "test" },
]);
const socket = io(BASE_URL);
const [room, setRoom] = useState({
General: false,
TypeScript: false,
NestJS: false,
});
console.log(room);
useEffect(() => {
socket.on("msgToClient", (msg) => {
setChat([...chat, { ...msg }]);
});
});
const onTextChange = (e) => {
setState({ ...state, [e.target.name]: e.target.value });
};
const onMessageSubmit = (e) => {
e.preventDefault();
const { sender, room, message } = state;
socket.emit("msgToServer", { sender, room, message });
setState({ message: "", sender: "", room: "" });
};
const toggleRoomMembership = (chatroom) => {
const isMemberOfActiveRoom = (chatroom) => {
return room[chatroom];
};
if (isMemberOfActiveRoom(chatroom)) {
setRoom({ ...room, [chatroom]: false });
socket.emit("leaveRoom", chatroom);
} else {
setRoom({ ...room, [chatroom]: true });
socket.emit("joinRoom", chatroom);
}
};
const renderChat = () => {
return chat.map(({ sender, message }, index) => (
<div key={index}>
<h3>
{sender}: <span>{message}</span>
</h3>
</div>
));
};
Turns out the solution is simple. Put the socket into the useEffect and create state for it.
const [socket, setSocket] = useState({});
useEffect(() => {
const socket = io(BASE_URL);
setSocket(socket);
socket.on("msgToClient", (msg) => {
setChat([...chat, { ...msg }]);
});
}, []);

Resources