Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"test": "echo \"Error: no test specified\" && exit 1",
"start:http": "NODE_ENV=development nodemon src/http/server.ts",
"start:socket": "NODE_ENV=development nodemon src/socket/server.ts",
"start:all": "concurrently \"npm run start:http\" \"npm run start:socket\"",
"start:webrtc": "NODE_ENV=development nodemon src/webrtc/signalingServer.ts",
"start:all": "concurrently \"npm run start:http\" \"npm run start:socket\" \"npm run start:webrtc\"",
"list:env": "node -e 'console.log(process.env)'",
"build": "tsc",
"start": "node dist/http/server.js"
Expand Down
4 changes: 3 additions & 1 deletion server/src/utils/env.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import dotenv from "dotenv";
import path from 'path';
import path from "path";

const envFile = process.env.NODE_ENV === "production" ? ".env.production" : ".env.development";
dotenv.config({ path: path.resolve(__dirname, "../../", envFile) });
Expand All @@ -24,6 +24,7 @@ export const GOOGLE_CLIENT_SECRET = getEnvVar("GOOGLE_CLIENT_SECRET");
export const UI_REDIRECT_URL = getEnvVar("UI_REDIRECT_URL");
export const SECRET_KEY = getEnvVar("SECRET_KEY");
export const GOOGLE_CALLBACK_URL = getEnvVar("GOOGLE_CALLBACK_URL");
export const WEBRTC_PORT = parseInt(getEnvVar("WEBRTC_PORT"));

// Log environment variables in development
if (process.env.NODE_ENV === "development") {
Expand All @@ -38,5 +39,6 @@ if (process.env.NODE_ENV === "development") {
UI_REDIRECT_URL,
SECRET_KEY,
GOOGLE_CALLBACK_URL,
WEBRTC_PORT,
});
}
72 changes: 72 additions & 0 deletions server/src/webrtc/signalingServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import express from "express";
import http from "http";
import { Server, Socket } from "socket.io";
import { WEBRTC_PORT } from "../utils/env";

const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});

type RoomMap = Record<string, Record<string, string>>;
const rooms: RoomMap = {};
const TAG = "SignalingServer";

io.on("connection", (socket: Socket) => {
console.log(TAG, "User connected:", socket.id);

socket.on("join", (roomId: string, email: string) => {
if (!rooms[roomId]) rooms[roomId] = {};
// if (rooms[roomId].length >= 2) {
// socket.emit("room_full");
// return;
// }

rooms[roomId][email] = socket.id;
socket.join(roomId);
console.log(TAG, `${socket.id} joined room ${roomId}`);
console.log(TAG, rooms[roomId]);

const otherUser = Object.keys(rooms[roomId]).find((id) => id !== email);
if (otherUser) {
console.log(TAG, `${socket.id} found other user ${otherUser}`);
socket.emit("other-user", rooms[roomId][otherUser], otherUser);
io.to(rooms[roomId][otherUser]).emit("user-joined", socket.id, email);
}

socket.on("offer", ({ to, offer }: { to: string; offer: RTCSessionDescriptionInit }, email: string) => {
console.log(TAG, `${socket.id} sent offer to ${to}`);
io.to(to).emit("offer", { from: socket.id, offer }, email);
});

socket.on("answer", ({ to, answer }: { to: string; answer: RTCSessionDescriptionInit }, email: string) => {
console.log(TAG, `${socket.id} sent answer to ${to}`);
io.to(to).emit("answer", { from: socket.id, answer }, email);
});

socket.on(
"ice-candidate",
({ to, candidate }: { to: string; candidate: RTCIceCandidateInit }, email: string) => {
console.log(TAG, `${socket.id} sent ice candidate to ${to}`);
io.to(to).emit("ice-candidate", { from: socket.id, candidate }, email);
}
);

socket.on("disconnect", () => {
console.log(TAG, "User disconnected:", socket.id);
const email = Object.keys(rooms[roomId]).find((id) => rooms[roomId][id] === socket.id);
if (email) {
socket.to(rooms[roomId][email]).emit("user-disconnected", email);
delete rooms[roomId][email];
}
});
});
});

server.listen(WEBRTC_PORT, () => {
console.log(`Signaling server listening on http://localhost:${WEBRTC_PORT}`);
});
17 changes: 17 additions & 0 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/js-cookie": "^3.0.6",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"dotenv": "^16.4.7",
"emoji-mart": "^5.6.0",
"js-cookie": "^3.0.5",
"jwt-decode": "^4.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
3 changes: 2 additions & 1 deletion ui/src/PageRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import ProfileV2 from "./pages/ProfileV2/Page";
import { ProtectedRoute } from "./components/ProtectedRoute";
import { AuthProvider } from "./contexts/Auth";
import StreamingRoomV2 from "./pages/StreamingRoomV2/Page";
import Cookies from "js-cookie";

const PageRoute: FC = () => {
const [initialCompenent, setInitialComponent] = useState<React.JSX.Element>(<LandingPage />);

useEffect(() => {
const currentToken = localStorage.getItem("authToken");
const currentToken = Cookies.get("authToken");
if (currentToken) {
setInitialComponent(<HomeV2 />);
} else {
Expand Down
6 changes: 4 additions & 2 deletions ui/src/api/common.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { HTTP_SERVER_URL } from "../utils/env";
import Cookies from "js-cookie";

export const baseUrl = HTTP_SERVER_URL + "/";

export const getHeaders = () => {
const token = localStorage.getItem("authToken");
const cookie = Cookies.get("authToken");
return {
Authorization: `Bearer ${token}`,
Authorization: `Bearer ${cookie}`,
"Content-Type": "application/json",
};
};
3 changes: 2 additions & 1 deletion ui/src/components/ProtectedRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { FC, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useAuth } from "../contexts/Auth";
import Cookies from "js-cookie";

interface ProtectedRouteProps {
children: React.ReactNode;
Expand All @@ -11,7 +12,7 @@ export const ProtectedRoute: FC<ProtectedRouteProps> = ({ children }) => {
const { user } = useAuth();

useEffect(() => {
const token = localStorage.getItem("authToken");
const token = Cookies.get("authToken");
if (!token || !user) {
navigate("/login", { replace: true });
}
Expand Down
5 changes: 3 additions & 2 deletions ui/src/contexts/Auth.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { createContext, useContext, useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { getProfile } from "../api/profile";
import Cookies from "js-cookie";

interface User {
email: string;
Expand All @@ -24,7 +25,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {

useEffect(() => {
const validateToken = async () => {
const token = localStorage.getItem("authToken");
const token = Cookies.get("authToken");
if (token) {
try {
const profile = await getProfile();
Expand All @@ -35,7 +36,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
});
} catch (error) {
// Token is invalid or expired
localStorage.removeItem("authToken");
Cookies.remove("authToken");
setUser(null);
navigate("/login", { replace: true });
}
Expand Down
7 changes: 4 additions & 3 deletions ui/src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { getStreamingRoomsList, StreamingRoom } from "../api/streamingRoom";
import { StreamingRoomListItem } from "../components/StreamingRoomListItem";
import AuthContext from "../contexts/Auth";
import Cookies from "js-cookie";

enum Section {
StreamingRooms,
Expand All @@ -29,7 +30,7 @@ const Home: FC = () => {
const { setUser, user } = useContext(AuthContext);

const checkOldTokenValidity = (newToken: string | null): boolean => {
const currentToken = localStorage.getItem("authToken");
const currentToken = Cookies.get("authToken");
console.log("currentToken", currentToken);
console.log("token", newToken);
if (newToken == null && currentToken) {
Expand All @@ -51,14 +52,14 @@ const Home: FC = () => {

const checkNewTokenValidity = (name: string | null, email: string | null, token: string | null) => {
if (!name || !email || !token) {
const token = localStorage.getItem("authToken");
const token = Cookies.get("authToken");
if (!user?.email || !user?.name || !token) {
navigation("/login");
return;
}
return;
}
localStorage.setItem("authToken", token ?? "");
Cookies.set("authToken", token ?? "", { expires: 1, path: "/", secure: true });
changeSection(Section.StreamingRooms);
setUser({ email: email ?? "", name: name ?? "", picture: "" });
};
Expand Down
7 changes: 4 additions & 3 deletions ui/src/pages/HomeV2/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import AuthContext from "../../contexts/Auth";
import HeartIcon from "./svg/HeartIcon";
import FriendsIcon from "./svg/FriendsIcon";
import Cookies from "js-cookie";

function getInitials(name: string): string {
return name
Expand Down Expand Up @@ -80,7 +81,7 @@ export const HomeV2: React.FC = () => {
const token = params.get("token");

const checkOldTokenValidity = (newToken: string | null): boolean => {
const currentToken = localStorage.getItem("authToken");
const currentToken = Cookies.get("authToken");
if (newToken == null && currentToken) {
getProfile()
.then((profileResp) => {
Expand All @@ -96,14 +97,14 @@ export const HomeV2: React.FC = () => {

const checkNewTokenValidity = (name: string | null, email: string | null, token: string | null) => {
if (!name || !email || !token) {
const token = localStorage.getItem("authToken");
const token = Cookies.get("authToken");
if (!user?.email || !user?.name || !token) {
navigation("/login");
return;
}
return;
}
localStorage.setItem("authToken", token ?? "");
Cookies.set("authToken", token ?? "", { expires: 1, path: "/", secure: true });
setUser({ email: email ?? "", name: name ?? "", picture: "" });
};

Expand Down
3 changes: 2 additions & 1 deletion ui/src/pages/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useLocation, useNavigate } from "react-router-dom";
import AuthContext from "../contexts/Auth";
import { useContext } from "react";
import { FriendshipStatus } from "../api/profile";
import Cookies from "js-cookie";

export const Profile: FC = () => {
const [user, setUser] = useState<ProfileResp | null>(null);
Expand Down Expand Up @@ -45,7 +46,7 @@ export const Profile: FC = () => {
};

const handleLogout = () => {
localStorage.removeItem("authToken");
Cookies.remove("authToken");
setAuthUser(null);
navigate("/login");
};
Expand Down
3 changes: 2 additions & 1 deletion ui/src/pages/ProfileV2/components/LogOut.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React, { FC } from "react";
import { useNavigate } from "react-router-dom";
import { useAuth } from "../../../contexts/Auth";
import Cookies from "js-cookie";

export const LogOut: FC = () => {
const navigate = useNavigate();

const { setUser } = useAuth();

const onLogout = () => {
localStorage.removeItem("authToken");
Cookies.remove("authToken");
setUser(null);
document.cookie.split(";").forEach(function (c) {
document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
Expand Down
Loading