diff --git a/lib b/lib index 61c9d61..a957a29 160000 --- a/lib +++ b/lib @@ -1 +1 @@ -Subproject commit 61c9d61229a18f5b484a7927bc343650024efc96 +Subproject commit a957a29498d6b9c3b121f8e27e43ad73d9342075 diff --git a/package.json b/package.json index 8b2a639..0374bd8 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,10 @@ "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-node-resolve": "^13.1.3", "@types/ws": "^8.2.2", - "rollup": "^2.63.0", + "rollup": "^2.64.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript2": "^0.31.1", "typescript": "^4.5.4", - "ws": "^8.4.1" + "ws": "^8.4.2" } } diff --git a/server.node.ts b/server.node.ts index e6792f7..c74f53d 100644 --- a/server.node.ts +++ b/server.node.ts @@ -8,16 +8,19 @@ import type { AckMessage, IdResponseMessage, TextMessage, + TypingMessage, } from "./lib/ServerMessage"; import { isServerMessage, isTextMessage, + isTypingMessage, MessageType, } from "./lib/ServerMessage"; const port = 8085; const timeout = 15000; +const typingTimeout = 2000; const httpsServer = https.createServer({ key: fs.readFileSync("./key.pem"), @@ -25,6 +28,10 @@ const httpsServer = https.createServer({ }); const webSocketServer = new WebSocketServer({ server: httpsServer }); +/* If not using SSL/TLS +const webSocketServer = new WebSocketServer({ port }); +*/ + console.log("listening on port: " + port); async function handleTextMessage(message: TextMessage, from: string) { @@ -39,12 +46,47 @@ async function handleTextMessage(message: TextMessage, from: string) { } } +const activeConnections = new Set(); +const currentlyTyping = new Set(); +const currentlyTypingTimeouts = new Map>(); + +async function handleTypingMessage(_message: TypingMessage, from: string) { + currentlyTyping.add(from); + + if(currentlyTypingTimeouts.has(from)) { + clearTimeout(currentlyTypingTimeouts.get(from)!); + } + currentlyTypingTimeouts.set(from, setTimeout(() => { + currentlyTyping.delete(from); + currentlyTypingTimeouts.delete(from); + sendCurrentlyTypingMessage(from, true); + }, typingTimeout)); + sendCurrentlyTypingMessage(from); +} + +async function sendCurrentlyTypingMessage(from?: string, stopped = false) { + for (const to of webSocketServer.clients) { + to.send( + JSON.stringify( + Object.assign({ + type: MessageType.CURRENTLY_TYPING, + date: Date.now(), + }, { + currently: Array.from(currentlyTyping.values()), + }, from === undefined ? { + __ctx: "regular update", + } : { + __ctx: from + (stopped ? " stopped typing" : " started typing"), + }) + ) + ) + } +} + async function handleCloseConnection(id: string) { activeConnections.delete(id); } -const activeConnections = new Set(); - webSocketServer.on("connection", function connection(socket) { const close = (reason: string, code: number = 1000) => { socket.send( @@ -71,6 +113,8 @@ webSocketServer.on("connection", function connection(socket) { if (message.author === authorId) { handleTextMessage(message, authorId); } + } else if (isTypingMessage(message)) { + handleTypingMessage(message, authorId); } clearTimeout(closeTimeout); diff --git a/yarn.lock b/yarn.lock index dadf956..d99e198 100644 --- a/yarn.lock +++ b/yarn.lock @@ -84,9 +84,9 @@ integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== "@types/node@*": - version "17.0.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b" - integrity sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg== + version "17.0.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.9.tgz#0b7f161afb5b1cc12518d29b2cdc7175d5490628" + integrity sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ== "@types/resolve@1.17.1": version "1.17.1" @@ -513,10 +513,10 @@ rollup-plugin-typescript2@^0.31.1: resolve "1.20.0" tslib "2.2.0" -rollup@^2.63.0: - version "2.63.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.63.0.tgz#fe2f7fec2133f3fab9e022b9ac245628d817c6bb" - integrity sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ== +rollup@^2.64.0: + version "2.64.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.64.0.tgz#f0f59774e21fbb56de438a37d06a2189632b207a" + integrity sha512-+c+lbw1lexBKSMb1yxGDVfJ+vchJH3qLbmavR+awDinTDA2C5Ug9u7lkOzj62SCu0PKUExsW36tpgW7Fmpn3yQ== optionalDependencies: fsevents "~2.3.2" @@ -635,10 +635,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@^8.4.1: - version "8.4.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.1.tgz#ce1a17e553d2b794e017fa94887808db5c67f614" - integrity sha512-6eqQ4yN2y2xv8b+BgbkUzPPyfo/PDl3VOWb06ZE0jIFYwuHMsMQN6F7o84yxJYCblfCRAxzpU59We4Rr4w0Luw== +ws@^8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b" + integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA== yocto-queue@^0.1.0: version "0.1.0"