0% found this document useful (0 votes)
31 views31 pages

Web RTC Video Call

This document describes the frontend code for a webRTC video call application. It includes imports for React, Chakra UI, Socket.io and other libraries. State variables are used to manage the call state and local/remote video streams. Functions handle initiating, accepting and rejecting calls via webRTC peer connections and Socket.io signaling.

Uploaded by

Rizi X
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views31 pages

Web RTC Video Call

This document describes the frontend code for a webRTC video call application. It includes imports for React, Chakra UI, Socket.io and other libraries. State variables are used to manage the call state and local/remote video streams. Functions handle initiating, accepting and rejecting calls via webRTC peer connections and Socket.io signaling.

Uploaded by

Rizi X
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 31

Web rtc video call:

frontend:
import { FormControl } from "@chakra-ui/form-control";

import { Input } from "@chakra-ui/input";


import { Box, Text } from "@chakra-ui/layout";
import { Flex } from "@chakra-ui/layout";
import { Alert, AlertIcon } from "@chakra-ui/react";
import "./styles.css";
import { IconButton, Spinner, useToast } from "@chakra-ui/react";
import { getSender, getSenderFull } from "../config/ChatLogics";
import React, { useState, useEffect, useRef } from 'react';
import axios from "axios";
import { ArrowBackIcon } from "@chakra-ui/icons";
import ProfileModal from "./miscellaneous/ProfileModal";
import { ChatState } from "../Context/ChatProvider";
import UpdateGroupChatModal from "./miscellaneous/UpdateGroupChatModal";
import ScrollableChat from "./ScrollableChat";
import io from "socket.io-client";
import Lottie from "react-lottie";
import animationData from "../animations/typing.json";
import { Progress } from "@chakra-ui/react";
import { ChatIcon } from '@chakra-ui/icons';

import { PhoneIcon } from '@chakra-ui/icons';


const ENDPOINT = "http://192.168.18.213:5000/";
let socket, selectedChatCompare;

const SingleChat = ({ fetchAgain, setFetchAgain }) => {


const [messages, setMessages] = useState([]);
const [loading, setLoading] = useState(false);
const [newMessage, setNewMessage] = useState("");
const [selectedFile, setSelectedFile] = useState(null);
const [fileUrl, setFileUrl] = useState("");
const [isUploading, setIsUploading] = useState(false);
const [socketConnected, setSocketConnected] = useState(false);
const [typing, setTyping] = useState(false);
const [istyping, setIsTyping] = useState(false);
const [uploadProgress, setUploadProgress] = useState(0);
const toast = useToast();

//...new
const [calling, setCalling] = useState(false);
const [localStream, setLocalStream] = useState(null);
const [remoteStream, setRemoteStream] = useState(null);
const [permissionDenied, setPermissionDenied] = useState(false);
const userVideoRef = useRef(null);
const remoteVideoRef = useRef(null);

const { selectedChat, setSelectedChat, user, notification, setNotification } =


ChatState();

const defaultOptions = {
loop: true,
autoplay: true,
animationData: animationData,
rendererSettings: {
preserveAspectRatio: "xMidYMid slice",
},
};

//for socket get initallize first we put this use effect at the top
useEffect(() => {
socket = io(ENDPOINT);
socket.emit("setup", user);
socket.on("connected", () => setSocketConnected(true));
socket.on("incomingCall", () => handleIncomingCall());
socket.on("typing", () => setIsTyping(true));
socket.on("stop typing", () => setIsTyping(false));

return () => {
socket.disconnect();
};

}, []);

useEffect(() => {
if (calling && localStream) {
initiatePeerConnection();
}
}, [calling, localStream]);

const initiatePeerConnection = () => {


// Initialize peer connection and add local stream
const peerConnection = new RTCPeerConnection();
localStream.getTracks().forEach(track => peerConnection.addTrack(track,
localStream));
// Event handler for receiving remote stream
peerConnection.ontrack = (event) => {
setRemoteStream(event.streams[0]);
remoteVideoRef.current.srcObject = event.streams[0];
};

// Create offer and set local description


peerConnection.createOffer()
.then(offer => {
peerConnection.setLocalDescription(offer);
// Emit offer to the recipient
socket.emit("call", { recipientId: selectedChat._id, offer });
})
.catch(error => {
console.error('Error creating offer:', error);
});
};
const handleIncomingCall = () => {
setCalling(true);
};

const initiateCall = () => {


// Ask for permission to access media devices
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
setLocalStream(stream);
userVideoRef.current.srcObject = stream;
setCalling(true);
})
.catch(error => {
console.error('Error accessing media devices:', error);
setPermissionDenied(true);
toast({
title: "Permission Denied",
description: "Please allow access to your camera and microphone.",
status: "error",
duration: 5000,
isClosable: true,
});
});
};

const acceptCall = () => {


navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
setLocalStream(stream);
userVideoRef.current.srcObject = stream;
const peerConnection = new RTCPeerConnection();
stream.getTracks().forEach(track => peerConnection.addTrack(track,
stream));
peerConnection.ontrack = (event) => {
setRemoteStream(event.streams[0]);
remoteVideoRef.current.srcObject = event.streams[0];
};
peerConnection.createAnswer()
.then(answer => {
peerConnection.setLocalDescription(answer);
socket.emit("answer", { callerId: selectedChat._id, answer });
})
.catch(error => {
console.error('Error creating answer:', error);
});
})
.catch(error => {
console.error('Error accessing media devices:', error);
});
};

const rejectCall = () => {


// Handle rejecting the call
setCalling(false);
};

const fetchMessages = async () => {


if (!selectedChat) return;

try {
const config = {
headers: {
Authorization: `Bearer ${user.token}`,
},
};

setLoading(true);

const { data } = await axios.get(


`/api/message/${selectedChat._id}`,
config
);
setMessages(data);
setLoading(false);
socket.emit("join chat", selectedChat._id);
} catch (error) {
toast({
title: "Error Occured!",
description: "Failed to Load the Messages",
status: "error",
duration: 5000,
isClosable: true,
position: "bottom",
});
}
};

const typingHandler = (e) => {


setNewMessage(e.target.value);

if (!socketConnected) return;

if (!typing) {
setTyping(true);
socket.emit("typing", selectedChat._id);
}
let lastTypingTime = new Date().getTime();
let timerLength = 3000;
setTimeout(() => {
let timeNow = new Date().getTime();
let timeDiff = timeNow - lastTypingTime;
if (timeDiff >= timerLength && typing) {
socket.emit("stop typing", selectedChat._id);
setTyping(false);
}
}, timerLength);
};
const uploadFile = async (file) => {
const formData = new FormData();
formData.append('file', file);

const config = {
headers: {
'Content-type': 'multipart/form-data',
Authorization: `Bearer ${user.token}`,
},
onUploadProgress: (progressEvent) => {
// Limit the reported progress to 90%
const progress = Math.round((progressEvent.loaded * 90) /
progressEvent.total);
setUploadProgress(progress);
},
};

const { data } = await axios.post("/api/message/attachment", formData,


config);
return data.fileUrl;
};
const handleFileChange = async (e) => {
const file = e.target.files[0];
const maxSize = 10485760; // 10 MB

if (file && file.size > maxSize) {


alert('File size too large. Maximum is 10 MB.');
return;
}

setIsUploading(true);
if (file) {
setSelectedFile(file);
const fileUrl = await uploadFile(file);
setFileUrl(fileUrl);
//alert('File attached successfully! Press Enter to send the message.');
}
setIsUploading(false);
};
const sendMessage = async (event) => {
if (event.key === "Enter" && (newMessage || fileUrl)) {

try {
const config = {
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${user.token}`,
},
};
setNewMessage("");
setSelectedFile(null);
const { data } = await axios.post(
"/api/message",
{
content: newMessage,
chatId: selectedChat,
fileUrl: fileUrl,
},
config
);
socket.emit("new message", data);
setMessages([...messages, data]);

} catch (error) {
toast({
title: "Error Occured!",
description: "Failed to send the Message",
status: "error",
duration: 5000,
isClosable: true,
position: "bottom",
});
}
}
};

useEffect(() => {
fetchMessages();
selectedChatCompare = selectedChat;
}, [selectedChat]);

useEffect(() => {
socket.on("message recieved", (newMessageRecieved) => {
if (
!selectedChatCompare || // if chat is not selected or doesn't match
current chat
selectedChatCompare._id !== newMessageRecieved.chat._id
) {
if (!notification.includes(newMessageRecieved)) {
setNotification([newMessageRecieved, ...notification]);
setFetchAgain(!fetchAgain);
}
} else {
setMessages([...messages, newMessageRecieved]);
}
});
});
return (
<>
<video ref={userVideoRef} autoPlay muted></video>
<video ref={remoteVideoRef} autoPlay></video>

<IconButton
icon={<PhoneIcon />}
onClick={initiateCall}
position="absolute"
top="20px"
right="20px"
zIndex="9999"
isDisabled={calling || !selectedChat}
/>

{calling && (
<Box position="absolute" bottom="20px" left="50%"
transform="translateX(-50%)">
<button onClick={acceptCall} style={{ marginRight: "10px",
backgroundColor: "green", color: "white", padding: "10px 20px", border: "none",
borderRadius: "5px" }}>Accept</button>
<button onClick={rejectCall} style={{ backgroundColor: "red", color:
"white", padding: "10px 20px", border: "none", borderRadius:
"5px" }}>Reject</button>
</Box>
)}
{selectedChat ? (
<>
<Text
fontSize={{ base: "18px", md: "20px" }}
pb={3}
px={2}
w="100%"
fontFamily="Work sans"
display="flex"
justifyContent={{ base: "space-between" }}
alignItems="center"
>
<IconButton
display={{ base: "flex", md: "none" }}
icon={<ArrowBackIcon />}
onClick={() => setSelectedChat("")}
/>

{!selectedChat.isGroupChat ? (
<>
{getSender(user, selectedChat.users)}
<ProfileModal user={getSenderFull(user, selectedChat.users)} />
</>
) : (
<>
{'# '}{selectedChat.chatName}
<UpdateGroupChatModal
fetchMessages={fetchMessages}
fetchAgain={fetchAgain}
setFetchAgain={setFetchAgain}
/>
</>
)}
</Text>

<Box
display="flex"
flexDir="column"
justifyContent="flex-end"
p={3}
bg="#E8E8E8"
w="100%"
h="100%"
borderRadius="lg"
overflowY="hidden"
>
{loading ? (
<Spinner
size="xl"
w={20}
h={20}
alignSelf="center"
margin="auto"
/>
) : (
<div className="messages">
<ScrollableChat messages={messages} />
</div>
)}

<FormControl
onKeyDown={sendMessage}
id="first-name"
isRequired
mt={3}
>
{istyping ? (
<div>
<Lottie
options={defaultOptions}
width={70}
style={{ marginBottom: 15, marginLeft: 0 }}
/>
typing...
</div>
) : (
<></>
)}
<Flex direction="row" align="center">
<label htmlFor="file-upload" style={{ cursor: 'pointer',
marginRight: '10px' }}>
<i className="fas fa-paperclip"></i>
</label>
<input
id="file-upload"
type="file"
accept="image/png,image/jpeg,video/mp4"
style={{ display: 'none' }}
onChange={handleFileChange}
/>

<Input
variant="filled"
bg="#E0E0E0"
placeholder="Enter a message.."
value={newMessage}
onChange={typingHandler}
flex="1"
isDisabled={isUploading}
/>

</Flex>
{selectedFile &&
<Box ml={2} mt={2}>

<span>File Attached: </span> <span>{selectedFile.name}</span>


</Box>
}
{isUploading &&
<Box>
<Progress value={uploadProgress}
isIndeterminate={uploadProgress === 0} />
<Alert status="info">
<AlertIcon />
File is uploading...
</Alert>
</Box>
}
</FormControl>
</Box>
</>
) : (
<Box display="flex" alignItems="center" justifyContent="center" h="100%"
gap={2}>
<ChatIcon boxSize="3em" /> {/* Adjust size as needed */}
<Text fontSize="3xl" pb={3} fontFamily="Work sans" fontWeight={600}>
Start chatting on Vibex.
</Text>
</Box>
)}
</>
);
};

export default SingleChat;

backend:

const dotenv = require("dotenv")


dotenv.config();
const express = require("express");
const connectDB = require("./config/db");

// const {chats}= require("./data/data");

const usesrRoutes = require("./routes/userRoutes");


const chatRoutes = require("./routes/chatRoutes");
const messageRoutes = require("./routes/messageRoutes");
// const colors=require("colors");
const { notFound, errorHandler } = require("./middleware/errorMiddleware");
// const { Socket } = require("socket.io");

console.log(process.env.MONGO_URI);
connectDB();

const app = express();


app.use(express.json());

app.use("/api/user", usesrRoutes);
app.use("/api/chat", chatRoutes);
app.use("/api/message", messageRoutes);

//////////////////////////////////////////////////////

const path = require("path");

const __dirname1 = path.resolve();

if (process.env.NODE_ENV === "production") {


app.use(express.static(path.join(__dirname1, "/frontend/build")));

app.get("*", (req, res) =>


res.sendFile(path.resolve(__dirname1, "frontend", "build", "index.html"))
);
} else {
app.get("/", (req, res) => {
res.send("API is running..");
});
}

//////////////////////////////////////////////////////

app.use(notFound);
app.use(errorHandler);

const PORT = process.env.PORT || 5000;


const server = app.listen(PORT, console.log(`server started on PORT ${PORT}`));

const io = require("socket.io")(server, {
pingTimeout: 60000,
cors: {
origin: "http://192.168.18.213:3000"
// credentials: true,
},
});

io.on("connection", (socket) => {


console.log("Connected to socket.io");

socket.on("setup", (userData) => {


socket.join(userData._id);
socket.emit("connected");
});
socket.on("call", ({ recipientId }) => {
// Emit incoming call event to the recipient
io.to(recipientId).emit("incomingCall");
});

socket.on("answer", ({ callerId, answer }) => {


// Forward answer to the caller
io.to(callerId).emit("answer", { answer });
});
socket.on("join chat", (room) => {
socket.join(room);
// console.log("User Joined Room: " + room);
});

socket.on("new message", (newMessageRecieved) => {


var chat = newMessageRecieved.chat;

if (!chat.users) return console.log("chat.users not defined");

chat.users.forEach((user) => {
if (user._id == newMessageRecieved.sender._id) return;

socket.in(user._id).emit("message recieved", newMessageRecieved);


});
});

socket.on("typing", (room) => socket.in(room).emit("typing"));


socket.on("stop typing", (room) => socket.in(room).emit("stop typing"));

socket.off("setup", () => {
console.log("USER DISCONNECTED");
socket.leave(userData._id);
});
});
please add the video, audio call feature in my chat App in easiest way possible like we can use
zego cloud call api:
frontend:
import { FormControl } from "@chakra-ui/form-control";
import { Input } from "@chakra-ui/input";
import { Box, Text } from "@chakra-ui/layout";
import { Flex } from "@chakra-ui/layout";
import { Alert, AlertIcon } from "@chakra-ui/react";
import "./styles.css";
import { IconButton, Spinner, useToast } from "@chakra-ui/react";
import { getSender, getSenderFull } from "../config/ChatLogics";
import { useEffect, useState } from "react";
import axios from "axios";
import { ArrowBackIcon } from "@chakra-ui/icons";
import ProfileModal from "./miscellaneous/ProfileModal";
import { ChatState } from "../Context/ChatProvider";
import UpdateGroupChatModal from "./miscellaneous/UpdateGroupChatModal";
import ScrollableChat from "./ScrollableChat";
import io from "socket.io-client";
import Lottie from "react-lottie";
import animationData from "../animations/typing.json";
import { Progress } from "@chakra-ui/react";
import { ChatIcon } from '@chakra-ui/icons';
const ENDPOINT = "http://localhost:5000/";
let socket, selectedChatCompare;

const SingleChat = ({ fetchAgain, setFetchAgain }) => {


const [messages, setMessages] = useState([]);
const [loading, setLoading] = useState(false);
const [newMessage, setNewMessage] = useState("");
const [selectedFile, setSelectedFile] = useState(null);
const [fileUrl, setFileUrl] = useState("");
const [isUploading, setIsUploading] = useState(false);
const [socketConnected, setSocketConnected] = useState(false);
const [typing, setTyping] = useState(false);
const [istyping, setIsTyping] = useState(false);
const [uploadProgress, setUploadProgress] = useState(0);
const toast = useToast();

const { selectedChat, setSelectedChat, user, notification, setNotification } =


ChatState();

const defaultOptions = {
loop: true,
autoplay: true,
animationData: animationData,
rendererSettings: {
preserveAspectRatio: "xMidYMid slice",
},
};

//for socket get initallize first we put this use effect at the top
useEffect(() => {
socket = io(ENDPOINT);
socket.emit("setup", user);
socket.on("connected", () => setSocketConnected(true));
socket.on("typing", () => setIsTyping(true));
socket.on("stop typing", () => setIsTyping(false));
}, []);

const fetchMessages = async () => {


if (!selectedChat) return;

try {
const config = {
headers: {
Authorization: `Bearer ${user.token}`,
},
};

setLoading(true);

const { data } = await axios.get(


`/api/message/${selectedChat._id}`,
config
);
setMessages(data);
setLoading(false);
socket.emit("join chat", selectedChat._id);
} catch (error) {
toast({
title: "Error Occured!",
description: "Failed to Load the Messages",
status: "error",
duration: 5000,
isClosable: true,
position: "bottom",
});
}
};

const typingHandler = (e) => {


setNewMessage(e.target.value);

if (!socketConnected) return;

if (!typing) {
setTyping(true);
socket.emit("typing", selectedChat._id);
}
let lastTypingTime = new Date().getTime();
let timerLength = 3000;
setTimeout(() => {
let timeNow = new Date().getTime();
let timeDiff = timeNow - lastTypingTime;
if (timeDiff >= timerLength && typing) {
socket.emit("stop typing", selectedChat._id);
setTyping(false);
}
}, timerLength);
};
const uploadFile = async (file) => {
const formData = new FormData();
formData.append('file', file);

const config = {
headers: {
'Content-type': 'multipart/form-data',
Authorization: `Bearer ${user.token}`,
},
onUploadProgress: (progressEvent) => {
// Limit the reported progress to 90%
const progress = Math.round((progressEvent.loaded * 90) / progressEvent.total);
setUploadProgress(progress);
},
};

const { data } = await axios.post("/api/message/attachment", formData, config);


return data.fileUrl;
};
const handleFileChange = async (e) => {
const file = e.target.files[0];
const maxSize = 10485760; // 10 MB

if (file && file.size > maxSize) {


alert('File size too large. Maximum is 10 MB.');
return;
}

setIsUploading(true);
if (file) {
setSelectedFile(file);
const fileUrl = await uploadFile(file);
setFileUrl(fileUrl);
//alert('File attached successfully! Press Enter to send the message.');
}
setIsUploading(false);
};
const sendMessage = async (event) => {
if (event.key === "Enter" && (newMessage || fileUrl)) {

try {
const config = {
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${user.token}`,
},
};
setNewMessage("");
setSelectedFile(null);
const { data } = await axios.post(
"/api/message",
{
content: newMessage,
chatId: selectedChat,
fileUrl: fileUrl,
},
config
);
socket.emit("new message", data);
setMessages([...messages, data]);

} catch (error) {
toast({
title: "Error Occured!",
description: "Failed to send the Message",
status: "error",
duration: 5000,
isClosable: true,
position: "bottom",
});
}
}
};

useEffect(() => {
fetchMessages();
selectedChatCompare = selectedChat;
}, [selectedChat]);

useEffect(() => {
socket.on("message recieved", (newMessageRecieved) => {
if (
!selectedChatCompare || // if chat is not selected or doesn't match current chat
selectedChatCompare._id !== newMessageRecieved.chat._id
){
if (!notification.includes(newMessageRecieved)) {
setNotification([newMessageRecieved, ...notification]);
setFetchAgain(!fetchAgain);
}
} else {
setMessages([...messages, newMessageRecieved]);
}
});
});

return (
<>
{selectedChat ? (
<>
<Text
fontSize={{ base: "18px", md: "20px" }}
pb={3}
px={2}
w="100%"
fontFamily="Work sans"
display="flex"
justifyContent={{ base: "space-between" }}
alignItems="center"
>
<IconButton
display={{ base: "flex", md: "none" }}
icon={<ArrowBackIcon />}
onClick={() => setSelectedChat("")}
/>

{!selectedChat.isGroupChat ? (
<>
{getSender(user, selectedChat.users)}
<ProfileModal user={getSenderFull(user, selectedChat.users)} />
</>
):(
<>
{'# '}{selectedChat.chatName}
<UpdateGroupChatModal
fetchMessages={fetchMessages}
fetchAgain={fetchAgain}
setFetchAgain={setFetchAgain}
/>
</>
)}
</Text>
<Box
display="flex"
flexDir="column"
justifyContent="flex-end"
p={3}
bg="#E8E8E8"
w="100%"
h="100%"
borderRadius="lg"
overflowY="hidden"
>
{loading ? (
<Spinner
size="xl"
w={20}
h={20}
alignSelf="center"
margin="auto"
/>
):(
<div className="messages">
<ScrollableChat messages={messages} />
</div>
)}

<FormControl
onKeyDown={sendMessage}
id="first-name"
isRequired
mt={3}
>
{istyping ? (
<div>
<Lottie
options={defaultOptions}
width={70}
style={{ marginBottom: 15, marginLeft: 0 }}
/>
typing...
</div>
):(
<></>
)}
<Flex direction="row" align="center">
<label htmlFor="file-upload" style={{ cursor: 'pointer', marginRight: '10px' }}>
<i className="fas fa-paperclip"></i>
</label>
<input
id="file-upload"
type="file"
accept="image/png,image/jpeg,video/mp4"
style={{ display: 'none' }}
onChange={handleFileChange}
/>

<Input
variant="filled"
bg="#E0E0E0"
placeholder="Enter a message.."
value={newMessage}
onChange={typingHandler}
flex="1"
isDisabled={isUploading}
/>

</Flex>
{selectedFile &&
<Box ml={2} mt={2}>

<span>File Attached: </span> <span>{selectedFile.name}</span>


</Box>
}
{isUploading &&
<Box>
<Progress value={uploadProgress} isIndeterminate={uploadProgress === 0} />
<Alert status="info">
<AlertIcon />
File is uploading...
</Alert>
</Box>
}
</FormControl>
</Box>
</>
):(
<Box display="flex" alignItems="center" justifyContent="center" h="100%" gap={2}>
<ChatIcon boxSize="3em" /> {/* Adjust size as needed */}
<Text fontSize="3xl" pb={3} fontFamily="Work sans" fontWeight={600}>
Start chatting on Vibex.
</Text>
</Box>
)}
</>
);
};

export default SingleChat;

backend:
const dotenv = require("dotenv")
dotenv.config();
const express = require("express");
const connectDB = require("./config/db");

// const {chats}= require("./data/data");


const usesrRoutes = require("./routes/userRoutes");
const chatRoutes = require("./routes/chatRoutes");
const messageRoutes = require("./routes/messageRoutes");

// const colors=require("colors");
const { notFound, errorHandler } = require("./middleware/errorMiddleware");
// const { Socket } = require("socket.io");

console.log(process.env.MONGO_URI);
connectDB();

const app = express();


app.use(express.json());

app.use("/api/user", usesrRoutes);
app.use("/api/chat", chatRoutes);
app.use("/api/message", messageRoutes);

//////////////////////////////////////////////////////

const path = require("path");

const __dirname1 = path.resolve();

if (process.env.NODE_ENV === "production") {


app.use(express.static(path.join(__dirname1, "/frontend/build")));

app.get("*", (req, res) =>


res.sendFile(path.resolve(__dirname1, "frontend", "build", "index.html"))
);
} else {
app.get("/", (req, res) => {
res.send("API is running..");
});
}

//////////////////////////////////////////////////////

app.use(notFound);
app.use(errorHandler);

const PORT = process.env.PORT || 5000;


const server = app.listen(PORT, console.log(`server started on PORT ${PORT}`));

const io = require("socket.io")(server, {
pingTimeout: 60000,
cors: {
origin: "http://localhost:3000"
// credentials: true,
},
});
io.on("connection", (socket) => {
console.log("Connected to socket.io");

socket.on("setup", (userData) => {


socket.join(userData._id);
socket.emit("connected");
});

socket.on("join chat", (room) => {


socket.join(room);
// console.log("User Joined Room: " + room);
});

socket.on("new message", (newMessageRecieved) => {


var chat = newMessageRecieved.chat;

if (!chat.users) return console.log("chat.users not defined");

chat.users.forEach((user) => {
if (user._id == newMessageRecieved.sender._id) return;

socket.in(user._id).emit("message recieved", newMessageRecieved);


});
});

socket.on("typing", (room) => socket.in(room).emit("typing"));


socket.on("stop typing", (room) => socket.in(room).emit("stop typing"));
socket.off("setup", () => {
console.log("USER DISCONNECTED");
socket.leave(userData._id);
});
});

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy