|
1 | 1 | import express from 'express'; |
| 2 | +import cors from 'cors'; |
2 | 3 | import { createServer } from 'http'; |
3 | 4 | import { Server } from 'socket.io'; |
4 | | -import cors from 'cors'; |
5 | 5 | import chat from './data/chat.json' with { type: 'json' }; |
6 | 6 |
|
7 | 7 | const app = express(); |
8 | | -const server = createServer(app); |
9 | | -const io = new Server(server, { |
10 | | - cors: { |
11 | | - origin: '*', |
12 | | - }, |
13 | | -}); |
14 | | - |
15 | | -const socketChat = [...chat]; |
16 | | -const pollChat = [...chat]; |
17 | | - |
18 | | -let lastMessageIndex = 0; |
19 | | -const pollClients = []; |
| 8 | +const httpServer = createServer(app); |
| 9 | +const io = new Server(httpServer, { cors: { origin: '*' } }); |
20 | 10 |
|
21 | 11 | app.use(cors()); |
| 12 | +app.use(express.json()); |
22 | 13 |
|
23 | | -app.get('/healthcheck', (req, res) => res.send('Server is running')); |
| 14 | +const pollStore = { messages: JSON.parse(JSON.stringify(chat)), clients: [] }; |
| 15 | +const socketStore = { messages: JSON.parse(JSON.stringify(chat)) }; |
24 | 16 |
|
25 | | -app.get('/history', (req, res) => { |
26 | | - res.json(pollChat); |
| 17 | +app.get('/poll/history', (req, res) => { |
| 18 | + res.json(pollStore.messages); |
27 | 19 | }); |
28 | 20 |
|
29 | 21 | app.get('/poll', (req, res) => { |
30 | | - const clientLastIndex = parseInt(req.query.lastIndex) || 0; |
| 22 | + const since = parseInt(req.query.since) || 0; |
| 23 | + const newMessages = pollStore.messages.filter((_, i) => i >= since); |
31 | 24 |
|
32 | | - if (pollChat.length > clientLastIndex) { |
| 25 | + if (newMessages.length > 0) { |
33 | 26 | return res.json({ |
34 | | - messages: pollChat.slice(clientLastIndex), |
35 | | - lastIndex: pollChat.length, |
| 27 | + messages: newMessages, |
| 28 | + cursor: pollStore.messages.length, |
36 | 29 | }); |
37 | 30 | } |
38 | 31 |
|
39 | | - const timeoutId = setTimeout(() => { |
40 | | - const index = pollClients.indexOf(timeoutId); |
41 | | - if (index > -1) { |
42 | | - pollClients.splice(index, 1); |
43 | | - } |
44 | | - res.json({ |
45 | | - messages: [], |
46 | | - lastIndex: pollChat.length, |
47 | | - }); |
48 | | - }, 30000); |
| 32 | + pollStore.clients.push({ res }); |
49 | 33 |
|
50 | | - pollClients.push(timeoutId); |
| 34 | + req.on('close', () => { |
| 35 | + const i = pollStore.clients.findIndex((c) => c.res === res); |
| 36 | + if (i !== -1) pollStore.clients.splice(i, 1); |
| 37 | + }); |
51 | 38 |
|
52 | | - res.on('close', () => { |
53 | | - const index = pollClients.indexOf(timeoutId); |
54 | | - if (index > -1) { |
55 | | - pollClients.splice(index, 1); |
56 | | - clearTimeout(timeoutId); |
| 39 | + setTimeout(() => { |
| 40 | + const i = pollStore.clients.findIndex((c) => c.res === res); |
| 41 | + if (i !== -1) { |
| 42 | + pollStore.clients.splice(i, 1); |
| 43 | + res.json({ messages: [], cursor: since }); |
57 | 44 | } |
58 | | - }); |
| 45 | + }, 30000); |
59 | 46 | }); |
60 | 47 |
|
61 | | -app.post('/message', express.json(), (req, res) => { |
| 48 | +app.post('/poll/message', (req, res) => { |
62 | 49 | const msg = req.body; |
63 | | - pollChat.push(msg); |
| 50 | + pollStore.messages.push(msg); |
| 51 | + pollStore.clients.forEach(({ res }) => |
| 52 | + res.json({ messages: [msg], cursor: pollStore.messages.length }), |
| 53 | + ); |
| 54 | + pollStore.clients.length = 0; |
| 55 | + res.sendStatus(200); |
| 56 | +}); |
64 | 57 |
|
65 | | - pollClients.forEach((timeoutId) => clearTimeout(timeoutId)); |
66 | | - pollClients.length = 0; |
67 | | - io.emit('message', msg); |
| 58 | +app.patch('/poll/message/:index/likes', (req, res) => { |
| 59 | + console.log('http poll'); |
| 60 | + const msg = pollStore.messages[req.params.index]; |
| 61 | + if (!msg) return res.sendStatus(404); |
| 62 | + msg.likes++; |
| 63 | + pollStore.clients.forEach(({ res }) => |
| 64 | + res.json({ |
| 65 | + messages: [{ ...msg, index: Number(req.params.index) }], |
| 66 | + cursor: pollStore.messages.length, |
| 67 | + }), |
| 68 | + ); |
| 69 | + pollStore.clients.length = 0; |
| 70 | + res.sendStatus(200); |
| 71 | +}); |
68 | 72 |
|
69 | | - res.json({ success: true }); |
| 73 | +app.patch('/poll/message/:index/dislikes', (req, res) => { |
| 74 | + const msg = pollStore.messages[req.params.index]; |
| 75 | + if (!msg) return res.sendStatus(404); |
| 76 | + msg.dislikes++; |
| 77 | + pollStore.clients.forEach(({ res }) => |
| 78 | + res.json({ |
| 79 | + messages: [{ ...msg, index: Number(req.params.index) }], |
| 80 | + cursor: pollStore.messages.length, |
| 81 | + }), |
| 82 | + ); |
| 83 | + pollStore.clients.length = 0; |
| 84 | + res.sendStatus(200); |
70 | 85 | }); |
71 | 86 |
|
72 | 87 | io.on('connection', (socket) => { |
73 | | - socket.emit('history', socketChat); |
| 88 | + socket.emit( |
| 89 | + 'history', |
| 90 | + socketStore.messages.map((msg, index) => ({ ...msg, index })), |
| 91 | + ); |
74 | 92 |
|
75 | 93 | socket.on('message', (msg) => { |
76 | | - socketChat.push(msg); |
77 | | - socket.broadcast.emit('message', msg); |
| 94 | + socketStore.messages.push(msg); |
| 95 | + socket.broadcast.emit('message', { ...msg, self: false }); |
| 96 | + }); |
78 | 97 |
|
79 | | - pollClients.forEach((timeoutId) => clearTimeout(timeoutId)); |
80 | | - pollClients.length = 0; |
| 98 | + socket.on('react', ({ index, type }) => { |
| 99 | + console.log('ws'); |
| 100 | + const msg = socketStore.messages[index]; |
| 101 | + if (!msg) return; |
| 102 | + msg[type]++; |
| 103 | + socket.broadcast.emit('react', { index, type, value: msg[type] }); |
81 | 104 | }); |
82 | 105 | }); |
83 | 106 |
|
84 | | -server.listen(3000, () => { |
85 | | - console.log('server running at http://localhost:3000'); |
86 | | -}); |
| 107 | +httpServer.listen(3000, () => console.log('Server running on port: 3000')); |
0 commit comments