From f4aed8b0ccb9f13ecc3245a95c533916c9a4c714 Mon Sep 17 00:00:00 2001 From: white <122345776@umail.ucc.ie> Date: Sat, 25 Jan 2025 12:45:09 +0000 Subject: [PATCH] Added Websockets to chat --- web_server/blueprints/__init__.py | 8 ++- web_server/blueprints/chat.py | 77 ++++++++++----------- web_server/blueprints/templates/chat.html | 82 +++++++++++------------ web_server/requirements.txt | 1 + 4 files changed, 85 insertions(+), 83 deletions(-) diff --git a/web_server/blueprints/__init__.py b/web_server/blueprints/__init__.py index a9be838..cb90558 100644 --- a/web_server/blueprints/__init__.py +++ b/web_server/blueprints/__init__.py @@ -1,4 +1,4 @@ -from flask import Flask, jsonify +from flask import Flask # from flask_wtf.csrf import CSRFProtect, generate_csrf from flask_session import Session from blueprints.utils import logged_in_user @@ -30,8 +30,9 @@ def create_app(): from blueprints.stripe import stripe_bp from blueprints.user import user_bp from blueprints.streams import stream_bp - from blueprints.chat import chat_bp + from blueprints.chat import chat_bp, socketio + # Registering Blueprints app.register_blueprint(auth_bp) app.register_blueprint(main_bp) app.register_blueprint(stripe_bp) @@ -39,4 +40,7 @@ def create_app(): app.register_blueprint(stream_bp) app.register_blueprint(chat_bp) + # Tell sockets where the initialisation app is + socketio.init_app(app, cors_allowed_origins="*") + return app diff --git a/web_server/blueprints/chat.py b/web_server/blueprints/chat.py index f463561..d0b580a 100644 --- a/web_server/blueprints/chat.py +++ b/web_server/blueprints/chat.py @@ -1,12 +1,39 @@ -from flask import Blueprint, request, jsonify +from flask import Blueprint, request, jsonify, session from blueprints.utils import login_required from database.database import Database +from flask_socketio import SocketIO, emit, join_room, leave_room +from datetime import datetime chat_bp = Blueprint("chat", __name__) +socketio = SocketIO() # <---------------------- ROUTES NEEDS TO BE CHANGED TO VIDEO OR DELETED AS DEEMED APPROPRIATE ----------------------> # TODO: Add a route that deletes all chat logs when the stream is finished +@socketio.on("connect") +def handle_connection(): + print("Client Connected") + +@socketio.on("join") +def handle_join(data): + """ + Allow a user to join the chat of the stream they are watching. + """ + stream_id = data.get("stream_id") + if stream_id: + join_room(stream_id) + emit("status", {"message": f"Welcome to the chat, stream_id: {stream_id}"}, room=stream_id) + +@socketio.on("leave") +def handle_leave(data): + """ + Handle what happens when a user leaves the stream they are watching in regards to the chat. + """ + stream_id = data.get("stream_id") + if stream_id: + leave_room(stream_id) + emit("status", {"message": f"user left room {stream_id}"}, room=stream_id) + @chat_bp.route("/chat/") def get_past_chat(stream_id): """ @@ -40,22 +67,21 @@ def get_past_chat(stream_id): # Pass the chat history to the proxy return jsonify({"chat_history": chat_history}), 200 -@chat_bp.route("/send_chat", methods=["POST"]) -@login_required -def send_chat(): +@socketio.on("send_message") +def send_chat(data): """ - Works with react, takes the chat entered by a logged in user and stores in database + Using WebSockets to send a chat message to the specified chat """ # Take the message information from frontend - data = request.get_json() - chatter_id = data.get("chatter_id") + chatter_id = data.get("chatter_id") # Need to change this to get session info stream_id = data.get("stream_id") message = data.get("message") # Input validation - chatter is logged in, message is not empty, stream exists if not all([chatter_id, message, stream_id]): - return jsonify({"chat_sent": False}), 400 + emit("error", {"error": "Unable to send a chat"}, broadcast=False) + return # Save chat information to database so other users can see db = Database() @@ -66,33 +92,8 @@ def send_chat(): db.commit_data() db.close_connection() - return jsonify({"chat_sent": True}), 200 - - - - -@chat_bp.route("/load_new_chat/", methods=["GET"]) -def get_recent_chat(stream_id): - """ - Fetch new chat messages on a stream a user has already loaded in to. - """ - # Get the last received chat to avoid repeating old chats - last_received = request.args.get("last_received") # last_received is a time stamp - if not last_received: - return jsonify({"error": "last_received timestamp required"}), 400 - - # Get the most recent chats from the database - db = Database() - cursor = db.create_connection() - - # fetched in format: [(chatter_id, message, time_sent)] - new_chats = cursor.execute(""" - SELECT chatter_id, message, time_sent - FROM chat - WHERE stream_id = ? - AND time_sent > ?;""", (stream_id, last_received)).fetchall() - db.close_connection() - - # Send the new chats to frontend - chat_data = [{"chatter_id": chat[0], "message": chat[1], "time_sent": chat[2]} for chat in new_chats] - return jsonify(chat_data), 200 \ No newline at end of file + emit("new_message", { + "chatter_id":chatter_id, + "message":message, + "time_sent": datetime.now().strftime("%Y-%m-%d %H:%M:%S") + }, room=stream_id) \ No newline at end of file diff --git a/web_server/blueprints/templates/chat.html b/web_server/blueprints/templates/chat.html index 70d54a2..3629a14 100644 --- a/web_server/blueprints/templates/chat.html +++ b/web_server/blueprints/templates/chat.html @@ -5,22 +5,37 @@ Chat Interface + diff --git a/web_server/requirements.txt b/web_server/requirements.txt index 6bace7f..2460d7b 100644 --- a/web_server/requirements.txt +++ b/web_server/requirements.txt @@ -21,3 +21,4 @@ urllib3==2.3.0 Werkzeug==3.1.3 WTForms==3.2.1 Gunicorn==20.1.0 +flask-socketio==5.5.1 \ No newline at end of file