diff --git a/package-lock.json b/package-lock.json index 03495cd..4e93449 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "dependencies": { "@netlify/functions": "^1.6.0", + "uuid": "^9.0.0", "ws": "^8.13.0" }, "devDependencies": { @@ -17753,6 +17754,14 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vite": { "version": "4.3.9", "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", diff --git a/package.json b/package.json index 5246090..42eab38 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "private": true, "scripts": { - "dev": "vite dev && netlify dev", + "dev": "vite dev", "build": "vite build", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", @@ -28,6 +28,7 @@ "type": "module", "dependencies": { "@netlify/functions": "^1.6.0", + "uuid": "^9.0.0", "ws": "^8.13.0" } } diff --git a/src/functions/websocket.js b/src/functions/websocket.js new file mode 100644 index 0000000..9994d71 --- /dev/null +++ b/src/functions/websocket.js @@ -0,0 +1,71 @@ +// websocket.js + +import { Server, OPEN } from 'ws'; + +const handler = async (event, context) => { + const wss = new Server({ noServer: true }); + + const clients = new Map(); + const estimates = new Map(); + + wss.on('connection', (socket) => { + const roomID = new URL(event.headers.referer).pathname.replace('/', ''); + + clients.set(socket, roomID); + + function broadcast(roomID, message) { + wss.clients.forEach((client) => { + if (clients.get(client) === roomID && client !== socket && client.readyState === OPEN) { + client.send(JSON.stringify(message)); + } + }); + } + + broadcast(roomID, { type: 'user-joined', message: 'A new user has joined the room' }); + + socket.on('message', (message) => { + const data = JSON.parse(message); + + if (data.type === 'select-estimate') { + const { user, estimate } = data; + + if (!estimates.has(roomID)) { + estimates.set(roomID, new Map()); + } + estimates.get(roomID).set(user, estimate); + + broadcast(roomID, { type: 'estimate-selected', user, estimate }); + } + }); + + socket.on('close', () => { + const user = clients.get(socket); + + clients.delete(socket); + + if (estimates.has(roomID)) { + estimates.get(roomID).delete(user); + } + + broadcast(roomID, { type: 'user-left', message: `${user} has left the room` }); + + if (estimates.has(roomID) && estimates.get(roomID).size === 0) { + estimates.delete(roomID); + broadcast(roomID, { type: 'estimation-closed', message: 'Estimation closed' }); + } else if (!estimates.has(roomID)) { + broadcast(roomID, { type: 'estimation-started', message: 'Estimation started again' }); + } + }); + }); + + wss.handleUpgrade(event, event.socket, Buffer.from(''), (ws) => { + wss.emit('connection', ws, event); + }); + + return { + statusCode: 200, + body: 'WebSocket server is running', + }; +}; + +export default { handler }; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index a4ca2ee..687ba6f 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,7 +1,8 @@ -