From 4a481acca68200d62e52a39b75edf77daf590971 Mon Sep 17 00:00:00 2001
From: Tom Vincent <github@tlvince.com>
Date: Wed, 3 Jul 2024 21:27:29 +0100
Subject: [PATCH] fix(server): Postgres -> Redis websocket (#10801)

---
 server/package-lock.json                   | 118 ++++++++++++++-------
 server/package.json                        |   2 +-
 server/src/config.ts                       |   2 +-
 server/src/middleware/websocket.adapter.ts |  11 +-
 4 files changed, 86 insertions(+), 47 deletions(-)

diff --git a/server/package-lock.json b/server/package-lock.json
index 51b691cdaa..cb53bb2117 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -25,7 +25,7 @@
         "@opentelemetry/exporter-prometheus": "^0.52.0",
         "@opentelemetry/sdk-node": "^0.52.0",
         "@react-email/components": "^0.0.19",
-        "@socket.io/postgres-adapter": "^0.3.1",
+        "@socket.io/redis-adapter": "^8.3.0",
         "archiver": "^7.0.0",
         "async-lock": "^1.4.0",
         "bcrypt": "^5.1.1",
@@ -2078,14 +2078,6 @@
       "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz",
       "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug=="
     },
-    "node_modules/@msgpack/msgpack": {
-      "version": "2.8.0",
-      "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz",
-      "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==",
-      "engines": {
-        "node": ">= 10"
-      }
-    },
     "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz",
@@ -5617,21 +5609,20 @@
       "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
       "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
     },
-    "node_modules/@socket.io/postgres-adapter": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/@socket.io/postgres-adapter/-/postgres-adapter-0.3.1.tgz",
-      "integrity": "sha512-8DeSln60sFSdoLL8A8p6nrXlER4lBsvMSAS+G4sqJhudQfGOjhu2AAcKyI/SIDs4p9iO63zTbR4n//ZY0VN2bg==",
+    "node_modules/@socket.io/redis-adapter": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-8.3.0.tgz",
+      "integrity": "sha512-ly0cra+48hDmChxmIpnESKrc94LjRL80TEmZVscuQ/WWkRP81nNj8W8cCGMqbI4L6NCuAaPRSzZF1a9GlAxxnA==",
       "dependencies": {
-        "@msgpack/msgpack": "~2.8.0",
-        "@types/pg": "^8.6.6",
-        "debug": "~4.3.4",
-        "pg": "^8.9.0"
+        "debug": "~4.3.1",
+        "notepack.io": "~3.0.1",
+        "uid2": "1.0.0"
       },
       "engines": {
-        "node": ">=12.0.0"
+        "node": ">=10.0.0"
       },
       "peerDependencies": {
-        "socket.io-adapter": "^2.4.0"
+        "socket.io-adapter": "^2.5.4"
       }
     },
     "node_modules/@sqltools/formatter": {
@@ -12110,6 +12101,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/notepack.io": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-3.0.1.tgz",
+      "integrity": "sha512-TKC/8zH5pXIAMVQio2TvVDTtPRX+DJPHDqjRbxogtFiByHyzKmy96RA0JtCQJ+WouyyL4A10xomQzgbUT+1jCg=="
+    },
     "node_modules/npm-run-path": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
@@ -14906,11 +14902,32 @@
       }
     },
     "node_modules/socket.io-adapter": {
-      "version": "2.5.2",
-      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz",
-      "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==",
+      "version": "2.5.5",
+      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
+      "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
       "dependencies": {
-        "ws": "~8.11.0"
+        "debug": "~4.3.4",
+        "ws": "~8.17.1"
+      }
+    },
+    "node_modules/socket.io-adapter/node_modules/ws": {
+      "version": "8.17.1",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+      "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+      "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/socket.io-client": {
@@ -16372,6 +16389,14 @@
         "node": ">=8"
       }
     },
+    "node_modules/uid2": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/uid2/-/uid2-1.0.0.tgz",
+      "integrity": "sha512-+I6aJUv63YAcY9n4mQreLUt0d4lvwkkopDNmpomkAUz0fAkEMV9pRWxN0EjhW1YfRhcuyHg2v3mwddCDW1+LFQ==",
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
     "node_modules/undici-types": {
       "version": "5.26.5",
       "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
@@ -18254,11 +18279,6 @@
       "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz",
       "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug=="
     },
-    "@msgpack/msgpack": {
-      "version": "2.8.0",
-      "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz",
-      "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ=="
-    },
     "@msgpackr-extract/msgpackr-extract-darwin-arm64": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz",
@@ -20397,15 +20417,14 @@
       "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
       "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
     },
-    "@socket.io/postgres-adapter": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/@socket.io/postgres-adapter/-/postgres-adapter-0.3.1.tgz",
-      "integrity": "sha512-8DeSln60sFSdoLL8A8p6nrXlER4lBsvMSAS+G4sqJhudQfGOjhu2AAcKyI/SIDs4p9iO63zTbR4n//ZY0VN2bg==",
+    "@socket.io/redis-adapter": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-8.3.0.tgz",
+      "integrity": "sha512-ly0cra+48hDmChxmIpnESKrc94LjRL80TEmZVscuQ/WWkRP81nNj8W8cCGMqbI4L6NCuAaPRSzZF1a9GlAxxnA==",
       "requires": {
-        "@msgpack/msgpack": "~2.8.0",
-        "@types/pg": "^8.6.6",
-        "debug": "~4.3.4",
-        "pg": "^8.9.0"
+        "debug": "~4.3.1",
+        "notepack.io": "~3.0.1",
+        "uid2": "1.0.0"
       }
     },
     "@sqltools/formatter": {
@@ -25227,6 +25246,11 @@
       "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
       "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="
     },
+    "notepack.io": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-3.0.1.tgz",
+      "integrity": "sha512-TKC/8zH5pXIAMVQio2TvVDTtPRX+DJPHDqjRbxogtFiByHyzKmy96RA0JtCQJ+WouyyL4A10xomQzgbUT+1jCg=="
+    },
     "npm-run-path": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
@@ -27072,11 +27096,20 @@
       }
     },
     "socket.io-adapter": {
-      "version": "2.5.2",
-      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz",
-      "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==",
+      "version": "2.5.5",
+      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
+      "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
       "requires": {
-        "ws": "~8.11.0"
+        "debug": "~4.3.4",
+        "ws": "~8.17.1"
+      },
+      "dependencies": {
+        "ws": {
+          "version": "8.17.1",
+          "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+          "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+          "requires": {}
+        }
       }
     },
     "socket.io-client": {
@@ -28093,6 +28126,11 @@
         "@lukeed/csprng": "^1.0.0"
       }
     },
+    "uid2": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/uid2/-/uid2-1.0.0.tgz",
+      "integrity": "sha512-+I6aJUv63YAcY9n4mQreLUt0d4lvwkkopDNmpomkAUz0fAkEMV9pRWxN0EjhW1YfRhcuyHg2v3mwddCDW1+LFQ=="
+    },
     "undici-types": {
       "version": "5.26.5",
       "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
diff --git a/server/package.json b/server/package.json
index fe0fdeea69..2111413c29 100644
--- a/server/package.json
+++ b/server/package.json
@@ -51,7 +51,7 @@
     "@opentelemetry/exporter-prometheus": "^0.52.0",
     "@opentelemetry/sdk-node": "^0.52.0",
     "@react-email/components": "^0.0.19",
-    "@socket.io/postgres-adapter": "^0.3.1",
+    "@socket.io/redis-adapter": "^8.3.0",
     "archiver": "^7.0.0",
     "async-lock": "^1.4.0",
     "bcrypt": "^5.1.1",
diff --git a/server/src/config.ts b/server/src/config.ts
index ea4ebf9d50..b2025881bb 100644
--- a/server/src/config.ts
+++ b/server/src/config.ts
@@ -384,7 +384,7 @@ export const immichAppConfig: ConfigModuleOptions = {
   }),
 };
 
-function parseRedisConfig(): RedisOptions {
+export function parseRedisConfig(): RedisOptions {
   const redisUrl = process.env.REDIS_URL;
   if (redisUrl && redisUrl.startsWith('ioredis://')) {
     try {
diff --git a/server/src/middleware/websocket.adapter.ts b/server/src/middleware/websocket.adapter.ts
index 7b97b9f429..4978b16102 100644
--- a/server/src/middleware/websocket.adapter.ts
+++ b/server/src/middleware/websocket.adapter.ts
@@ -1,9 +1,9 @@
 import { INestApplicationContext } from '@nestjs/common';
 import { IoAdapter } from '@nestjs/platform-socket.io';
-import { createAdapter } from '@socket.io/postgres-adapter';
+import { createAdapter } from '@socket.io/redis-adapter';
+import { Redis } from 'ioredis';
 import { ServerOptions } from 'socket.io';
-import { DataSource } from 'typeorm';
-import { PostgresDriver } from 'typeorm/driver/postgres/PostgresDriver.js';
+import { parseRedisConfig } from 'src/config';
 
 export class WebSocketAdapter extends IoAdapter {
   constructor(private app: INestApplicationContext) {
@@ -12,8 +12,9 @@ export class WebSocketAdapter extends IoAdapter {
 
   createIOServer(port: number, options?: ServerOptions): any {
     const server = super.createIOServer(port, options);
-    const pool = (this.app.get(DataSource).driver as PostgresDriver).master;
-    server.adapter(createAdapter(pool));
+    const pubClient = new Redis(parseRedisConfig());
+    const subClient = pubClient.duplicate();
+    server.adapter(createAdapter(pubClient, subClient));
     return server;
   }
 }