From 2032e248a4f3ebb1825794edf5d54a42a9af2e3f Mon Sep 17 00:00:00 2001 From: Process-ing Date: Sat, 9 Nov 2024 13:52:21 +0000 Subject: [PATCH] Add WebSocket integration --- package-lock.json | 86 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + src/api/socket.ts | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 src/api/socket.ts diff --git a/package-lock.json b/package-lock.json index a39122fd..e8e1d14c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "react-router-dom": "^6.3.0", "react-sortablejs": "^6.1.4", "react-toastify": "^9.1.1", + "socket.io-client": "^4.8.0", "sortablejs": "^1.15.2", "swr": "^2.2.5", "tailwind-merge": "^2.2.0", @@ -2137,6 +2138,12 @@ "node": ">= 14" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, "node_modules/@tailwindcss/forms": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", @@ -3768,6 +3775,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/engine.io-client": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.1.tgz", + "integrity": "sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -6670,6 +6699,34 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/socket.io-client": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.0.tgz", + "integrity": "sha512-C0jdhD5yQahMws9alf/yvtsMGTaIDBnZ8Rb5HU56svyq0l5LIrGzIDZZD5pHQlmzxLuU91Gz+VpQMKgCTNYtkw==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sortablejs": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.2.tgz", @@ -7695,6 +7752,35 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz", + "integrity": "sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 31b22fc0..b956abec 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "react-router-dom": "^6.3.0", "react-sortablejs": "^6.1.4", "react-toastify": "^9.1.1", + "socket.io-client": "^4.8.0", "sortablejs": "^1.15.2", "swr": "^2.2.5", "tailwind-merge": "^2.2.0", diff --git a/src/api/socket.ts b/src/api/socket.ts new file mode 100644 index 00000000..3b9b38c9 --- /dev/null +++ b/src/api/socket.ts @@ -0,0 +1,73 @@ +import { io, Socket } from "socket.io-client"; +import backendApi from "./backend"; + +const SOCKET_URL = 'ws://' + backendApi.BACKEND_URL.split('//')[1]; + +class OptionalSocket { + private socket: Socket | null; + + constructor() { + this.socket = null; + } + + set(socket: Socket) { + this.socket = socket; + } + + unset() { + this.socket = null; + } + + use(callback: (socket: Socket) => T): T { + if (!this.socket) { + throw new Error('Socket is not connected'); + } + return callback(this.socket); + } +} + +class SessionsSocket { + private url: string; + private socket: OptionalSocket; + + constructor(url: string) { + this.url = url; + this.socket = new OptionalSocket(); + } + + connect() { + const newSocket = io(this.url, { + auth: { + token: 'dummy', // TODO: Replace with actual federated authentication token + } + }); + this.socket.set(newSocket); + console.log('Connected to socket'); + } + + disconnect() { + this.socket.use(socket => socket.disconnect()); + this.socket.unset(); + + console.log('Disconnected from socket'); + } + + on(event: string, callback: (...args: any[]) => void) { + this.socket.use(socket => socket.on(event, callback)); + } + + off(event: string, callback?: (...args: any[]) => void) { + this.socket.use(socket => socket.off(event, callback)); + } + + emit(event: string, ...args: any[]) { + this.socket.use(socket => socket.emit(event, args)); + } +} + +const sessionsSocket = new SessionsSocket(SOCKET_URL); + +export { + sessionsSocket, + SOCKET_URL, +};