Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a redis backend to socket.io #1

Open
2 tasks
Nainterceptor opened this issue Apr 24, 2023 · 1 comment
Open
2 tasks

Add a redis backend to socket.io #1

Nainterceptor opened this issue Apr 24, 2023 · 1 comment
Assignees

Comments

@Nainterceptor
Copy link

  • When environment variable BACKEND_REDIS_URL exists, the redis backend should be used to sync rooms
  • When environment variable BACKEND_REDIS_URL doesn't exists, behavior shouldn't be changed
@Nainterceptor
Copy link
Author

https://github.com/excalidraw/excalidraw/blob/master/package.json#L54 is using fixed version for socket io client, so we have to use old version I guess.

Suggest to fix current version and add carets
diff --git a/package.json b/package.json
index b7fc91a..6704830 100644
--- a/package.json
+++ b/package.json
@@ -1,24 +1,24 @@
 {
   "dependencies": {
-    "@excalidraw/eslint-config": "1.0.1",
-    "@excalidraw/prettier-config": "1.0.2",
-    "@types/debug": "4.1.5",
-    "@types/express": "4.17.11",
-    "@types/node": "14.14.31",
-    "@types/socket.io": "2.1.4",
-    "@typescript-eslint/eslint-plugin": "4.16.1",
-    "@typescript-eslint/parser": "4.16.1",
+    "@excalidraw/eslint-config": "^1.0.1",
+    "@excalidraw/prettier-config": "^1.0.2",
+    "@types/debug": "^4.1.5",
+    "@types/express": "^4.17.11",
+    "@types/node": "^14.14.31",
+    "@types/socket.io": "^2.1.4",
+    "@typescript-eslint/eslint-plugin": "^4.16.1",
+    "@typescript-eslint/parser": "^4.16.1",
     "cross-env": "^7.0.3",
-    "debug": "4.3.1",
+    "debug": "^4.3.1",
     "dotenv": "^10.0.0",
-    "eslint": "7.21.0",
-    "eslint-config-prettier": "8.1.0",
-    "eslint-plugin-prettier": "3.3.1",
-    "express": "4.17.1",
-    "prettier": "2.2.1",
-    "socket.io": "2.3.0",
+    "eslint": "^7.21.0",
+    "eslint-config-prettier": "^8.1.0",
+    "eslint-plugin-prettier": "^3.3.1",
+    "express": "^4.17.1",
+    "prettier": "^2.2.1",
+    "socket.io": "^2.3.0",
     "ts-node-dev": "^1.1.8",
-    "typescript": "4.2.3"
+    "typescript": "^4.2.3"
   },
   "license": "MIT",
   "main": "dist/index.js",
diff --git a/src/index.ts b/src/index.ts
index 6c9da5e..c8e956e 100755
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,6 @@
 import debug from "debug";
 import express from "express";
-import http from "http";
+import http, { OutgoingHttpHeaders } from "http";
 import socketIO from "socket.io";
 
 const serverDebug = debug("server");
@@ -30,11 +30,11 @@ server.listen(port, () => {
 
 const io = socketIO(server, {
   handlePreflightRequest: (req, res) => {
-    const headers = {
+    const headers: OutgoingHttpHeaders = {
       "Access-Control-Allow-Headers": "Content-Type, Authorization",
       "Access-Control-Allow-Origin":
-        (req.header && req.header.origin) || "https://excalidraw.com",
-      "Access-Control-Allow-Credentials": true,
+        (req.headers && req.headers.origin) || "https://excalidraw.com",
+      "Access-Control-Allow-Credentials": "true",
     };
     res.writeHead(200, headers);
     res.end();
Suggest to update socket io server and add redis support
diff --git a/package.json b/package.json
index b7fc91a..47d44de 100644
--- a/package.json
+++ b/package.json
@@ -1,24 +1,26 @@
 {
   "dependencies": {
-    "@excalidraw/eslint-config": "1.0.1",
-    "@excalidraw/prettier-config": "1.0.2",
-    "@types/debug": "4.1.5",
-    "@types/express": "4.17.11",
-    "@types/node": "14.14.31",
-    "@types/socket.io": "2.1.4",
-    "@typescript-eslint/eslint-plugin": "4.16.1",
-    "@typescript-eslint/parser": "4.16.1",
+    "@excalidraw/eslint-config": "^1.0.1",
+    "@excalidraw/prettier-config": "^1.0.2",
+    "@socket.io/redis-adapter": "^8.1.0",
+    "@types/debug": "^4.1.5",
+    "@types/express": "^4.17.11",
+    "@types/node": "^14.14.31",
+    "@types/socket.io": "^2.1.4",
+    "@typescript-eslint/eslint-plugin": "^4.16.1",
+    "@typescript-eslint/parser": "^4.16.1",
     "cross-env": "^7.0.3",
-    "debug": "4.3.1",
+    "debug": "^4.3.1",
     "dotenv": "^10.0.0",
-    "eslint": "7.21.0",
-    "eslint-config-prettier": "8.1.0",
-    "eslint-plugin-prettier": "3.3.1",
-    "express": "4.17.1",
-    "prettier": "2.2.1",
-    "socket.io": "2.3.0",
+    "eslint": "^7.21.0",
+    "eslint-config-prettier": "^8.1.0",
+    "eslint-plugin-prettier": "^3.3.1",
+    "express": "^4.17.1",
+    "prettier": "^2.2.1",
+    "redis": "^4.6.6",
+    "socket.io": "^4.6.1",
     "ts-node-dev": "^1.1.8",
-    "typescript": "4.2.3"
+    "typescript": "^4.2.3"
   },
   "license": "MIT",
   "main": "dist/index.js",
diff --git a/src/index.ts b/src/index.ts
index 6c9da5e..fb6d0b8 100755
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,7 +1,9 @@
 import debug from "debug";
 import express from "express";
 import http from "http";
-import socketIO from "socket.io";
+import { Server } from "socket.io";
+import { createAdapter } from "@socket.io/redis-adapter";
+import Redis from "redis";
 
 const serverDebug = debug("server");
 const ioDebug = debug("io");
@@ -24,20 +26,28 @@ app.get("/", (req, res) => {
 
 const server = http.createServer(app);
 
-server.listen(port, () => {
-  serverDebug(`listening on port: ${port}`);
-});
+let adapterOptions = {};
 
-const io = socketIO(server, {
-  handlePreflightRequest: (req, res) => {
-    const headers = {
-      "Access-Control-Allow-Headers": "Content-Type, Authorization",
-      "Access-Control-Allow-Origin":
-        (req.header && req.header.origin) || "https://excalidraw.com",
-      "Access-Control-Allow-Credentials": true,
-    };
-    res.writeHead(200, headers);
-    res.end();
+if (process.env.REDIS_URL) {
+  const pubClient = Redis.createClient({ url: process.env.REDIS_URL });
+  const subClient = pubClient.duplicate();
+
+  adapterOptions = {
+    adapter: createAdapter(pubClient, subClient),
+  };
+}
+
+const io = new Server(server, {
+  ...adapterOptions,
+  cors: {
+    origin: (origin, callback) => {
+      if (!origin || origin === "https://excalidraw.com") {
+        callback(null, true);
+      } else {
+        callback(new Error("Not allowed by CORS"));
+      }
+    },
+    credentials: true,
   },
 });
 
@@ -47,15 +57,13 @@ io.on("connection", (socket) => {
   socket.on("join-room", (roomID) => {
     socketDebug(`${socket.id} has joined ${roomID}`);
     socket.join(roomID);
-    if (io.sockets.adapter.rooms[roomID].length <= 1) {
+    const sessions = Array.from(io.sockets.adapter.rooms.get(roomID) ?? []);
+    if (sessions.length <= 1) {
       io.to(`${socket.id}`).emit("first-in-room");
     } else {
       socket.broadcast.to(roomID).emit("new-user", socket.id);
     }
-    io.in(roomID).emit(
-      "room-user-change",
-      Object.keys(io.sockets.adapter.rooms[roomID].sockets),
-    );
+    io.in(roomID).emit("room-user-change", Object.keys(sessions));
   });
 
   socket.on(
@@ -79,7 +87,7 @@ io.on("connection", (socket) => {
   socket.on("disconnecting", () => {
     const rooms = io.sockets.adapter.rooms;
     for (const roomID in socket.rooms) {
-      const clients = Object.keys(rooms[roomID].sockets).filter(
+      const clients = Array.from(rooms.get(roomID) ?? []).filter(
         (id) => id !== socket.id,
       );
       if (clients.length > 0) {
@@ -92,3 +100,7 @@ io.on("connection", (socket) => {
     socket.removeAllListeners();
   });
 });
+
+server.listen(port, () => {
+  serverDebug(`listening on port: ${port}`);
+});

Upgrade is not working cause of outdated socket io client on excalidraw main repo.
Both solutions are not working locally, cause of unmaintained repo ? (Twitter)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants