diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f41f3b4..16674e7 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import { AuthContext } from "./context/AuthContext"; import { StreamsProvider } from "./context/StreamsContext"; import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { SocketProvider } from "./context/SocketContext"; import HomePage from "./pages/HomePage"; import StreamerRoute from "./components/Stream/StreamerRoute"; import NotFoundPage from "./pages/NotFoundPage"; @@ -25,19 +26,20 @@ function App() { return ( - - - - : } - /> - } /> - - } /> - - - + + + + + : } + /> + } /> + } /> + + + + ); } diff --git a/frontend/src/components/Layout/ListRow.tsx b/frontend/src/components/Layout/ListRow.tsx index d3d8437..3649fb2 100644 --- a/frontend/src/components/Layout/ListRow.tsx +++ b/frontend/src/components/Layout/ListRow.tsx @@ -27,7 +27,6 @@ const ListItem: React.FC = ({ thumbnail, onItemClick, }) => { - console.log(title, "thumbnail", thumbnail); return (
= ({ streamId }) => { const [messages, setMessages] = useState([]); const [inputMessage, setInputMessage] = useState(""); - const [socket, setSocket] = useState(null); const chatContainerRef = useRef(null); const { isLoggedIn, username } = useAuth(); + const { socket, isConnected } = useSocket(); - // Initialize socket connection + // Join chat room when component mounts useEffect(() => { - const newSocket = io("/", { - path: "/api/socket.io", - withCredentials: true - }); - setSocket(newSocket); + if (socket && isConnected) { + socket.emit("join", { stream_id: streamId }); - newSocket.on("connect", () => { - console.log("Socket Connection established!"); - // Join the stream's chat room - newSocket.emit("join", { stream_id: streamId }); - }); + // Load initial chat history + fetch(`/api/chat/${streamId}`) + .then((response) => { + if (!response.ok) throw new Error("Failed to fetch chat history"); + return response.json(); + }) + .then((data) => { + if (data.chat_history) { + setMessages(data.chat_history); + } + }) + .catch((error) => { + console.error("Error loading chat history:", error); + }); - newSocket.on("new_message", (data: ChatMessage) => { - setMessages(prev => [...prev, data]); - }); + // Handle incoming messages + socket.on("new_message", (data: ChatMessage) => { + setMessages((prev) => [...prev, data]); + }); - newSocket.on("connect_error", (error) => { - console.error("Socket connection error:", error); - }); - - newSocket.on("connect_timeout", () => { - console.error("Socket connection timeout"); - }); - - newSocket.on("error", (error) => { - console.error("Socket error:", error); - }); - - // Cleanup on unmount - return () => { - newSocket.emit("leave", { stream_id: streamId }); - newSocket.close(); - }; - }, [streamId]); - - // Load initial chat history - useEffect(() => { - const loadPastChat = async () => { - try { - const response = await fetch(`/api/chat/${streamId}`); - if (!response.ok) throw new Error("Failed to fetch chat history"); - const data = await response.json(); - if (data.chat_history) { - setMessages(data.chat_history); - } - } catch (error) { - console.error("Error loading chat history:", error); - } - }; - - loadPastChat(); - }, [streamId]); + // Cleanup + return () => { + socket.emit("leave", { stream_id: streamId }); + socket.off("new_message"); + }; + } + }, [socket, isConnected, streamId]); // Auto-scroll to bottom when new messages arrive useEffect(() => { if (chatContainerRef.current) { - chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight; + chatContainerRef.current.scrollTop = + chatContainerRef.current.scrollHeight; } }, [messages]); const sendChat = () => { - if (!inputMessage.trim() || !socket) { - console.log("No message to send or socket not initialized!"); + if (!inputMessage.trim() || !socket || !isConnected) { + console.log("Invalid message or socket not connected"); return; - }; + } socket.emit("send_message", { stream_id: streamId, - message: inputMessage.trim() + message: inputMessage.trim(), }); setInputMessage(""); @@ -102,7 +81,7 @@ const ChatPanel: React.FC = ({ streamId }) => { sendChat(); } }; - + return (

Stream Chat

@@ -113,11 +92,21 @@ const ChatPanel: React.FC = ({ streamId }) => { className="flex-grow w-full max-h-[50vh] overflow-y-auto mb-4 space-y-2" > {messages.map((msg, index) => ( -
+
{new Date(msg.time_sent).toLocaleTimeString()} - {msg.chatter_id}: + + {" "} + {msg.chatter_id}:{" "} + {msg.message}
))} @@ -145,4 +134,4 @@ const ChatPanel: React.FC = ({ streamId }) => { ); }; -export default ChatPanel; \ No newline at end of file +export default ChatPanel; diff --git a/frontend/src/context/SocketContext.tsx b/frontend/src/context/SocketContext.tsx new file mode 100644 index 0000000..b75db69 --- /dev/null +++ b/frontend/src/context/SocketContext.tsx @@ -0,0 +1,57 @@ +import React, { createContext, useContext, useEffect, useState } from 'react'; +import { io, Socket } from 'socket.io-client'; + +interface SocketContextType { + socket: Socket | null; + isConnected: boolean; +} + +const SocketContext = createContext(undefined); + +export const SocketProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [socket, setSocket] = useState(null); + const [isConnected, setIsConnected] = useState(false); + + useEffect(() => { + const newSocket = io("http://localhost:8080", { + path: "/socket.io/", + withCredentials: true, + transports: ['websocket'], + upgrade: false + }); + + newSocket.on('connect', () => { + console.log('Socket connected!'); + setIsConnected(true); + }); + + newSocket.on('connect_error', (error) => { + console.error('Socket connection error:', error); + }); + + newSocket.on('disconnect', () => { + console.log('Socket disconnected!'); + setIsConnected(false); + }); + + setSocket(newSocket); + + return () => { + newSocket.close(); + }; + }, []); + + return ( + + {children} + + ); +}; + +export const useSocket = () => { + const context = useContext(SocketContext); + if (context === undefined) { + throw new Error('useSocket must be used within a SocketProvider'); + } + return context; +}; \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 573f21a..199c658 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -37,6 +37,7 @@ rtmp { } http { + access_log off; # Enable HLS server { listen 8080; diff --git a/web_server/blueprints/streams.py b/web_server/blueprints/streams.py index 6ca9c63..e81082b 100644 --- a/web_server/blueprints/streams.py +++ b/web_server/blueprints/streams.py @@ -134,7 +134,7 @@ def get_specific_stream(streamer_username, stream_id): if stream: return jsonify(stream) - abort(404) + return jsonify({'error': 'Stream not found'}), 404 @login_required @stream_bp.route('/get_followed_streamers')