Kaynağa Gözat

fix: Longpolling loop

gugdun 7 ay önce
ebeveyn
işleme
eac0a46343
3 değiştirilmiş dosya ile 69 ekleme ve 27 silme
  1. 1 1
      package.json
  2. 66 24
      src/routes/longpoll.js
  3. 2 2
      src/views/chat.ejs

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "svin-chat",
-  "version": "1.2.3",
+  "version": "1.2.4",
   "description": "Coolest chat in the world 😎",
   "main": "src/index.js",
   "scripts": {

+ 66 - 24
src/routes/longpoll.js

@@ -8,34 +8,76 @@ const { decrypt } = require("../util/crypto");
 const router = express.Router();
 
 router.post("/poll/:id", async (req, res) => {
-    if (req.user) {
-        try {
-            const chat = await db.one("SELECT user1_id, user2_id FROM chats WHERE id = $1", [ req.params.id ]);
-            if (chat?.user1_id !== req.user.id && chat?.user2_id !== req.user.id) {
-                throw "User does not belong to this chat!";
-            }
-            async function checkMessages() {
-                const messages = await db.any("SELECT username, attachment_id, text, timestamp FROM messages JOIN users ON users.id = user_id WHERE chat_id = $1 AND timestamp > $2 ORDER BY messages.timestamp DESC", [ req.params.id, req.body.timestamp ]);
+    if (!req.user) {
+        return res.redirect("/login");
+    }
+
+    const POLLING_TIMEOUT_MS = 30000;
+    const POLLING_INTERVAL_MS = 250;
+
+    let isFinished = false;
+    const startTime = Date.now();
+
+    // Прерывание при разрыве соединения клиентом
+    req.on("close", () => {
+        isFinished = true;
+    });
+
+    try {
+        const chat = await db.one("SELECT user1_id, user2_id FROM chats WHERE id = $1", [ req.params.id ]);
+
+        // Проверка доступа пользователя к чату
+        if (chat.user1_id !== req.user.id && chat.user2_id !== req.user.id) {
+            return res.status(403).json({ success: false, error: "Access denied" });
+        }
+
+        async function pollLoop() {
+            if (isFinished || res.writableEnded) return;
+
+            try {
+                const messages = await db.any(`
+                    SELECT username, attachment_id, text, timestamp
+                    FROM messages
+                    JOIN users ON users.id = user_id
+                    WHERE chat_id = $1 AND timestamp > $2
+                    ORDER BY messages.timestamp ASC
+                `, [ req.params.id, req.body.timestamp ]);
+
                 if (messages.length > 0) {
-                    res.json({
-                        messages: messages.map((message) => {
-                            return {
-                                username: message.username,
-                                text: decrypt(message.text),
-                                datetime: message.timestamp,
-                                attachment: message.attachment_id
-                            }
-                        })
+                    isFinished = true;
+                    return res.json({
+                        messages: messages.map(message => ({
+                            username: message.username,
+                            text: decrypt(message.text),
+                            datetime: message.timestamp,
+                            attachment: message.attachment_id
+                        }))
                     });
-                } else setTimeout(checkMessages, 500);
+                }
+
+                if (Date.now() - startTime > POLLING_TIMEOUT_MS) {
+                    isFinished = true;
+                    return res.status(204).end(); // Нет новых сообщений
+                }
+
+                // Ждём и пробуем снова
+                setTimeout(pollLoop, POLLING_INTERVAL_MS);
+            } catch (err) {
+                console.error("Polling DB error:", err);
+                if (!res.writableEnded) {
+                    isFinished = true;
+                    res.status(500).json({ success: false });
+                }
             }
-            checkMessages();
-        } catch (err) {
-            console.log(err);
-            res.json({ success: false });
         }
-    } else {
-        res.redirect("/login");
+
+        pollLoop();
+
+    } catch (err) {
+        console.error("Polling init error:", err);
+        if (!res.writableEnded) {
+            res.status(500).json({ success: false });
+        }
     }
 });
 

+ 2 - 2
src/views/chat.ejs

@@ -98,7 +98,7 @@
         messageList.insertBefore(container, target)
         setTimeout(function () {
             container.scrollIntoView()
-        }, 500)
+        }, 250)
     }
     function onMessageSubmit(event) {
         event.preventDefault()
@@ -177,7 +177,7 @@
     messageInput.addEventListener("focus", function (e) {
         setTimeout(function () {
             version.scrollIntoView()
-        }, 500)
+        }, 250)
     })
     window.addEventListener("pageshow", function (e) {
         messageList.firstElementChild.scrollIntoView(false)