Commit 63618602 authored by 이재연's avatar 이재연
Browse files

Merge remote-tracking branch 'origin/seoyeon2' into jaeyeoniiiiii

parents e72932e2 3aa0a668
// express 설정 파일 // express 설정 파일
import express from "express"; import express from "express";
import fs from "fs"; import cors from "cors";
import socketio from "socket.io";
import http from "http";
import wrtc from "wrtc";
import cookieParser from "cookie-parser"; import cookieParser from "cookie-parser";
import mainRouter from "./routes/index.js"; import mainRouter from "./routes/index.js";
const app = express(); const app = express();
app.use(cors());
const server = http.createServer(app);
app.use(express.json()); app.use(express.json());
// app.use('/uploads', express.static('uploads'))
app.use(express.urlencoded({ extended: true })); app.use(express.urlencoded({ extended: true }));
app.use(cookieParser()); app.use(cookieParser());
app.use("/api", mainRouter); app.use("/api", mainRouter);
export default app; let receiverPCs = {};
let senderPCs = {};
let users = {};
let socketToRoom = {};
const pc_config = {
iceServers: [
// {
// urls: 'stun:[STUN_IP]:[PORT]',
// 'credentials': '[YOR CREDENTIALS]',
// 'username': '[USERNAME]'
// },
{
urls: "stun:stun.l.google.com:19302",
},
],
};
const isIncluded = (array, id) => {
let len = array.length;
for (let i = 0; i < len; i++) {
if (array[i].id === id) return true;
}
return false;
};
const createReceiverPeerConnection = (socketID, socket, roomID) => {
let pc = new wrtc.RTCPeerConnection(pc_config);
if (receiverPCs[socketID]) receiverPCs[socketID] = pc;
else receiverPCs = { ...receiverPCs, [socketID]: pc };
pc.onicecandidate = (e) => {
//console.log(`socketID: ${socketID}'s receiverPeerConnection icecandidate`);
socket.to(socketID).emit("getSenderCandidate", {
candidate: e.candidate,
});
};
pc.oniceconnectionstatechange = (e) => {
//console.log(e);
};
pc.ontrack = (e) => {
if (users[roomID]) {
if (!isIncluded(users[roomID], socketID)) {
users[roomID].push({
id: socketID,
stream: e.streams[0],
});
} else return;
} else {
users[roomID] = [
{
id: socketID,
stream: e.streams[0],
},
];
}
socket.broadcast.to(roomID).emit("userEnter", { id: socketID });
};
return pc;
};
const createSenderPeerConnection = (
receiverSocketID,
senderSocketID,
socket,
roomID
) => {
let pc = new wrtc.RTCPeerConnection(pc_config);
if (senderPCs[senderSocketID]) {
senderPCs[senderSocketID].filter((user) => user.id !== receiverSocketID);
senderPCs[senderSocketID].push({ id: receiverSocketID, pc: pc });
} else
senderPCs = {
...senderPCs,
[senderSocketID]: [{ id: receiverSocketID, pc: pc }],
};
pc.onicecandidate = (e) => {
//console.log(`socketID: ${receiverSocketID}'s senderPeerConnection icecandidate`);
socket.to(receiverSocketID).emit("getReceiverCandidate", {
id: senderSocketID,
candidate: e.candidate,
});
};
pc.oniceconnectionstatechange = (e) => {
//console.log(e);
};
const sendUser = users[roomID].filter((user) => user.id === senderSocketID);
sendUser[0].stream.getTracks().forEach((track) => {
pc.addTrack(track, sendUser[0].stream);
});
return pc;
};
const getOtherUsersInRoom = (socketID, roomID) => {
let allUsers = [];
if (!users[roomID]) return allUsers;
let len = users[roomID].length;
for (let i = 0; i < len; i++) {
if (users[roomID][i].id === socketID) continue;
allUsers.push({ id: users[roomID][i].id });
}
return allUsers;
};
const deleteUser = (socketID, roomID) => {
let roomUsers = users[roomID];
if (!roomUsers) return;
roomUsers = roomUsers.filter((user) => user.id !== socketID);
users[roomID] = roomUsers;
if (roomUsers.length === 0) {
delete users[roomID];
}
delete socketToRoom[socketID];
};
const closeRecevierPC = (socketID) => {
if (!receiverPCs[socketID]) return;
receiverPCs[socketID].close();
delete receiverPCs[socketID];
};
const closeSenderPCs = (socketID) => {
if (!senderPCs[socketID]) return;
let len = senderPCs[socketID].length;
for (let i = 0; i < len; i++) {
senderPCs[socketID][i].pc.close();
let _senderPCs = senderPCs[senderPCs[socketID][i].id];
let senderPC = _senderPCs.filter((sPC) => sPC.id === socketID);
if (senderPC[0]) {
senderPC[0].pc.close();
senderPCs[senderPCs[socketID][i].id] = _senderPCs.filter(
(sPC) => sPC.id !== socketID
);
}
}
delete senderPCs[socketID];
};
const io = socketio.listen(server);
io.sockets.on("connection", (socket) => {
console.log("socket connection complete")
socket.on("joinRoom", (data) => {
try {
let allUsers = getOtherUsersInRoom(data.id, data.roomID);
io.to(data.id).emit("allUsers", { users: allUsers });
} catch (error) {
console.log(error);
}
});
socket.on("senderOffer", async (data) => {
try {
socketToRoom[data.senderSocketID] = data.roomID;
let pc = createReceiverPeerConnection(
data.senderSocketID,
socket,
data.roomID
);
await pc.setRemoteDescription(data.sdp);
let sdp = await pc.createAnswer({
offerToReceiveAudio: true,
offerToReceiveVideo: true,
});
await pc.setLocalDescription(sdp);
socket.join(data.roomID);
io.to(data.senderSocketID).emit("getSenderAnswer", { sdp });
} catch (error) {
console.log(error);
}
});
socket.on("senderCandidate", async (data) => {
try {
let pc = receiverPCs[data.senderSocketID];
await pc.addIceCandidate(new wrtc.RTCIceCandidate(data.candidate));
} catch (error) {
console.log(error);
}
});
socket.on("receiverOffer", async (data) => {
try {
let pc = createSenderPeerConnection(
data.receiverSocketID,
data.senderSocketID,
socket,
data.roomID
);
await pc.setRemoteDescription(data.sdp);
let sdp = await pc.createAnswer({
offerToReceiveAudio: false,
offerToReceiveVideo: false,
});
await pc.setLocalDescription(sdp);
io.to(data.receiverSocketID).emit("getReceiverAnswer", {
id: data.senderSocketID,
sdp,
});
} catch (error) {
console.log(error);
}
});
socket.on("receiverCandidate", async (data) => {
try {
const senderPC = senderPCs[data.senderSocketID].filter(
(sPC) => sPC.id === data.receiverSocketID
);
await senderPC[0].pc.addIceCandidate(
new wrtc.RTCIceCandidate(data.candidate)
);
} catch (error) {
console.log(error);
}
});
socket.on("disconnect", () => {
try {
let roomID = socketToRoom[socket.id];
deleteUser(socket.id, roomID);
closeRecevierPC(socket.id);
closeSenderPCs(socket.id);
socket.broadcast.to(roomID).emit("userExit", { id: socket.id });
} catch (error) {
console.log(error);
}
});
});
export default server;
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",
"axios": "^0.21.1", "axios": "^0.21.1",
"bootstrap": "^5.0.2", "bootstrap": "^5.0.2",
"nanoid": "^3.1.23",
"node-sass": "^6.0.1", "node-sass": "^6.0.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
...@@ -23,6 +24,9 @@ ...@@ -23,6 +24,9 @@
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject" "eject": "react-scripts eject"
}, },
"nodemonConfig":{
"ignore":["test/*","docs/*","client/*"]
},
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [
"react-app", "react-app",
......
import axios from "axios"; import axios from "axios";
const login = async (payload) => { const create = async (payload) => {
const { data } = await axios.post("/api/login", payload); const { data } = await axios.post("/api/room/create", payload);
return data; return data;
}; };
const signup = async (payload) => { const join = async (payload) => {
const { data } = await axios.post("/api/signup", payload); const { data } = await axios.put("/api/room/join", payload);
return data; return data;
}; };
const roomApi = { login, signup }; const roomApi = { create, join };
export default roomApi; export default roomApi;
import axios from "axios"; import axios from "axios";
const getUser = async (payload) => {
const { data } = await axios.post("/api/getUser", payload);
return data;
};
const login = async (payload) => { const login = async (payload) => {
const { data } = await axios.post("/api/login", payload); const { data } = await axios.post("/api/login", payload);
return data; return data;
......
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { handleLogout } from '../context/auth'
const Header = () => { const Header = () => {
return ( return (
<div> <div>
...@@ -6,11 +8,71 @@ const Header = () => { ...@@ -6,11 +8,71 @@ const Header = () => {
style={{ backgroundColor: '#FCF4FF' }} style={{ backgroundColor: '#FCF4FF' }}
className="flex-column align-items-center justify-content-center p-2" className="flex-column align-items-center justify-content-center p-2"
> >
<div className="d-flex justify-content-center"> <div className="d-flex justify-content-end">
<Link to="/"> <div>
<Link to="/user">
<img src="/BORA.png" style={{ width: '160px' }} /> <img src="/BORA.png" style={{ width: '160px' }} />
</Link> </Link>
</div> </div>
<button
type="button"
className=" mt-3 ms-5 rounded"
data-bs-toggle="modal"
data-bs-target="#logout"
style={{
height: '30px',
backgroundColor: '#E0CEE8',
color: 'black',
border: '1px #E0CEE8',
}}
>
로그아웃
</button>
<div
className="modal fade"
id="logout"
tabIndex="-1"
aria-labelledby="logoutLabel"
aria-hidden="true"
>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div className="modal-body d-flex justify-content-center">
로그아웃 하시겠습니까?
</div>
<div className="row mb-3">
<div className="d-flex justify-content-evenly">
<Link to="/" className="col-2 p-1 btn btn-primary">
<button
type="submit"
className="btn btn-primary"
onClick={() => handleLogout()}
data-bs-dismiss="modal"
>
</button>
</Link>
<button
type="submit"
className="col-2 p-1 btn btn-primary"
data-bs-dismiss="modal"
>
아니요
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form> </form>
<div <div
style={{ backgroundColor: '#262626', width: 'auto', height: '2px' }} style={{ backgroundColor: '#262626', width: 'auto', height: '2px' }}
......
import { useEffect, useState } from "react"; import CreateRoom from "./CreateRoom";
import axios from 'axios' import JoinRoom from "./JoinRoom";
const INIT_ROOM = {
roomName: '',
owner: '123456',
member: '123456',
profileimg: [],
}
const AddRoom = () => { const AddRoom = () => {
const [room, setRoom] = useState(INIT_ROOM)
const [error, setError] = useState("");
const [success, setSuccess] = useState(false)
const [disabled, setDisabled] = useState(true)
useEffect(() => {
setDisabled(
!(
room.name &&
room.owner &&
room.member &&
room.profileimg
)
);
}, [room]);
//LocalStorage에 user id를 저장할때 id를 owner, member에 저장하기
//const userId = localStorage.getItem('id')
// setRoom({...room, [owner]: userId})
// setRoom({...room, [member]: userId})
function handleChange(event) {
const { name, value } = event.target
setRoom({ ...room, [name]: value })
console.log(room)
}
async function handleSubmit(event) {
event.preventDefault()
try {
console.log('룸룸', room)
let res = await axios.post("/room/create", room)
const Id = res.data.id
alert(`방참여코드는 ${Id}입니다`)
setSuccess(true)
} catch (error) {
// catchErrors(error, setError);
} finally {
// setLoading(false);
}
}
if (success) {
console.log('success', success)
alert('룸생성이 완료되었습니다!')
//return <Redirect to='/' />
}
const { name, owner, member, profileimg } = room;
return ( return (
<div> <div>
<div className="mx-4 my-3 d-flex justify-content-between"> <div className="mx-4 my-3 d-flex justify-content-between">
...@@ -102,6 +45,7 @@ const AddRoom = () => { ...@@ -102,6 +45,7 @@ const AddRoom = () => {
className="p-3" className="p-3"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#joinModal" data-bs-target="#joinModal"
// data-bs-dismiss="modal"
style={{ style={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
...@@ -110,11 +54,19 @@ const AddRoom = () => { ...@@ -110,11 +54,19 @@ const AddRoom = () => {
backgroundColor: "#E0CEE8", backgroundColor: "#E0CEE8",
borderColor: "#E0CEE8", borderColor: "#E0CEE8",
}} }}
>방참여하기
</button>
<div
className="modal fade"
id="joinModal"
tabIndex="-1"
aria-labelledby="joinModalLabel"
aria-hidden="true"
> >
<div style={{ width: "6rem" }} > <div className="modal-dialog">
방참여하기 <JoinRoom />
</div>
</div> </div>
</button>
</div> </div>
<div className="col-6 d-flex justify-content-center"> <div className="col-6 d-flex justify-content-center">
<button <button
...@@ -122,6 +74,7 @@ const AddRoom = () => { ...@@ -122,6 +74,7 @@ const AddRoom = () => {
className="p-3" className="p-3"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#makeModal" data-bs-target="#makeModal"
// data-bs-dismiss="modal"
style={{ style={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
...@@ -130,95 +83,19 @@ const AddRoom = () => { ...@@ -130,95 +83,19 @@ const AddRoom = () => {
backgroundColor: "#f5cfe3", backgroundColor: "#f5cfe3",
borderColor: "#f5cfe3", borderColor: "#f5cfe3",
}} }}
> >방생성하기
<div style={{ width: "6rem" }} >
방생성하기
</div>
</button> </button>
</div> <div
</div> className="modal fade"
</div> id="makeModal"
</div> tabIndex="-1"
</div> aria-labelledby="makeModalLabel"
</div> aria-hidden="true"
>
{/* 방참여하기 모달 */}
<div className="form" onSubmit={handleSubmit}>
<div className="modal" id="joinModal" tabIndex="-1" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<div>방참여하기</div>
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div className="modal-body">
<div className="input-group mb-3">
<input
type="text"
className="form-control"
placeholder="참여코드를 입력하세요"
aria-label="참여코드를 입력하세요"
aria-describedby="basic-addon1"
/>
</div>
<div className="modal-footer">
<button type="submit" className="btn btn-primary">
확인
</button>
</div>
</div>
</div>
</div>
</div>
</div>
{/* 방생성하기 모달 */}
<div className="form" onSubmit={handleSubmit}>
<div className="modal" id="makeModal" tabIndex="-1" aria-hidden="true">
<div className="modal-dialog"> <div className="modal-dialog">
<div className="modal-content"> <CreateRoom />
<div className="modal-header">
<div>방생성하기</div>
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div> </div>
<div className="modal-body">
<h6>방프로필사진</h6>
<div className="mb-4">
<input
type="file"
className="upload-hidden"
onChange={handleChange}
name="profileimg"
value={room.profileimg} />
</div>
<h6>방이름</h6>
<div className="input-group">
<input
type="text"
className="form-control"
placeholder="방이름을 입력해주세요"
aria-label="방이름 입력해주세요"
aria-describedby="basic-addon1"
onChange={handleChange}
name="name"
value={room.name}
/>
</div> </div>
<div className="modal-footer">
<button type="submit" className="btn btn-primary">
생성
</button>
</div> </div>
</div> </div>
</div> </div>
......
import { useEffect, useState } from "react";
import { Redirect } from "react-router-dom";
import roomApi from "../../apis/room.api";
const userId = localStorage.getItem('user');
console.log(userId)
const INIT_ROOM = {
name: '',
owner: userId,
member: userId,
profileimg: '',
}
const CreateRoom = () => {
const [room, setRoom] = useState(INIT_ROOM)
const [error, setError] = useState("");
const [success, setSuccess] = useState(false)
const [disabled, setDisabled] = useState(true)
useEffect(() => {
const isRoom = Object.values(roomApi).every((el) => Boolean(el));
isRoom ? setDisabled(false) : setDisabled(true);
}, [room]);
function handleChange(event) {
console.log(room)
const { name, value } = event.target
setRoom({ ...room, [name]: value })
}
console.log(room)
async function handleSubmit(e) {
e.preventDefault()
console.log('룸룸', room)
try {
const res = await roomApi.create(room)
// console.log(res)
const Id = res.id
console.log(Id)
alert(`방참여코드는 ${Id}입니다`)
setSuccess(true)
} catch (error) {
// catchErrors(error, setError);
} finally {
// setLoading(false);
}
}
if (success) {
console.log('success', success)
alert('룸생성이 완료되었습니다!')
return <Redirect to='/user' />
}
const { name, owner, member, profileimg } = room;
return (
<div className="modal-content" >
<form onSubmit={handleSubmit}>
<div className="modal-header">
<div className="modal-title" id="makeModal">방생성하기</div>
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div className="modal-body">
<h6>방프로필사진</h6>
<div className="mb-4">
<input
type="file"
className="upload-hidden"
onChange={handleChange}
accept="image/*"
name="profileimg"
value={room.profileimg} />
</div>
<h6>방이름</h6>
<div className="input-group">
<input
type="text"
className="form-control"
placeholder="방이름을 입력해주세요"
aria-label="방이름 입력해주세요"
aria-describedby="basic-addon1"
onChange={handleChange}
name="name"
value={room.name}
/>
</div>
<div className="modal-footer">
<button type="submit" className="btn btn-primary">
생성
</button>
</div>
</div>
</form>
</div >
);
};
export default CreateRoom;
\ No newline at end of file
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useState, useEffect } from "react";
import userApi from "../../apis/user.api";
const userprofile = localStorage.getItem("user");
console.log(userprofile)
const INIT_USER = {
id: userprofile,
name: '',
img: '',
}
const HomeProfile = () => { const HomeProfile = () => {
const id = 1; const [user, setUser] = useState(INIT_USER)
async function getSetUser(userID) {
try {
// `/users/${userId}`랑 userId랑 같은지 확인
console.log('userID',userID)
const data = await userApi.getUser({id: userID})
console.log(data)
setUser(data)
console.log(user)
} catch (error) {
// catchErrors(error, setError)
}
}
useEffect(() => {
console.log('예에에에에ㅔ에에')
getSetUser(userprofile)
}, [userprofile])
return ( return (
<Link to={`/profile/${id}`} className="text-decoration-none text-dark"> <Link to={`/profile/${user}`} className="text-decoration-none text-dark">
<form className="flex-column align-items-center justify-content-center m-2"> <form className="flex-column align-items-center justify-content-center m-2">
<div className="d-flex justify-content-center"> <div className="d-flex justify-content-center">
<img <img
src="cherry.jpg" // src="cherry.jpg"
className="rounded-circle" className="rounded-circle"
style={{ style={{
width: "157px", width: "157px",
height: "157px", height: "157px",
}} }}
value={user.img}
/> />
</div> </div>
<h1 className="d-flex justify-content-center"> CHERRY </h1> <h1 className="d-flex justify-content-center"> {user.name} </h1>
<h2 className="d-flex justify-content-center"> #0805 </h2> <h2 className="d-flex justify-content-center"> #{user.id} </h2>
</form> </form>
<div <div
style={{ backgroundColor: "#262626", width: "auto", height: "2px" }} style={{ backgroundColor: "#262626", width: "auto", height: "2px" }}
......
import { useEffect, useState } from "react";
import { Redirect } from "react-router-dom";
import roomApi from "../../apis/room.api";
const userId = localStorage.getItem('user');
const JoinRoom = () => {
const [roomId, setRoomId] = useState('');
const [disabled, setDisabled] = useState(true);
const [error, setError] = useState("");
const [success, setSuccess] = useState(false);
useEffect(() => {
const isRoom = Object.values(roomApi).every((el) => Boolean(el));
isRoom ? setDisabled(false) : setDisabled(true);
}, [roomId]);
function handleChange(event) {
const { value } = event.target;
setRoomId(value);
console.log(roomId);
}
async function handleSubmit(e) {
e.preventDefault();
try {
// setLoading(true);
// setError("");
console.log('userId:', userId)
console.log('roomId:', roomId)
const data = await roomApi.join({ userId: userId, roomId: roomId });
console.log(data);
setSuccess(true);
} catch (error) {
// catchErrors(error, setError);
} finally {
// setLoading(false);
}
}
if (success) {
return <Redirect to="/user" />;
}
return (
<div className="modal-content">
<form onSubmit={handleSubmit}>
<div className="modal-header">
<div className="modal-title" id="joinModal">방참여하기</div>
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div className="modal-body">
<div className="input-group mb-3">
<input
type="text"
className="form-control"
placeholder="참여코드를 입력하세요"
aria-label="참여코드를 입력하세요"
aria-describedby="basic-addon1"
name="roomId"
value={roomId}
onChange={handleChange}
/>
</div>
<div className="modal-footer">
<button type="submit" className="btn btn-primary">
확인
</button>
</div>
</div>
</form>
</div>
);
};
export default JoinRoom;
\ No newline at end of file
import { useEffect, useState } from "react"; import { useEffect, useState } from 'react'
import { Redirect } from "react-router-dom"; import { Redirect } from 'react-router-dom'
import userApi from "../apis/user.api"; import userApi from '../apis/user.api'
import catchErrors from "../context/catchError";
import { handleLogin } from '../context/auth';
const INIT_USER = { const INIT_USER = {
email: "", email: '',
password: "", password: '',
}; }
const Login = () => { const Login = () => {
// const { error, loading, login } = useAuth(); // const { loading, login, catchErrorAuth } = useAuth()
const [user, setUser] = useState(INIT_USER); const [user, setUser] = useState(INIT_USER)
const [disabled, setDisabled] = useState(true); const [disabled, setDisabled] = useState(true)
const [error, setError] = useState(""); const [error, setError] = useState('')
const [success, setSuccess] = useState(false); const [success, setSuccess] = useState(false)
useEffect(() => { useEffect(() => {
const isUser = Object.values(user).every((el) => Boolean(el)); const isUser = Object.values(user).every((el) => Boolean(el))
isUser ? setDisabled(false) : setDisabled(true); isUser ? setDisabled(false) : setDisabled(true)
}, [user]); }, [user])
function handleChange(event) { function handleChange(event) {
const { name, value } = event.target; const { name, value } = event.target
setUser({ ...user, [name]: value }); setUser({ ...user, [name]: value })
} }
async function handleSubmit(e) { async function handleSubmit(e) {
e.preventDefault(); e.preventDefault()
console.log('로그인')
try { try {
// setLoading(true); // setLoading(true);
// setError(""); // setError("");
const data = await userApi.login(user); const data = await userApi.login(user)
console.log(data); console.log(data)
setSuccess(true); handleLogin(data.id)
setSuccess(true)
} catch (error) { } catch (error) {
// catchErrors(error, setError); console.log('error in login', error)
catchErrors(error, setError)
} finally { } finally {
// setLoading(false); // setLoading(false);
} }
} }
if (success) {
return <Redirect to="/user" />;
}
if (success) { if (success) {
alert('로그인 되었습니다') alert('로그인 되었습니다')
return <Redirect to="/user" />
} }
const { email, password } = user; const { email, password } = user
return ( return (
<div className="modal-content"> <div className="modal-content">
{error && <div className="alert alert-danger">{error}</div>}
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className="modal-header"> <div className="modal-header">
<h5 className="modal-title" id="loginModalLabel"> <h5 className="modal-title" id="loginModalLabel">
...@@ -88,13 +91,18 @@ const Login = () => { ...@@ -88,13 +91,18 @@ const Login = () => {
</div> </div>
</div> </div>
<div className="modal-footer"> <div className="modal-footer">
<button type="submit" className="btn btn-primary" disabled={disabled}> <button
type="submit"
className="btn btn-primary"
disabled={disabled}
data-bs-dismiss="modal"
>
로그인 로그인
</button> </button>
</div> </div>
</form> </form>
</div> </div>
); )
}; }
export default Login; export default Login
...@@ -44,7 +44,7 @@ const InfoUpdate = () => { ...@@ -44,7 +44,7 @@ const InfoUpdate = () => {
type="button" type="button"
className="btn btn-outline-white " className="btn btn-outline-white "
style={{ style={{
background: "#E8B7FF", background: "#d4cafb",
fontSize: "13px", fontSize: "13px",
fontWeight: "bold", fontWeight: "bold",
}} }}
...@@ -105,7 +105,7 @@ const InfoUpdate = () => { ...@@ -105,7 +105,7 @@ const InfoUpdate = () => {
borderRight: "0", borderRight: "0",
borderLeft: "0", borderLeft: "0",
borderBottom: "1", borderBottom: "1",
borderColor: "#E8B7FF", borderColor: "#d4cafb",
height: "38px", height: "38px",
width: "130px", width: "130px",
}} }}
...@@ -139,7 +139,7 @@ const InfoUpdate = () => { ...@@ -139,7 +139,7 @@ const InfoUpdate = () => {
type="button" type="button"
className="btn btn-outline-white ms-2" className="btn btn-outline-white ms-2"
style={{ style={{
background: "#E8B7FF", background: "#d4cafb",
fontSize: "13px", fontSize: "13px",
fontWeight: "bold", fontWeight: "bold",
}} }}
......
...@@ -18,7 +18,7 @@ const Profile = () => { ...@@ -18,7 +18,7 @@ const Profile = () => {
type="button" type="button"
className="btn btn-outline-white " className="btn btn-outline-white "
style={{ style={{
background: "#E8B7FF", background: "#d4cafb",
fontSize: "13px", fontSize: "13px",
fontWeight: "bold", fontWeight: "bold",
}} }}
......
...@@ -62,9 +62,9 @@ const RightHamberger = () => { ...@@ -62,9 +62,9 @@ const RightHamberger = () => {
style={{ style={{
height: '30px', height: '30px',
fontWeight: 'bold', fontWeight: 'bold',
backgroundColor: '#D64D61', backgroundColor: '#d86da6',
color: 'black', color: 'black',
border: '1px #D64D61', border: '1px #d86da6',
}} }}
> >
퇴장 퇴장
......
import React, { useState } from "react";
import io from "socket.io-client";
import { useRef } from "react";
import { useEffect } from "react";
import Video from "./Video";
import { useParams } from "react-router-dom";
const Screen = () => { const Screen = () => {
const user = '00' const [socket, setSocket] = useState(null);
const [users, setUsers] = useState([]);
const { roomId, channelId } = useParams();
const user = "00";
let localVideoRef = useRef(null);
let sendPC;
let receivePCs;
// 방화벽 등의 보호장치를 거쳐 ip로 연결하기 위한 설정
const pc_config = {
iceServers: [
// {
// urls: 'stun:[STUN_IP]:[PORT]',
// 'credentials': '[YOR CREDENTIALS]',
// 'username': '[USERNAME]'
// },
{
urls: "stun:stun.l.google.com:19302",
},
],
};
useEffect(() => {
let newSocket = io.connect("http://localhost:8080");
let localStream;
// console.log("newSocket", newSocket.id);
//
newSocket.on("userEnter", (data) => {
console.log(data);
createReceivePC(data.id, newSocket);
});
newSocket.on("allUsers", (data) => {
let len = data.users.length;
for (let i = 0; i < len; i++) {
createReceivePC(data.users[i].id, newSocket);
}
});
newSocket.on("userExit", (data) => {
receivePCs[data.id].close();
delete receivePCs[data.id];
setUsers((users) => users.filter((user) => user.id !== data.id));
});
newSocket.on("getSenderAnswer", async (data) => {
try {
console.log("get sender answer");
console.log(data.sdp);
await sendPC.setRemoteDescription(new RTCSessionDescription(data.sdp));
} catch (error) {
console.log(error);
}
});
newSocket.on("getSenderCandidate", async (data) => {
try {
console.log("get sender candidate");
if (!data.candidate) return;
sendPC.addIceCandidate(new RTCIceCandidate(data.candidate));
console.log("candidate add success");
} catch (error) {
console.log(error);
}
});
newSocket.on("getReceiverAnswer", async (data) => {
try {
console.log(`get socketID(${data.id})'s answer`);
let pc = receivePCs[data.id];
await pc.setRemoteDescription(data.sdp);
console.log(`socketID(${data.id})'s set remote sdp success`);
} catch (error) {
console.log(error);
}
});
newSocket.on("getReceiverCandidate", async (data) => {
try {
console.log(data);
console.log(`get socketID(${data.id})'s candidate`);
let pc = receivePCs[data.id];
if (!data.candidate) return;
pc.addIceCandidate(new RTCIceCandidate(data.candidate));
console.log(`socketID(${data.id})'s candidate add success`);
} catch (error) {
console.log(error);
}
});
setSocket(newSocket);
navigator.mediaDevices
.getUserMedia({
audio: true,
video: {
width: 375,
height: 260,
},
})
.then((stream) => {
if (localVideoRef.current) localVideoRef.current.srcObject = stream;
localStream = stream;
sendPC = createSenderPeerConnection(newSocket, localStream);
createSenderOffer(newSocket);
newSocket.emit("joinRoom", {
id: newSocket.id,
roomID: roomId,
});
})
.catch((error) => {
console.log(`getUserMedia error: ${error}`);
});
}, []);
const createReceivePC = (id, newSocket) => {
try {
console.log(`socketID(${id}) user entered`);
let pc = createReceiverPeerConnection(id, newSocket);
createReceiverOffer(pc, newSocket, id);
} catch (error) {
console.log(error);
}
};
const createSenderOffer = async (newSocket) => {
try {
let sdp = await sendPC.createOffer({
offerToReceiveAudio: false,
offerToReceiveVideo: false,
});
console.log("create sender offer success");
await sendPC.setLocalDescription(new RTCSessionDescription(sdp));
console.log(sdp, "", newSocket.id, "", roomId);
newSocket.emit("senderOffer", {
sdp,
senderSocketID: newSocket.id,
roomID: roomId,
});
} catch (error) {
console.log(error);
}
};
const createReceiverOffer = async (pc, newSocket, senderSocketID) => {
try {
let sdp = await pc.createOffer({
offerToReceiveAudio: true,
offerToReceiveVideo: true,
});
console.log("create receiver offer success");
await pc.setLocalDescription(new RTCSessionDescription(sdp));
console.log(sdp, newSocket.id, senderSocketID, roomId);
newSocket.emit("receiverOffer", {
sdp,
receiverSocketID: newSocket.id,
senderSocketID,
roomID: roomId,
});
} catch (error) {
console.log(error);
}
};
const createSenderPeerConnection = (newSocket, localStream) => {
let pc = new RTCPeerConnection(pc_config);
pc.onicecandidate = (e) => {
if (e.candidate) {
console.log("sender PC onicecandidate");
newSocket.emit("senderCandidate", {
candidate: e.candidate,
senderSocketID: newSocket.id,
});
}
};
pc.oniceconnectionstatechange = (e) => {
console.log(e);
};
if (localStream) {
console.log("localstream add");
localStream.getTracks().forEach((track) => {
pc.addTrack(track, localStream);
});
} else {
console.log("no local stream");
}
// return pc
return pc;
};
const createReceiverPeerConnection = (socketID, newSocket) => {
let pc = new RTCPeerConnection(pc_config);
// add pc to peerConnections object
receivePCs = { ...receivePCs, [socketID]: pc };
pc.onicecandidate = (e) => {
if (e.candidate) {
console.log("receiver PC onicecandidate");
newSocket.emit("receiverCandidate", {
candidate: e.candidate,
receiverSocketID: newSocket.id,
senderSocketID: socketID,
});
}
};
pc.oniceconnectionstatechange = (e) => {
console.log(e);
};
pc.ontrack = (e) => {
console.log("ontrack success");
setUsers((oldUsers) => oldUsers.filter((user) => user.id !== socketID));
setUsers((oldUsers) => [
...oldUsers,
{
id: socketID,
stream: e.streams[0],
},
]);
};
// return pc
return pc;
};
return ( return (
<div className="container"> <div className="container">
<div className="row"> {/* {console.log(users)} */}
<div className="col mt-3 d-flex justify-content-space-between" style={{ backgroundColor: '#FCF4FF' }}> <div className="mt-3" style={{ backgroundColor: "#FCF4FF" }}>
<div
className="m-2 d-flex fw-bold text-center"
style={{ color: "#4A4251", fontSize: "20px" }}
>
<img <img
className="rounded-circle" className="rounded-circle me-2"
src="/cherry.jpg" src="/cherry.jpg"
width="40px" width="40px"
height="40px" height="40px"
/> />
<p
className="m-2"
style={{ fontWeight: 'bold', color: '#4A4251', fontSize: '20px' }}
>
{user}님이 화면공유중... {user}님이 화면공유중...
<br />
</p>
<div className="col m-5"></div>
</div> </div>
<video
style={{
display: "flex",
justifyContent: "center",
width: 375,
height: 260,
backgroundColor: "black",
}}
muted
ref={localVideoRef}
autoPlay
/>
{/* {users.map((user, index) => {
return <Video key={index} stream={user.stream} />;
})} */}
</div> </div>
</div> </div>
) );
} };
export default Screen export default Screen;
...@@ -2,7 +2,7 @@ const User = () => { ...@@ -2,7 +2,7 @@ const User = () => {
return ( return (
<div className="container"> <div className="container">
<div className="row"> <div className="row">
<div className="col" style={{ backgroundColor: "#DEC7F5", position:'absolute', bottom:'58px', width: '414px'}}> <div className="col" style={{ backgroundColor: "#ded0fa", position:'absolute', bottom:'58px', width: '414px'}}>
<p <p
className="m-2" className="m-2"
style={{ fontWeight: "bold", color: "#4A4251", fontSize: "20px" }} style={{ fontWeight: "bold", color: "#4A4251", fontSize: "20px" }}
......
import axios from "axios"; import axios from "axios";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Redirect } from "react-router-dom";
import userApi from "../apis/user.api"; import userApi from "../apis/user.api";
// import catchErrors from "../context/catchError";
// import auth from "../context/auth_context"
const INIT_USER = { const INIT_USER = {
name: "", name: "",
idNumber1: "", idNumber1: "",
...@@ -17,6 +19,7 @@ const Signup = () => { ...@@ -17,6 +19,7 @@ const Signup = () => {
const [error, setError] = useState(""); const [error, setError] = useState("");
const [disabled, setDisabled] = useState(false); const [disabled, setDisabled] = useState(false);
const [success, setSuccess] = useState(false); const [success, setSuccess] = useState(false);
const [loading, setLoading] = useState(false);
useEffect(() => { useEffect(() => {
setDisabled( setDisabled(
...@@ -40,11 +43,13 @@ const Signup = () => { ...@@ -40,11 +43,13 @@ const Signup = () => {
async function handleSubmit() { async function handleSubmit() {
try { try {
const data = await userApi.signup(user) const data = await userApi.signup(user)
// const data = await axios.post("https://localhost:8080/api/room/1/1",user)
setLoading(true); setLoading(true);
setError(""); setError("");
// const success = await login(user.email, user.password); // const success = await login(user.email, user.password);
// const data = await axios.post("/api/room/1/1",user)
console.log(data); console.log(data);
setSuccess(success); setSuccess(true);
} catch (error) { } catch (error) {
// catchErrors(error, setError); // catchErrors(error, setError);
} finally { } finally {
...@@ -54,6 +59,7 @@ const Signup = () => { ...@@ -54,6 +59,7 @@ const Signup = () => {
if (success) { if (success) {
alert('회원가입 되었습니다.') alert('회원가입 되었습니다.')
return <Redirect to="/" />;
} }
......
import axios from 'axios'
export function handleLogin(userId) {
localStorage.setItem("user", userId)
}
export async function handleLogout() {
alert("로그아웃되었습니다.")
localStorage.removeItem("user")
await axios.get('/api/auth/logout')
window.location.href='/'
}
export function isAuthenticated() {
const userId = localStorage.getItem('loginStatus')
if (userId) {
return userId
}else{
return false
}
}
import axios from "axios"; import axios from "axios";
import { createContext, FC, useCallback, useContext, useState } from "react"; import { createContext, FC, useCallback, useContext, useState } from "react";
import authApi from "../apis/auth.api"; import authApi from "../apis/user.api";
import { getLocalUser } from "../utils/auth"; import { getLocalUser } from "../utils/auth";
import baseUrl from "../utils/baseUrl"; import baseUrl from "../utils/baseUrl";
import catchErrors from "../utils/catchErrors"; import catchErrors from "../utils/catchErrors";
......
function catchErrors(error, displayError) {
let errorMsg
if (error.response) {
errorMsg = error.response.data
console.log(errorMsg)
}else if (error.requset) {
errorMsg = error.requset
console.log(errorMsg)
} else {
errorMsg = error.message
console.log(errorMsg)
}
displayError(errorMsg)
}
export default catchErrors
$primary: #e8b7ff; $primary: #f5cfe3;
$secondary: #df99ff; $secondary: #df99ff;
$info: #fcf4ff; $info: #fcf4ff;
$warning: #ff0000; $warning: #ff0000;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment