From f431f728059660b43158c2da4723496cc473ce38 Mon Sep 17 00:00:00 2001 From: Thomas Riffard Date: Wed, 18 Dec 2024 23:35:26 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=AE=20Ditch=20mongo,=20add=20Redis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/entities/game.ts | 56 -- back/entities/pool.ts | 17 - back/entities/queuer.ts | 22 - back/main.ts | 11 +- back/npm-shrinkwrap.json | 788 ++---------------- back/package.json | 4 +- back/types/mongo-deserialized.ts | 1 - back/types/mongo-serialized.ts | 5 - back/types/redis-events.ts | 6 + back/utils/create-back-context.ts | 8 +- back/utils/create-data-mapper.ts | 47 +- ...reate-game-with-pool-and-delete-queuers.ts | 45 +- back/utils/create-pool.ts | 22 +- back/utils/create-queuer.ts | 21 +- back/utils/create-redis-client.ts | 11 + back/utils/delete-queuer.ts | 25 +- back/utils/init-mikro.ts | 14 - back/utils/init-mongo.ts | 23 - back/utils/mongo-deserialize.ts | 9 - back/utils/mongo-serialize.ts | 9 - back/utils/observe-created-game.ts | 35 +- back/utils/observe-game.ts | 39 +- back/utils/observe-queuers.ts | 43 +- back/utils/read-all-games.ts | 14 - back/utils/read-and-update-game.ts | 36 +- back/utils/read-and-update-pool-with-game.ts | 48 +- back/utils/read-game.ts | 21 +- back/utils/read-pool.ts | 21 +- back/utils/read-queuers.ts | 21 +- back/utils/update-game.ts | 21 +- compose.yml | 185 +--- core/mocks/create-data-mapper-mock.ts | 3 - core/types/data-mapper.ts | 1 - mongo-config-server/Dockerfile | 5 - mongo-config-server/entrypoint.sh | 35 - mongo-router/Dockerfile | 5 - mongo-router/entrypoint.sh | 64 -- mongo-shard/Dockerfile | 5 - mongo-shard/entrypoint.sh | 33 - 39 files changed, 330 insertions(+), 1449 deletions(-) delete mode 100644 back/entities/game.ts delete mode 100644 back/entities/pool.ts delete mode 100644 back/entities/queuer.ts delete mode 100644 back/types/mongo-deserialized.ts delete mode 100644 back/types/mongo-serialized.ts create mode 100644 back/types/redis-events.ts create mode 100644 back/utils/create-redis-client.ts delete mode 100644 back/utils/init-mikro.ts delete mode 100644 back/utils/init-mongo.ts delete mode 100644 back/utils/mongo-deserialize.ts delete mode 100644 back/utils/mongo-serialize.ts delete mode 100644 back/utils/read-all-games.ts delete mode 100644 mongo-config-server/Dockerfile delete mode 100755 mongo-config-server/entrypoint.sh delete mode 100644 mongo-router/Dockerfile delete mode 100755 mongo-router/entrypoint.sh delete mode 100644 mongo-shard/Dockerfile delete mode 100755 mongo-shard/entrypoint.sh diff --git a/back/entities/game.ts b/back/entities/game.ts deleted file mode 100644 index 5a6bb42..0000000 --- a/back/entities/game.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { Playsig } from "core/types/playsig.js"; -import type { PublicKey } from "core/types/public-key.js"; -import type { Hero } from "core/types/hero.js"; -import type { Appellation } from "core/types/appellation.js"; -import type { Money } from "core/types/money.js"; -import type { Level } from "core/types/level.js"; -import type { Health } from "core/types/health.js"; -import type { Combat } from "core/types/combat.js"; -import type { Phase } from "core/types/phase.js"; -import type { DateTime } from "core/types/date-time.js"; -import { Entity, PrimaryKey, Property, Unique } from "@mikro-orm/core"; - -@Entity() -class Game { - @PrimaryKey() - _id: string; - - @Property() - @Unique() - playsig: Playsig; - - @Property() - publicKeys: PublicKey[]; - - @Property() - nicknames: Record; - - @Property() - playerHeroes: Record; - - @Property() - playerBenches: Record>; - - @Property() - playerShops: Record; - - @Property() - playerMoney: Record; - - @Property() - playerLevel: Record; - - @Property() - playerHealths: Record; - - @Property({ nullable: true }) - combats?: Combat[]; - - @Property() - phase: Phase; - - @Property() - phaseStartAt: DateTime; -} - -export const GameEntity = Game; diff --git a/back/entities/pool.ts b/back/entities/pool.ts deleted file mode 100644 index 54f5652..0000000 --- a/back/entities/pool.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Pool as PoolType } from "core/types/pool.js"; -import { Entity, PrimaryKey, Property, Unique } from "@mikro-orm/core"; - -@Entity() -class Pool { - @PrimaryKey() - _id: string; - - @Property() - @Unique() - playsig: string; - - @Property() - heroes: PoolType["heroes"]; -} - -export const PoolEntity = Pool; diff --git a/back/entities/queuer.ts b/back/entities/queuer.ts deleted file mode 100644 index 6255e78..0000000 --- a/back/entities/queuer.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { PublicKey } from "core/types/public-key.js"; -import type { Nickname } from "core/types/nickname.js"; -import type { DateTime } from "core/types/date-time.js"; -import { Entity, PrimaryKey, Property, Unique } from "@mikro-orm/core"; - -@Entity() -class Queuer { - @PrimaryKey() - _id; - - @Property() - @Unique() - publicKey: PublicKey; - - @Property() - nickname: Nickname; - - @Property() - createdAt: DateTime; -} - -export const QueuerEntity = Queuer; diff --git a/back/main.ts b/back/main.ts index 3598fa7..5cf9e64 100644 --- a/back/main.ts +++ b/back/main.ts @@ -1,17 +1,14 @@ -import { initMikro } from "./utils/init-mikro.js"; -import { initMongo } from "./utils/init-mongo.js"; -import type { Db } from "mongodb"; -import type { MikroORM } from "@mikro-orm/core"; import { createBackContext } from "./utils/create-back-context.js"; import { startServer } from "core/utils/start-server.js"; +import { createRedisClient } from "./utils/create-redis-client.js"; +import { createDataMapper } from "./utils/create-data-mapper.js"; console.log("Server is starting..."); Promise.resolve() .then(async () => { - const db: Db = await initMongo(); - const orm: MikroORM = await initMikro(); - const backContext = await createBackContext(orm, db); + const redis = await createRedisClient(); + const backContext = await createBackContext(redis); startServer(backContext); console.log("\n╭───────────────────╮"); console.log("│ Autochess Backend |"); diff --git a/back/npm-shrinkwrap.json b/back/npm-shrinkwrap.json index 59bf2f6..7909833 100644 --- a/back/npm-shrinkwrap.json +++ b/back/npm-shrinkwrap.json @@ -6,11 +6,9 @@ "": { "devDependencies": { "@biomejs/biome": "^1.9.4", - "@mikro-orm/core": "^6.4.1", - "@mikro-orm/mongodb": "^6.4.1", "@types/node": "^22.10.1", "core": "file:../core", - "mongodb": "^5.9.2", + "redis": "^4.7.0", "rxjs": "^7.8.1", "tinybench": "^3.0.7", "typescript": "^5.7.2", @@ -195,196 +193,69 @@ "node": ">=8" } }, - "node_modules/@mikro-orm/core": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.1.tgz", - "integrity": "sha512-OChUSn2Kx1cGnVo8TcB5J9+6LonVXZCuzK808oD1gnnkmQxWtqFMLO695s4m2jmBGl3LUXXvKfXndagp9v/h7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dataloader": "2.2.3", - "dotenv": "16.4.7", - "esprima": "4.0.1", - "fs-extra": "11.2.0", - "globby": "11.1.0", - "mikro-orm": "6.4.1", - "reflect-metadata": "0.2.2" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/b4nan" - } - }, - "node_modules/@mikro-orm/mongodb": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@mikro-orm/mongodb/-/mongodb-6.4.1.tgz", - "integrity": "sha512-sRvmhTlZxuHdMzqO9at6hu8INIFVUtREbuauQhK7SuqTwXHIefX1d7BGRherZjnCo4hrz40gBz3lJ6AAAhuIEA==", + "node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", "dev": true, "license": "MIT", - "dependencies": { - "bson": "^6.10.0", - "mongodb": "6.11.0" - }, - "engines": { - "node": ">= 18.12.0" - }, "peerDependencies": { - "@mikro-orm/core": "^6.0.0" + "@redis/client": "^1.0.0" } }, - "node_modules/@mikro-orm/mongodb/node_modules/@types/whatwg-url": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", - "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "node_modules/@redis/client": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.0.tgz", + "integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==", "dev": true, "license": "MIT", "dependencies": { - "@types/webidl-conversions": "*" - } - }, - "node_modules/@mikro-orm/mongodb/node_modules/bson": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.1.tgz", - "integrity": "sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.20.1" - } - }, - "node_modules/@mikro-orm/mongodb/node_modules/mongodb": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.11.0.tgz", - "integrity": "sha512-yVbPw0qT268YKhG241vAMLaDQAPbRyTgo++odSgGc9kXnzOujQI60Iyj23B9sQQFPSvmNPvMZ3dsFz0aN55KgA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@mongodb-js/saslprep": "^1.1.9", - "bson": "^6.10.0", - "mongodb-connection-string-url": "^3.0.0" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/@mikro-orm/mongodb/node_modules/mongodb-connection-string-url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", - "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/whatwg-url": "^11.0.2", - "whatwg-url": "^13.0.0" - } - }, - "node_modules/@mikro-orm/mongodb/node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.0" + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" }, "engines": { "node": ">=14" } }, - "node_modules/@mikro-orm/mongodb/node_modules/whatwg-url": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", - "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", - "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", + "node_modules/@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", "dev": true, "license": "MIT", - "dependencies": { - "sparse-bitfield": "^3.0.3" + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 8" + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "@redis/client": "^1.0.0" } }, "node_modules/@types/node": { @@ -397,469 +268,46 @@ "undici-types": "~6.20.0" } }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/webidl-conversions": "*" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bson": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", - "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=14.20.1" + "node": ">=0.10.0" } }, "node_modules/core": { "resolved": "../core", "link": true }, - "node_modules/dataloader": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz", - "integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==", - "dev": true, - "license": "MIT" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", "dev": true, "license": "MIT", "engines": { "node": ">= 4" } }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/redis": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz", + "integrity": "sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mikro-orm": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.1.tgz", - "integrity": "sha512-hRVi5KE1vi4U83RqPcOyVnf+GXcC61jjsRHUuNUMzqYIwElmBubfXZ4Fz/GnKvDtlGcXHnVg2e366wJ++8uOtA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18.12.0" - } - }, - "node_modules/mongodb": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", - "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bson": "^5.5.0", - "mongodb-connection-string-url": "^2.6.0", - "socks": "^2.7.1" - }, - "engines": { - "node": ">=14.20.1" - }, - "optionalDependencies": { - "@mongodb-js/saslprep": "^1.1.0" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.0.0", - "kerberos": "^1.0.0 || ^2.0.0", - "mongodb-client-encryption": ">=2.3.0 <3", - "snappy": "^7.2.2" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - } - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", - "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } + "workspaces": [ + "./packages/*" ], - "license": "MIT" - }, - "node_modules/reflect-metadata": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", "dependencies": { - "queue-microtask": "^1.2.2" + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.0", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" } }, "node_modules/rxjs": { @@ -872,59 +320,6 @@ "tslib": "^2.1.0" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "memory-pager": "^1.0.2" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/tinybench": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-3.0.7.tgz", @@ -935,32 +330,6 @@ "node": ">=18.0.0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -1002,40 +371,6 @@ "dev": true, "license": "MIT" }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", @@ -1057,6 +392,13 @@ "optional": true } } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" } } } diff --git a/back/package.json b/back/package.json index a4e076d..1a69f40 100644 --- a/back/package.json +++ b/back/package.json @@ -6,11 +6,9 @@ }, "devDependencies": { "@biomejs/biome": "^1.9.4", - "@mikro-orm/core": "^6.4.1", - "@mikro-orm/mongodb": "^6.4.1", "@types/node": "^22.10.1", "core": "file:../core", - "mongodb": "^5.9.2", + "redis": "^4.7.0", "rxjs": "^7.8.1", "tinybench": "^3.0.7", "typescript": "^5.7.2", diff --git a/back/types/mongo-deserialized.ts b/back/types/mongo-deserialized.ts deleted file mode 100644 index 959d5f4..0000000 --- a/back/types/mongo-deserialized.ts +++ /dev/null @@ -1 +0,0 @@ -export type MongoDeserialized = Omit; diff --git a/back/types/mongo-serialized.ts b/back/types/mongo-serialized.ts deleted file mode 100644 index b463dfb..0000000 --- a/back/types/mongo-serialized.ts +++ /dev/null @@ -1,5 +0,0 @@ -interface WithObjectId { - _id: string; -} - -export type MongoSerialized = T & WithObjectId; diff --git a/back/types/redis-events.ts b/back/types/redis-events.ts new file mode 100644 index 0000000..a0197ea --- /dev/null +++ b/back/types/redis-events.ts @@ -0,0 +1,6 @@ +export enum RedisEvent { + QueuerJoin = "queuer:join", + QueuerLeave = "queuer:leave", + GameUpdate = "game:update", + GameCreate = "game:create", +} diff --git a/back/utils/create-back-context.ts b/back/utils/create-back-context.ts index d90d15e..f024890 100644 --- a/back/utils/create-back-context.ts +++ b/back/utils/create-back-context.ts @@ -2,16 +2,14 @@ import type { BackContext } from "core/types/back-context.js"; import { createWsServer } from "./create-ws-server.js"; import { debounceTime } from "rxjs"; import { createDataMapper } from "./create-data-mapper.js"; -import type { MikroORM } from "@mikro-orm/core"; -import type { Db } from "mongodb"; import { createRoundTimer } from "core/utils/create-round-timer.js"; import { sign } from "./sign.js"; import { createKeyPair } from "./create-key-pair.js"; import { verify } from "./verify.js"; +import type { RedisClientType } from "redis"; export async function createBackContext( - orm: MikroORM, - db: Db, + redis: RedisClientType, ): Promise { const [serverPublicKey, serverPrivateKey] = await createKeyPair(); @@ -22,7 +20,7 @@ export async function createBackContext( signMessage: (message) => sign(serverPublicKey, serverPrivateKey, message), lateMatchmakingTimer: (source) => source.pipe(debounceTime(3000)), roundTimer: createRoundTimer(), - dataMapper: createDataMapper(orm, db), + dataMapper: createDataMapper(redis), queuerConnections: {}, }; } diff --git a/back/utils/create-data-mapper.ts b/back/utils/create-data-mapper.ts index 66c9760..ef1a86a 100644 --- a/back/utils/create-data-mapper.ts +++ b/back/utils/create-data-mapper.ts @@ -1,6 +1,5 @@ import type { DataMapper } from "core/types/data-mapper.js"; import { readGame } from "./read-game.js"; -import { readAllGames } from "./read-all-games.js"; import { updateGame } from "./update-game.js"; import { readAndUpdateGame } from "./read-and-update-game.js"; import { createGameWithPoolAndDeleteQueuers } from "./create-game-with-pool-and-delete-queuers.js"; @@ -12,33 +11,35 @@ import { createPool } from "./create-pool.js"; import { readAndUpdatePoolWithGame } from "./read-and-update-pool-with-game.js"; import { readQueuers } from "./read-queuers.js"; import { createQueuer } from "./create-queuer.js"; -import type { Db } from "mongodb"; -import type { MikroORM } from "@mikro-orm/core"; -import type { Game } from "core/types/game.js"; -import type { Queuer } from "core/types/queuer.js"; -import type { MongoSerialized } from "../types/mongo-serialized.js"; import { deleteQueuer } from "./delete-queuer.js"; +import type { RedisClientType } from "redis"; +import { Observable, share } from "rxjs"; +import type { RedisEvent } from "../types/redis-events.js"; -export function createDataMapper(orm: MikroORM, db: Db): DataMapper { - const gameCollection = db.collection>("game"); - const queuerCollection = db.collection>("queuer"); +export function createDataMapper(redis: RedisClientType): DataMapper { + const RedisEvents$: Observable<[RedisEvent, string]> = new Observable< + [RedisEvent, string] + >((observer) => { + redis.on("message", (channel, message) => { + observer.next([channel as RedisEvent, message as string]); + }); + }).pipe(share()); return { - readGame: (playsig) => readGame(orm, playsig), - readAllGames: () => readAllGames(orm), - updateGame: (game) => updateGame(orm, game), - readAndUpdateGame: (playsig) => readAndUpdateGame(orm, playsig), + readGame: (playsig) => readGame(redis, playsig), + updateGame: (game) => updateGame(redis, game), + readAndUpdateGame: (playsig) => readAndUpdateGame(redis, playsig), createGameWithPoolAndDeleteQueuers: (game, pool, queuersPublicKeys) => - createGameWithPoolAndDeleteQueuers(orm, game, pool, queuersPublicKeys), - createdGame$: observeCreatedGame(gameCollection), - observeGame: (playsig) => observeGame(gameCollection, playsig), - readPool: (playsig) => readPool(orm, playsig), - createPool: (pool) => createPool(orm, pool), + createGameWithPoolAndDeleteQueuers(redis, game, pool, queuersPublicKeys), + createdGame$: observeCreatedGame(redis, RedisEvents$), + observeGame: (playsig) => observeGame(redis, RedisEvents$, playsig), + readPool: (playsig) => readPool(redis, playsig), + createPool: (pool) => createPool(redis, pool), readAndUpdatePoolWithGame: (playsig) => - readAndUpdatePoolWithGame(orm, playsig), - readQueuers: () => readQueuers(orm), - createQueuer: (queuer) => createQueuer(orm, queuer), - deleteQueuer: (publicKey) => deleteQueuer(orm, publicKey), - queuers$: observeQueuers(orm, queuerCollection), + readAndUpdatePoolWithGame(redis, playsig), + readQueuers: () => readQueuers(redis), + createQueuer: (queuer) => createQueuer(redis, queuer), + deleteQueuer: (publicKey) => deleteQueuer(redis, publicKey), + queuers$: observeQueuers(redis, RedisEvents$), }; } diff --git a/back/utils/create-game-with-pool-and-delete-queuers.ts b/back/utils/create-game-with-pool-and-delete-queuers.ts index 0923c81..ff4a80b 100644 --- a/back/utils/create-game-with-pool-and-delete-queuers.ts +++ b/back/utils/create-game-with-pool-and-delete-queuers.ts @@ -1,37 +1,32 @@ import type { Game } from "core/types/game.js"; -import { GameEntity } from "../entities/game.js"; import type { Pool } from "core/types/pool.js"; -import { PoolEntity } from "../entities/pool.js"; -import { QueuerEntity } from "../entities/queuer.js"; import type { PublicKey } from "core/types/public-key.js"; -import type { MikroORM } from "@mikro-orm/core"; -import { mongoSerialize } from "./mongo-serialize.js"; +import type { RedisClientType } from "redis"; +import { RedisEvent } from "../types/redis-events.js"; export async function createGameWithPoolAndDeleteQueuers( - orm: MikroORM, + redis: RedisClientType, game: Game, pool: Pool, queuersPublicKeys: PublicKey[], ) { - const em = orm.em.fork(); + const gameKey = `game:${game.playsig}`; + const poolKey = `pool:${pool.playsig}`; + const queuersKey = "queuers"; + await redis.watch([queuersKey, gameKey, poolKey]); + const transaction = redis.multi(); + const queuersString = await redis.get(queuersKey); + const queuers = queuersString ? JSON.parse(queuersString) : []; - try { - await em.begin(); - const gameRepository = em.getRepository(GameEntity); - const poolRepository = em.getRepository(PoolEntity); - const queuerRepository = em.getRepository(QueuerEntity); - await gameRepository.create(mongoSerialize(game)); - await poolRepository.create(mongoSerialize(pool)); + const newQueuers = queuers.filter( + (queuer: PublicKey) => !queuersPublicKeys.includes(queuer), + ); - for (const publicKey of queuersPublicKeys) { - await queuerRepository.nativeDelete({ publicKey }); - } - - await em.flush(); - await em.commit(); - return true; - } catch (error) { - await em.rollback(); - throw error; - } + transaction.set(gameKey, JSON.stringify(game)); + transaction.set(poolKey, JSON.stringify(pool)); + transaction.set(queuersKey, JSON.stringify(newQueuers)); + redis.publish(RedisEvent.GameCreate, game.playsig); + redis.publish(RedisEvent.QueuerLeave, ""); + await transaction.exec(); + return true; } diff --git a/back/utils/create-pool.ts b/back/utils/create-pool.ts index 57c6c80..aa7b544 100644 --- a/back/utils/create-pool.ts +++ b/back/utils/create-pool.ts @@ -1,12 +1,18 @@ import type { Pool } from "core/types/pool.js"; -import { PoolEntity } from "../entities/pool.js"; -import type { MikroORM } from "@mikro-orm/core"; -import { mongoSerialize } from "./mongo-serialize.js"; +import type { RedisClientType } from "redis"; -export async function createPool(orm: MikroORM, pool: Pool): Promise { - const em = orm.em.fork(); - const poolRepository = em.getRepository(PoolEntity); - await poolRepository.create(mongoSerialize(pool)); - await em.flush(); +export async function createPool( + redis: RedisClientType, + pool: Pool, +): Promise { + const poolKey = `pool:${pool.playsig}`; + const existingPoolString = await redis.get(poolKey); + + if (existingPoolString !== null) { + return false; + } + + const poolString = JSON.stringify(pool); + await redis.set(poolKey, poolString); return true; } diff --git a/back/utils/create-queuer.ts b/back/utils/create-queuer.ts index d1bfe75..a145717 100644 --- a/back/utils/create-queuer.ts +++ b/back/utils/create-queuer.ts @@ -1,15 +1,20 @@ -import { QueuerEntity } from "../entities/queuer.js"; import type { Queuer } from "core/types/queuer.js"; -import type { MikroORM } from "@mikro-orm/core"; -import { mongoSerialize } from "./mongo-serialize.js"; +import type { RedisClientType } from "redis"; +import { RedisEvent } from "../types/redis-events.js"; export async function createQueuer( - orm: MikroORM, + redis: RedisClientType, queuer: Queuer, ): Promise { - const em = orm.em.fork(); - const queuerRepository = em.getRepository(QueuerEntity); - await queuerRepository.create(mongoSerialize(queuer)); - await em.flush(); + const queuerKey = `queuer:${queuer.publicKey}`; + const existingQueuerString = await redis.get(queuerKey); + + if (existingQueuerString !== null) { + return false; + } + + const queuerString = JSON.stringify(queuer); + await redis.set(queuerKey, queuerString); + redis.publish(RedisEvent.QueuerJoin, ""); return true; } diff --git a/back/utils/create-redis-client.ts b/back/utils/create-redis-client.ts new file mode 100644 index 0000000..4769d43 --- /dev/null +++ b/back/utils/create-redis-client.ts @@ -0,0 +1,11 @@ +import { createClient } from "redis"; +import type { RedisClientType } from "redis"; + +export async function createRedisClient(): Promise { + const client: RedisClientType = createClient({ + url: process.env.REDIS_URL, + }); + + await client.connect(); + return client; +} diff --git a/back/utils/delete-queuer.ts b/back/utils/delete-queuer.ts index dc2ffe8..d4c6187 100644 --- a/back/utils/delete-queuer.ts +++ b/back/utils/delete-queuer.ts @@ -1,18 +1,23 @@ -import { QueuerEntity } from "../entities/queuer.js"; -import type { MikroORM } from "@mikro-orm/core"; import type { PublicKey } from "core/types/public-key.js"; +import type { RedisClientType } from "redis"; +import { RedisEvent } from "../types/redis-events.js"; export async function deleteQueuer( - orm: MikroORM, + redisClient: RedisClientType, publicKey: PublicKey, ): Promise { - try { - const em = orm.em.fork(); - const queuerRepository = em.getRepository(QueuerEntity); - await queuerRepository.nativeDelete({ publicKey }); - await em.flush(); - return true; - } catch (_e) { + const existingQueuerString = await redisClient.get(`queuer:${publicKey}`); + + if (existingQueuerString === null) { return false; } + + const queuers = JSON.parse(existingQueuerString); + + const newQueuers = queuers.filter( + (queuer: PublicKey) => queuer !== publicKey, + ); + + await redisClient.set("queuers", JSON.stringify(newQueuers)); + redisClient.publish(RedisEvent.QueuerLeave, ""); } diff --git a/back/utils/init-mikro.ts b/back/utils/init-mikro.ts deleted file mode 100644 index f3dddac..0000000 --- a/back/utils/init-mikro.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MikroORM } from "@mikro-orm/mongodb"; -import { GameEntity } from "../entities/game.js"; -import { QueuerEntity } from "../entities/queuer.js"; -import { PoolEntity } from "../entities/pool.js"; - -export async function initMikro(): Promise { - const orm = await MikroORM.init({ - entities: [GameEntity, QueuerEntity, PoolEntity], - dbName: process.env.MONGODB_DATABASE, - clientUrl: `mongodb://${process.env.MONGODB_USERNAME}:${process.env.MONGODB_PASSWORD}@mongo-router-node0:27017,mongo-router-node1:27017/?authSource=${process.env.MONGODB_DATABASE}`, - }); - - return orm; -} diff --git a/back/utils/init-mongo.ts b/back/utils/init-mongo.ts deleted file mode 100644 index 4d6aa87..0000000 --- a/back/utils/init-mongo.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MongoClient } from "mongodb"; -import type { Db } from "mongodb"; - -export async function initMongo(): Promise { - const uri = `mongodb://${process.env.MONGODB_USERNAME}:${process.env.MONGODB_PASSWORD}@mongo-router-node0:27017,mongo-router-node1:27017/?authSource=${process.env.MONGODB_DATABASE}`; - let retries = 0; - - while (true) { - try { - const client = new MongoClient(uri); - await client.connect(); - return client.db(process.env.MONGODB_DATABASE); - } catch (e) { - retries++; - - if (retries > 10) { - throw e; - } - - await new Promise((resolve) => setTimeout(resolve, 1000)); - } - } -} diff --git a/back/utils/mongo-deserialize.ts b/back/utils/mongo-deserialize.ts deleted file mode 100644 index 6fd5910..0000000 --- a/back/utils/mongo-deserialize.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; -import type { MongoSerialized } from "../types/mongo-serialized.js"; - -export function mongoDeserialize({ - _id, - ...data -}: MongoSerialized): MongoDeserialized { - return { ...data }; -} diff --git a/back/utils/mongo-serialize.ts b/back/utils/mongo-serialize.ts deleted file mode 100644 index 508a31e..0000000 --- a/back/utils/mongo-serialize.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ObjectId } from "mongodb"; -import type { MongoSerialized } from "../types/mongo-serialized.js"; - -export function mongoSerialize(data: T): MongoSerialized { - return { - ...data, - _id: new ObjectId().toString(), - }; -} diff --git a/back/utils/observe-created-game.ts b/back/utils/observe-created-game.ts index ae0fdc8..7790dfd 100644 --- a/back/utils/observe-created-game.ts +++ b/back/utils/observe-created-game.ts @@ -1,26 +1,23 @@ -import type { Collection } from "mongodb"; -import { Observable, share } from "rxjs"; +import type { Observable } from "rxjs"; import type { Game } from "core/types/game.js"; -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; -import { mongoDeserialize } from "./mongo-deserialize.js"; -import type { MongoSerialized } from "../types/mongo-serialized.js"; +import type { RedisClientType } from "redis"; +import { filter, mergeMap } from "rxjs/operators"; +import { RedisEvent } from "../types/redis-events.js"; export function observeCreatedGame( - gameCollection: Collection>, -): Observable> { - return new Observable>((subscriber) => { - const changeStream = gameCollection.watch([ - { $match: { operationType: "insert" } }, - ]); + redis: RedisClientType, + redisEvents$: Observable<[RedisEvent, string]>, +): Observable { + return redisEvents$.pipe( + filter(([message]) => message === RedisEvent.GameCreate), + mergeMap(async ([_, playsig]) => { + const gameString = await redis.get(`game:${playsig}`); - changeStream.on("change", async (change) => { - if (change.operationType === "insert") { - subscriber.next(mongoDeserialize(change.fullDocument)); + if (!gameString) { + return []; } - }); - return () => { - changeStream.close(); - }; - }).pipe(share()); + return JSON.parse(gameString); + }), + ); } diff --git a/back/utils/observe-game.ts b/back/utils/observe-game.ts index acc86a5..51604c6 100644 --- a/back/utils/observe-game.ts +++ b/back/utils/observe-game.ts @@ -1,28 +1,29 @@ -import type { Collection } from "mongodb"; -import { Observable, share } from "rxjs"; +import type { Observable } from "rxjs"; import type { Game } from "core/types/game.js"; import type { Playsig } from "core/types/playsig.js"; -import { mongoDeserialize } from "./mongo-deserialize.js"; -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; -import type { MongoSerialized } from "../types/mongo-serialized.js"; +import type { RedisClientType } from "redis"; +import { filter, mergeMap } from "rxjs/operators"; +import { RedisEvent } from "../types/redis-events.js"; export function observeGame( - gameCollection: Collection>, + redis: RedisClientType, + redisEvents$: Observable<[RedisEvent, string]>, playsig: Playsig, -): Observable> { - return new Observable>((subscriber) => { - const changeStream = gameCollection.watch([ - { $match: { operationType: "update", "fullDocument.playsig": playsig } }, - ]); +): Observable { + return redisEvents$.pipe( + filter( + ([message, content]) => + message === RedisEvent.GameUpdate && content === playsig, + ), + mergeMap(async () => { + const key = `game:${playsig}`; + const gameString = await redis.get(key); - changeStream.on("change", async (change) => { - if (change.operationType === "update") { - subscriber.next(mongoDeserialize(change.fullDocument)); + if (!gameString) { + return []; } - }); - return () => { - changeStream.close(); - }; - }).pipe(share()); + return JSON.parse(gameString); + }), + ); } diff --git a/back/utils/observe-queuers.ts b/back/utils/observe-queuers.ts index 42b4e90..04139a9 100644 --- a/back/utils/observe-queuers.ts +++ b/back/utils/observe-queuers.ts @@ -1,29 +1,26 @@ import type { Queuer } from "core/types/queuer.js"; -import type { Collection } from "mongodb"; -import { QueuerEntity } from "../entities/queuer.js"; -import { Observable, share } from "rxjs"; -import type { MikroORM } from "@mikro-orm/core"; -import { mongoDeserialize } from "./mongo-deserialize.js"; -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; -import type { MongoSerialized } from "../types/mongo-serialized.js"; +import type { Observable } from "rxjs"; +import type { RedisClientType } from "redis"; +import { filter, mergeMap } from "rxjs/operators"; +import { RedisEvent } from "../types/redis-events.js"; export function observeQueuers( - orm: MikroORM, - queuerCollection: Collection>, -): Observable[]> { - const em = orm.em.fork(); - const queuerRepository = em.getRepository(QueuerEntity); + redis: RedisClientType, + redisEvents$: Observable<[RedisEvent, string]>, +): Observable { + return redisEvents$.pipe( + filter( + ([message]) => + message === RedisEvent.QueuerJoin || message === RedisEvent.QueuerLeave, + ), + mergeMap(async () => { + const queuersString = await redis.get("queuers"); - return new Observable[]>((subscriber) => { - const changeStream = queuerCollection.watch(); + if (!queuersString) { + return []; + } - changeStream.on("change", async () => { - const queuers = await queuerRepository.findAll(); - subscriber.next(queuers.map(mongoDeserialize)); - }); - - return () => { - changeStream.close(); - }; - }).pipe(share()); + return JSON.parse(queuersString); + }), + ); } diff --git a/back/utils/read-all-games.ts b/back/utils/read-all-games.ts deleted file mode 100644 index e83364e..0000000 --- a/back/utils/read-all-games.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Game } from "core/types/game.js"; -import { GameEntity } from "../entities/game.js"; -import type { MikroORM } from "@mikro-orm/core"; -import { mongoDeserialize } from "./mongo-deserialize.js"; -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; - -export async function readAllGames( - orm: MikroORM, -): Promise[]> { - const em = orm.em.fork(); - const gameRepository = em.getRepository(GameEntity); - const games = await gameRepository.findAll(); - return games.map(mongoDeserialize); -} diff --git a/back/utils/read-and-update-game.ts b/back/utils/read-and-update-game.ts index ccdb671..23db548 100644 --- a/back/utils/read-and-update-game.ts +++ b/back/utils/read-and-update-game.ts @@ -1,27 +1,33 @@ import type { Game } from "core/types/game.js"; -import { GameEntity } from "../entities/game.js"; import type { Playsig } from "core/types/playsig.js"; -import type { MikroORM } from "@mikro-orm/core"; -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; -import { mongoDeserialize } from "./mongo-deserialize.js"; +import type { RedisClientType } from "redis"; +import { RedisEvent } from "../types/redis-events.js"; -export async function readAndUpdateGame(orm: MikroORM, playsig: Playsig) { - const em = orm.em.fork(); - await em.begin(); - const gameRepository = em.getRepository(GameEntity); - const _game = await gameRepository.findOneOrFail({ playsig }); - const game: MongoDeserialized = mongoDeserialize(_game); +export async function readAndUpdateGame( + redis: RedisClientType, + playsig: Playsig, +) { + const key = `game:${playsig}`; + await redis.watch(key); + const transaction = redis.multi(); + const gameString = await redis.get(key); + + if (!gameString) { + transaction.discard(); + throw new Error("Game not found !"); + } async function commit(game: Game) { - const affected = await gameRepository.nativeUpdate({ playsig }, game); - await em.flush(); - await em.commit(); - return Boolean(affected); + transaction.set(key, JSON.stringify(game)); + await transaction.exec(); + redis.publish(RedisEvent.GameUpdate, playsig); + return true; } async function abort() { - await em.rollback(); + await transaction.discard(); } + const game: Game = JSON.parse(gameString); return { game, commit, abort }; } diff --git a/back/utils/read-and-update-pool-with-game.ts b/back/utils/read-and-update-pool-with-game.ts index c68490c..7e7cd63 100644 --- a/back/utils/read-and-update-pool-with-game.ts +++ b/back/utils/read-and-update-pool-with-game.ts @@ -1,36 +1,44 @@ import type { Game } from "core/types/game.js"; -import { GameEntity } from "../entities/game.js"; import type { Playsig } from "core/types/playsig.js"; import type { Pool } from "core/types/pool.js"; -import type { MikroORM } from "@mikro-orm/core"; -import { PoolEntity } from "../entities/pool.js"; -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; -import { mongoDeserialize } from "./mongo-deserialize.js"; +import type { RedisClientType } from "redis"; +import { RedisEvent } from "../types/redis-events.js"; export async function readAndUpdatePoolWithGame( - orm: MikroORM, + redis: RedisClientType, playsig: Playsig, ) { - const em = orm.em.fork(); - await em.begin(); - const gameRepository = em.getRepository(GameEntity); - const poolRepository = em.getRepository(PoolEntity); - const _game = await gameRepository.findOneOrFail({ playsig }); - const game: MongoDeserialized = mongoDeserialize(_game); - const _pool = await poolRepository.findOneOrFail({ playsig }); - const pool: MongoDeserialized = mongoDeserialize(_pool); + const key = `pool:${playsig}`; + const gameKey = `game:${playsig}`; + const transaction = redis.multi(); + await redis.watch([key, gameKey]); + const poolString = await redis.get(key); + + if (!poolString) { + transaction.discard(); + throw new Error("Pool not found !"); + } + + const gameString = await redis.get(gameKey); + + if (!gameString) { + transaction.discard(); + throw new Error("Game not found !"); + } async function commit(pool: Pool, game: Game) { - const affected = await gameRepository.nativeUpdate({ playsig }, game); - const affectedPool = await poolRepository.nativeUpdate({ playsig }, pool); - await em.flush(); - await em.commit(); - return Boolean(affected && affectedPool); + transaction.set(key, JSON.stringify(pool)); + transaction.set(gameKey, JSON.stringify(game)); + await transaction.exec(); + redis.publish(RedisEvent.GameUpdate, playsig); + return true; } async function abort() { - await em.rollback(); + await transaction.discard(); } + const game: Game = JSON.parse(gameString); + const pool: Pool = JSON.parse(poolString); return { game, pool, commit, abort }; } diff --git a/back/utils/read-game.ts b/back/utils/read-game.ts index 6c1dd4c..c3f7184 100644 --- a/back/utils/read-game.ts +++ b/back/utils/read-game.ts @@ -1,16 +1,17 @@ import type { Game } from "core/types/game.js"; -import { GameEntity } from "../entities/game.js"; import type { Playsig } from "core/types/playsig.js"; -import type { MikroORM } from "@mikro-orm/core"; -import { mongoDeserialize } from "./mongo-deserialize.js"; -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; +import type { RedisClientType } from "redis"; export async function readGame( - orm: MikroORM, + redis: RedisClientType, playsig: Playsig, -): Promise | undefined> { - const em = orm.em.fork(); - const gameRepository = em.getRepository(GameEntity); - const game = await gameRepository.findOne({ playsig }); - return game ? mongoDeserialize(game) : undefined; +): Promise { + const key = `game:${playsig}`; + const existing = await redis.get(key); + + if (!existing) { + return undefined; + } + + return JSON.parse(existing); } diff --git a/back/utils/read-pool.ts b/back/utils/read-pool.ts index 6ce7f36..61941b7 100644 --- a/back/utils/read-pool.ts +++ b/back/utils/read-pool.ts @@ -1,16 +1,17 @@ import type { Pool } from "core/types/pool.js"; import type { Playsig } from "core/types/playsig.js"; -import type { MikroORM } from "@mikro-orm/core"; -import { PoolEntity } from "../entities/pool.js"; -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; -import { mongoDeserialize } from "./mongo-deserialize.js"; +import type { RedisClientType } from "redis"; export async function readPool( - orm: MikroORM, + redis: RedisClientType, playsig: Playsig, -): Promise | null> { - const em = orm.em.fork(); - const poolRepository = em.getRepository(PoolEntity); - const pool = await poolRepository.findOne({ playsig }); - return mongoDeserialize(pool); +): Promise { + const key = `pool:${playsig}`; + const existing = await redis.get(key); + + if (!existing) { + throw new Error("Pool not found !"); + } + + return JSON.parse(existing); } diff --git a/back/utils/read-queuers.ts b/back/utils/read-queuers.ts index 1514e44..798cfcd 100644 --- a/back/utils/read-queuers.ts +++ b/back/utils/read-queuers.ts @@ -1,14 +1,13 @@ -import { QueuerEntity } from "../entities/queuer.js"; import type { Queuer } from "core/types/queuer.js"; -import type { MikroORM } from "@mikro-orm/core"; -import { mongoDeserialize } from "./mongo-deserialize.js"; -import type { MongoDeserialized } from "../types/mongo-deserialized.js"; +import type { RedisClientType } from "redis"; -export async function readQueuers( - orm: MikroORM, -): Promise[]> { - const em = orm.em.fork(); - const queuerRepository = em.getRepository(QueuerEntity); - const queuers = await queuerRepository.findAll(); - return queuers.map(mongoDeserialize); +export async function readQueuers(redis: RedisClientType): Promise { + const key = "queuers"; + const existing = await redis.get(key); + + if (!existing) { + return []; + } + + return JSON.parse(existing); } diff --git a/back/utils/update-game.ts b/back/utils/update-game.ts index 2994ac5..e1c5f0f 100644 --- a/back/utils/update-game.ts +++ b/back/utils/update-game.ts @@ -1,16 +1,19 @@ import type { Game } from "core/types/game.js"; -import { GameEntity } from "../entities/game.js"; -import type { MikroORM } from "@mikro-orm/core"; +import type { RedisClientType } from "redis"; +import { RedisEvent } from "../types/redis-events.js"; -export async function updateGame(orm: MikroORM, game: Game): Promise { - const em = orm.em.fork(); - const gameRepository = em.getRepository(GameEntity); - const playsig = game.playsig; +export async function updateGame( + redis: RedisClientType, + game: Game, +): Promise { + const key = `game:${game.playsig}`; + const existing = await redis.get(key); - if (!playsig) { + if (!existing) { return false; } - const affected = await gameRepository.nativeUpdate({ playsig }, game); - return Boolean(affected); + await redis.set(key, JSON.stringify(game)); + redis.publish(RedisEvent.GameUpdate, game.playsig); + return true; } diff --git a/compose.yml b/compose.yml index ab17d0f..32c36d0 100644 --- a/compose.yml +++ b/compose.yml @@ -54,164 +54,6 @@ services: depends_on: - core - mongo-config-server-node0: - build: mongo-config-server - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: example - REPLICASET: configsvrRs - NODE_0: mongo-config-server-node0 - NODE_1: mongo-config-server-node1 - NODE_2: mongo-config-server-node2 - IS_REPLICA_SET_INITIATOR: true - volumes: - - mongo-config-server-node0-data:/data/db - - mongo-config-server-node0-config:/data/configdb - - mongo-config-server-node1: - build: mongo-config-server - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: example - REPLICASET: configsvrRs - NODE_0: mongo-config-server-node0 - NODE_1: mongo-config-server-node1 - NODE_2: mongo-config-server-node2 - volumes: - - mongo-config-server-node1-data:/data/db - - mongo-config-server-node1-config:/data/configdb - - mongo-config-server-node2: - build: mongo-config-server - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: example - REPLICASET: configsvrRs - NODE_0: mongo-config-server-node0 - NODE_1: mongo-config-server-node1 - NODE_2: mongo-config-server-node2 - volumes: - - mongo-config-server-node2-data:/data/db - - mongo-config-server-node2-config:/data/configdb - - mongo-shard0-node0: - build: mongo-shard - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: example - REPLICASET: shard0rs - NODE_0: mongo-shard0-node0 - NODE_1: mongo-shard0-node1 - IS_REPLICA_SET_INITIATOR: true - volumes: - - mongo-shard0-node0-data:/data/db - - mongo-shard0-node0-config:/data/configdb - - mongo-shard0-node1: - build: mongo-shard - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: example - REPLICASET: shard0rs - NODE_0: mongo-shard0-node0 - NODE_1: mongo-shard0-node1 - volumes: - - mongo-shard0-node1-data:/data/db - - mongo-shard0-node1-config:/data/configdb - - mongo-shard1-node0: - build: mongo-shard - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: example - REPLICASET: shard1rs - NODE_0: mongo-shard1-node0 - NODE_1: mongo-shard1-node1 - IS_REPLICA_SET_INITIATOR: true - volumes: - - mongo-shard1-node0-data:/data/db - - mongo-shard1-node0-config:/data/configdb - - mongo-shard1-node1: - build: mongo-shard - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: example - REPLICASET: shard1rs - NODE_0: mongo-shard1-node0 - NODE_1: mongo-shard1-node1 - volumes: - - mongo-shard1-node1-data:/data/db - - mongo-shard1-node1-config:/data/configdb - - mongo-router-node0: - build: mongo-router - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: example - DB_USERNAME: user - DB_PASSWORD: example - MONGO_INITDB_DATABASE: autochess - NODE_0: mongo-router-node0 - NODE_1: mongo-router-node1 - SHARD_REPLICA_SET_0: shard0rs - SHARD_REPLICA_SET_1: shard1rs - SHARD_0_NODE_0: mongo-shard0-node0 - SHARD_0_NODE_1: mongo-shard0-node1 - SHARD_1_NODE_0: mongo-shard1-node0 - SHARD_1_NODE_1: mongo-shard1-node1 - IS_SHARDING_INITIATOR: true - CONFIG_SERVER_REPLICA_SET: configsvrRs - CONFIG_SERVER_NODE_0: mongo-config-server-node0 - CONFIG_SERVER_NODE_1: mongo-config-server-node1 - CONFIG_SERVER_NODE_2: mongo-config-server-node2 - depends_on: - - mongo-config-server-node0 - - mongo-config-server-node1 - - mongo-config-server-node2 - - mongo-shard0-node0 - - mongo-shard0-node1 - - mongo-shard1-node0 - - mongo-shard1-node1 - volumes: - - mongo-router-node0-data:/data/db - - mongo-router-node0-config:/data/configdb - ports: - - "27017:27017" - - mongo-router-node1: - build: mongo-router - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: example - DB_USERNAME: user - DB_PASSWORD: example - MONGO_INITDB_DATABASE: autochess - NODE_0: mongo-router-node0 - NODE_1: mongo-router-node1 - SHARD_REPLICA_SET_0: shard0rs - SHARD_REPLICA_SET_1: shard1rs - SHARD_0_NODE_0: mongo-shard0-node0 - SHARD_0_NODE_1: mongo-shard0-node1 - SHARD_1_NODE_0: mongo-shard1-node0 - SHARD_1_NODE_1: mongo-shard1-node1 - CONFIG_SERVER_REPLICA_SET: configsvrRs - CONFIG_SERVER_NODE_0: mongo-config-server-node0 - CONFIG_SERVER_NODE_1: mongo-config-server-node1 - CONFIG_SERVER_NODE_2: mongo-config-server-node2 - depends_on: - - mongo-config-server-node0 - - mongo-config-server-node1 - - mongo-config-server-node2 - - mongo-shard0-node0 - - mongo-shard0-node1 - - mongo-shard1-node0 - - mongo-shard1-node1 - volumes: - - mongo-router-node1-data:/data/db - - mongo-router-node1-config:/data/configdb - ports: - - "27018:27017" back: build: back @@ -220,12 +62,15 @@ services: MONGODB_PASSWORD: example MONGODB_DATABASE: autochess VITE_WEBSOCKET_PROTOCOL: ${VITE_WEBSOCKET_PROTOCOL} + REDIS_URL: redis://database ports: - ${VITE_WEBSOCKET_PORT}:3000 depends_on: - core - - mongo-router-node0 - - mongo-router-node1 + - database + + database: + image: redis ingame: build: @@ -244,23 +89,3 @@ services: - back - core - interface - -volumes: - mongo-config-server-node0-data: - mongo-config-server-node0-config: - mongo-config-server-node1-data: - mongo-config-server-node1-config: - mongo-config-server-node2-data: - mongo-config-server-node2-config: - mongo-shard0-node0-data: - mongo-shard0-node0-config: - mongo-shard0-node1-data: - mongo-shard0-node1-config: - mongo-shard1-node0-data: - mongo-shard1-node0-config: - mongo-shard1-node1-data: - mongo-shard1-node1-config: - mongo-router-node0-data: - mongo-router-node0-config: - mongo-router-node1-data: - mongo-router-node1-config: \ No newline at end of file diff --git a/core/mocks/create-data-mapper-mock.ts b/core/mocks/create-data-mapper-mock.ts index 83bb515..3da78c1 100644 --- a/core/mocks/create-data-mapper-mock.ts +++ b/core/mocks/create-data-mapper-mock.ts @@ -32,9 +32,6 @@ export function createDataMapperMock(): DataMapper { return { readGame, - async readAllGames() { - return structuredClone(games); - }, async readAndUpdateGame(playsig: string) { const game = structuredClone( games.find((game) => game.playsig === playsig), diff --git a/core/types/data-mapper.ts b/core/types/data-mapper.ts index a35e4f4..6623501 100644 --- a/core/types/data-mapper.ts +++ b/core/types/data-mapper.ts @@ -20,7 +20,6 @@ interface ReadAndUpdateGame { export interface DataMapper { readGame(playsig: string): Promise; - readAllGames(): Promise; updateGame(game: Game): Promise; readAndUpdateGame(playsig: Playsig): Promise; createGameWithPoolAndDeleteQueuers( diff --git a/mongo-config-server/Dockerfile b/mongo-config-server/Dockerfile deleted file mode 100644 index 22ea85f..0000000 --- a/mongo-config-server/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM mongo -RUN mkdir -p /etc/mongodb/pki -RUN openssl rand -base64 756 > /etc/mongodb/pki/keyfile && chmod 400 /etc/mongodb/pki/keyfile -COPY ./entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/mongo-config-server/entrypoint.sh b/mongo-config-server/entrypoint.sh deleted file mode 100755 index abe64de..0000000 --- a/mongo-config-server/entrypoint.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -set -e - -function start_mongodb { - mongod --configsvr --replSet "$REPLICASET" --bind_ip_all --logpath /dev/null -} - -function mongo_is_ready { - echo "Waiting for mongo config server to be ready..." - mongosh --port 27019 --eval "print(\"Mongo config server is ready\")" -} - -function initiate_replica_set { - mongosh --port 27019 --eval " - rs.initiate({ - _id: '$REPLICASET', - configsvr: true, - members: [ - {_id: 0, host: '$NODE_0:27019'}, - {_id: 1, host: '$NODE_1:27019'}, - {_id: 2, host: '$NODE_2:27019'} - ] - }) - - console.log('Replica set initiated'); - " -} - -start_mongodb & - -until mongo_is_ready; do sleep 1; done - -if [ "$IS_REPLICA_SET_INITIATOR" = "true" ]; then initiate_replica_set; fi - -sleep infinity \ No newline at end of file diff --git a/mongo-router/Dockerfile b/mongo-router/Dockerfile deleted file mode 100644 index 22ea85f..0000000 --- a/mongo-router/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM mongo -RUN mkdir -p /etc/mongodb/pki -RUN openssl rand -base64 756 > /etc/mongodb/pki/keyfile && chmod 400 /etc/mongodb/pki/keyfile -COPY ./entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/mongo-router/entrypoint.sh b/mongo-router/entrypoint.sh deleted file mode 100755 index 7a6153f..0000000 --- a/mongo-router/entrypoint.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -set -e - -function start_mongodb { - mongos --configdb "$CONFIG_SERVER_REPLICA_SET/$CONFIG_SERVER_NODE_0:27019,$CONFIG_SERVER_NODE_1:27019,$CONFIG_SERVER_NODE_2:27019" --bind_ip_all --logpath /dev/null -} - -function mongo_is_ready { - echo "Waiting for mongo router to be ready..." - mongosh --eval "print(\"Mongo router is ready\")" -} - -function create_user_if_initiator { - mongosh --eval " - if ('$IS_SHARDING_INITIATOR' == 'true') { - console.log('creating user'); - - db = db.getSiblingDB(process.env.MONGO_INITDB_DATABASE) - - db.createUser({ - user: process.env.DB_USERNAME, - pwd: process.env.DB_PASSWORD, - roles: [{ role: 'readWrite', db: process.env.MONGO_INITDB_DATABASE }] - }, { w: 'majority', wtimeout: 5000 }); - - console.log('User created'); - } - " -} - -add_shards_to_router_if_initiator() { - mongosh --eval " - if ('$IS_SHARDING_INITIATOR' == 'true') { - sh.addShard('$SHARD_REPLICA_SET_0/$SHARD_0_NODE_0:27018,$SHARD_0_NODE_1:27018') - sh.addShard('$SHARD_REPLICA_SET_1/$SHARD_1_NODE_0:27018,$SHARD_1_NODE_1:27018') - } - " -} - -enable_sharding() { - mongosh --eval " - if ('$IS_SHARDING_INITIATOR' == 'true') { - console.log('initiating sharding'); - sh.enableSharding('$MONGO_INITDB_DATABASE') - sh.shardCollection('${MONGO_INITDB_DATABASE}.queuer', { _id: 'hashed' }) - sh.shardCollection('${MONGO_INITDB_DATABASE}.pool', { _id: 'hashed' }) - sh.shardCollection('${MONGO_INITDB_DATABASE}.game', { _id: 'hashed' }) - console.log('Added shard to router'); - } - " -} - - -start_mongodb & - -until mongo_is_ready; do sleep 4; done - -add_shards_to_router_if_initiator - -enable_sharding - -create_user_if_initiator - -sleep infinity \ No newline at end of file diff --git a/mongo-shard/Dockerfile b/mongo-shard/Dockerfile deleted file mode 100644 index 22ea85f..0000000 --- a/mongo-shard/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM mongo -RUN mkdir -p /etc/mongodb/pki -RUN openssl rand -base64 756 > /etc/mongodb/pki/keyfile && chmod 400 /etc/mongodb/pki/keyfile -COPY ./entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/mongo-shard/entrypoint.sh b/mongo-shard/entrypoint.sh deleted file mode 100755 index d632b46..0000000 --- a/mongo-shard/entrypoint.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -set -e - -function start_mongodb { - mongod --shardsvr --replSet "$REPLICASET" --bind_ip_all --logpath /dev/null -} - -function mongo_is_ready { - echo "Waiting for mongo shard to be ready..." - mongosh --port 27018 --eval "print(\"Mongo shard is ready.\")" -} - -function initiate_replica_set { - mongosh --port 27018 --eval " - rs.initiate({ - _id: '$REPLICASET', - members: [ - {_id: 0, host: '$NODE_0:27018'}, - {_id: 1, host: '$NODE_1:27018'} - ] - }) - - console.log('Replica set initiated'); - " -} - -start_mongodb & - -until mongo_is_ready; do sleep 1; done - -if [ "$IS_REPLICA_SET_INITIATOR" = "true" ]; then initiate_replica_set; fi - -sleep infinity \ No newline at end of file