Pārlūkot izejas kodu

fix(ws): simplify websocket paths and remove duplication

unknown 3 dienas atpakaļ
vecāks
revīzija
fa4d1229cd
4 mainītis faili ar 55 papildinājumiem un 44 dzēšanām
  1. 49 2
      backend/main.py
  2. 4 39
      backend/routers/chat.py
  3. 1 2
      src/components/OrderChat.vue
  4. 1 1
      src/stores/auth.ts

+ 49 - 2
backend/main.py

@@ -8,6 +8,7 @@ import os
 import auth_utils
 import session_utils
 from services.global_manager import global_manager
+from services.chat_manager import manager
 
 import locales
 import config
@@ -74,8 +75,7 @@ app.include_router(blog.router)
 app.include_router(admin.router)
 
 # WebSocket Global Handler (Centralized to handle various proxy prefixes)
-@app.websocket("/ws/auth/ws/global")
-@app.websocket("/auth/ws/global")
+@app.websocket("/global")
 async def ws_global(websocket: WebSocket, token: str = Query(...)):
     print(f"DEBUG: WS Connection attempt with token: {token[:10]}...")
     payload = auth_utils.decode_token(token)
@@ -112,6 +112,53 @@ async def ws_global(websocket: WebSocket, token: str = Query(...)):
         print(f"DEBUG: WS Error: {e}")
         global_manager.disconnect(websocket, user_id)
 
+@app.websocket("/chat")
+async def ws_chat(websocket: WebSocket, token: str = Query(...), order_id: int = Query(...)):
+    print(f"DEBUG: Chat WS attempt: order_id={order_id}")
+    payload = auth_utils.decode_token(token)
+    if not payload:
+        await websocket.close(code=4001)
+        return
+    role = payload.get("role")
+    user_id = payload.get("id")
+    if role != 'admin':
+        user_info = db.execute_query("SELECT can_chat FROM users WHERE id = %s", (user_id,))
+        if not user_info or not user_info[0]['can_chat']:
+            await websocket.close(code=4003)
+            return
+
+    order = db.execute_query("SELECT user_id FROM orders WHERE id = %s", (order_id,))
+    if not order:
+        await websocket.close(code=4004)
+        return
+    if role != 'admin' and order[0]['user_id'] != user_id:
+        await websocket.close(code=4003)
+        return
+    
+    print(f"DEBUG: Chat WS connected: order_id={order_id}, user_id={user_id}")
+    await manager.connect(websocket, order_id, role)
+    try:
+        while True:
+            data = await websocket.receive_text()
+            if data == "typing":
+                await manager.broadcast_to_order(order_id, {"type": "typing", "is_admin": role == 'admin'})
+            elif data == "stop_typing":
+                await manager.broadcast_to_order(order_id, {"type": "stop_typing", "is_admin": role == 'admin'})
+            elif data == "read":
+                if role == 'admin':
+                    db.execute_commit("UPDATE order_messages SET is_read = TRUE WHERE order_id = %s AND is_from_admin = FALSE AND is_read = FALSE", (order_id,))
+                    await global_manager.notify_admins()
+                    await global_manager.notify_order_read(order_id)
+                else:
+                    db.execute_commit("UPDATE order_messages SET is_read = TRUE WHERE order_id = %s AND is_from_admin = TRUE AND is_read = FALSE", (order_id,))
+                    await global_manager.notify_user(user_id)
+    except WebSocketDisconnect:
+        print(f"DEBUG: Chat WS disconnected: order_id={order_id}")
+        manager.disconnect(websocket, order_id)
+    except Exception as e:
+        print(f"DEBUG: Chat WS error: {e}")
+        manager.disconnect(websocket, order_id)
+
 # Mount Static Files
 if not os.path.exists("uploads"):
     os.makedirs("uploads")

+ 4 - 39
backend/routers/chat.py

@@ -82,42 +82,7 @@ async def post_order_message(order_id: int, data: schemas.MessageCreate, user: d
         event_hooks.on_message_received(order_id, user_id, message)
     return {"id": msg_id, "status": "sent"}
 
-@router.websocket("/ws/chat/{order_id}")
-async def ws_chat(websocket: WebSocket, order_id: int, token: str = Query(...)):
-    payload = auth_utils.decode_token(token)
-    if not payload:
-        await websocket.close(code=4001)
-        return
-    role = payload.get("role")
-    user_id = payload.get("id")
-    if role != 'admin':
-        user_info = db.execute_query("SELECT can_chat FROM users WHERE id = %s", (user_id,))
-        if not user_info or not user_info[0]['can_chat']:
-            await websocket.close(code=4003)
-            return
-
-    order = db.execute_query("SELECT user_id FROM orders WHERE id = %s", (order_id,))
-    if not order:
-        await websocket.close(code=4004)
-        return
-    if role != 'admin' and order[0]['user_id'] != user_id:
-        await websocket.close(code=4003)
-        return
-    await manager.connect(websocket, order_id, role)
-    try:
-        while True:
-            data = await websocket.receive_text()
-            if data == "typing":
-                await manager.broadcast_to_order(order_id, {"type": "typing", "is_admin": role == 'admin'})
-            elif data == "stop_typing":
-                await manager.broadcast_to_order(order_id, {"type": "stop_typing", "is_admin": role == 'admin'})
-            elif data == "read":
-                if role == 'admin':
-                    db.execute_commit("UPDATE order_messages SET is_read = TRUE WHERE order_id = %s AND is_from_admin = FALSE AND is_read = FALSE", (order_id,))
-                    await global_manager.notify_admins()
-                    await global_manager.notify_order_read(order_id)
-                else:
-                    db.execute_commit("UPDATE order_messages SET is_read = TRUE WHERE order_id = %s AND is_from_admin = TRUE AND is_read = FALSE", (order_id,))
-                    await global_manager.notify_user(user_id)
-    except WebSocketDisconnect:
-        manager.disconnect(websocket, order_id)
+# WebSocket moved to main.py
+# @router.websocket("/ws/chat/{order_id}")
+# async def ws_chat(websocket: WebSocket, order_id: int, token: str = Query(...)):
+#     ...

+ 1 - 2
src/components/OrderChat.vue

@@ -138,8 +138,7 @@ function connectWebSocket() {
   const token = localStorage.getItem("token");
   if (!token) return;
 
-  const url = `${WS_BASE_URL}/ws/chat/${props.orderId}?token=${encodeURIComponent(token)}`;
-  ws = new WebSocket(url);
+  ws = new WebSocket(`${WS_BASE_URL}/chat?token=${encodeURIComponent(token)}&order_id=${props.orderId}`);
 
   ws.onopen = () => {
     wsConnected.value = true;

+ 1 - 1
src/stores/auth.ts

@@ -143,7 +143,7 @@ export const useAuthStore = defineStore("auth", () => {
     const token = localStorage.getItem("token");
     if (!token || wsAuthFailed.value) return;
 
-    globalWs = new WebSocket(`${WS_BASE_URL}/auth/ws/global?token=${encodeURIComponent(token)}`);
+    globalWs = new WebSocket(`${WS_BASE_URL}/global?token=${encodeURIComponent(token)}`);
 
     globalWs.onopen = () => {
       // Send ping every 25 seconds to keep connection alive and update online status in Redis