From 9ee790ebbb7232395489d64e4af5550239e2fa85 Mon Sep 17 00:00:00 2001 From: AlexMog Date: Fri, 25 Dec 2020 03:55:28 +0100 Subject: [PATCH 1/3] Cache and started rabbitMQ messenger --- .gitignore | 4 +- package.json | 12 +- src/cache/Cache.ts | 17 + src/cache/RedisCache.ts | 46 ++ src/index.ts | 86 +++- src/manager/PlayerSessionsManager.ts | 17 + src/messaging/Messenger.ts | 30 ++ src/messaging/RabbitmqMessenger.ts | 15 + src/model/Player.ts | 6 + tsconfig.json | 3 +- yarn-error.log | 742 ++++++++++++++++++++++++--- yarn.lock | 250 +++++++-- 12 files changed, 1091 insertions(+), 137 deletions(-) create mode 100644 src/cache/Cache.ts create mode 100644 src/cache/RedisCache.ts create mode 100644 src/manager/PlayerSessionsManager.ts create mode 100644 src/messaging/Messenger.ts create mode 100644 src/messaging/RabbitmqMessenger.ts create mode 100644 src/model/Player.ts diff --git a/.gitignore b/.gitignore index 763301f..ea6fe27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ dist/ -node_modules/ \ No newline at end of file +node_modules/ +.idea/ +*.iml diff --git a/package.json b/package.json index 6cf95e7..d483613 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,16 @@ "main": "index.js", "license": "GPL-3.0-or-later", "dependencies": { + "amqplib": "^0.6.0", "express": "^4.17.1", "morgan": "^1.10.0", "public-ip": "^4.0.2", "pug": "^3.0.0", + "redis": "^3.0.2", + "redlock": "^4.2.0", "socket.io": "^2.3.0", - "tracer": "^1.1.4" + "tracer": "^1.1.4", + "uuid": "^8.3.2" }, "scripts": { "start": "yarn compile && node dist/index.js", @@ -17,9 +21,13 @@ "postinstall": "yarn compile" }, "devDependencies": { - "@types/express": "^4.17.8", + "@types/amqplib": "^0.5.16", + "@types/express": "^4.17.9", "@types/morgan": "^1.9.2", + "@types/public-ip": "^3.1.0", + "@types/redis": "^2.8.28", "@types/socket.io": "^2.1.11", + "@types/uuid": "^8.3.0", "typescript": "^4.0.5" } } diff --git a/src/cache/Cache.ts b/src/cache/Cache.ts new file mode 100644 index 0000000..84c062c --- /dev/null +++ b/src/cache/Cache.ts @@ -0,0 +1,17 @@ +import {Player} from "../model/Player"; + +export interface Cache { + /** + * Retrieve room players + * @param roomId The roomID to retrieve players from + */ + retrieveRoomPlayers(roomId: string): Promise>; + + /** + * Add a player to a room + * @param roomId The room to add the player in + * @param player The player's data + */ + addPlayerToRoom(roomId: string, player: Player): Promise; + removePlayerFromRoom(roomId: string, playerId: string): Promise; +} diff --git a/src/cache/RedisCache.ts b/src/cache/RedisCache.ts new file mode 100644 index 0000000..e2de812 --- /dev/null +++ b/src/cache/RedisCache.ts @@ -0,0 +1,46 @@ +import {Cache} from "./Cache"; +import {Player} from "../model/Player"; +import Redis, {RedisClient} from "redis"; + +export class RedisCache implements Cache { + private readonly ROOM_KEY_PRE = process.env.REDIS_ROOM_KEY_PRE || "crewlink:room:"; + private readonly redis: RedisClient; + + constructor(redisUrl: string) { + this.redis = Redis.createClient(redisUrl); + } + + async addPlayerToRoom(roomId: string, player: Player): Promise { + return new Promise((resolve, reject) => { + this.redis.hset(`${this.ROOM_KEY_PRE}{${roomId}}`, + player.id, JSON.stringify(player), (err, reply) => { + if (err) { + reject(err); + } + resolve(); + }); + }); + } + + async removePlayerFromRoom(roomId: string, playerId: string): Promise { + return new Promise((resolve, reject) => { + this.redis.hdel(`${this.ROOM_KEY_PRE}{${roomId}}`, playerId, (err, reply) => { + if (err) { + reject(err); + } + resolve(); + }); + }); + } + + async retrieveRoomPlayers(roomId: string): Promise> { + return new Promise>((resolve, reject) => { + this.redis.hgetall(`${this.ROOM_KEY_PRE}{${roomId}}`, (err, reply) => { + if (err) { + reject(err); + } + resolve(Object.keys(reply).map(playerId => JSON.parse(reply[playerId]))); + }) + }); + } +} diff --git a/src/index.ts b/src/index.ts index ec6cbcc..78dbb11 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,14 @@ import socketIO from 'socket.io'; import Tracer from 'tracer'; import morgan from 'morgan'; import publicIp from 'public-ip'; +import { v4 } from "uuid"; +import {Cache} from "./cache/Cache"; +import {RedisCache} from "./cache/RedisCache"; +import {Messenger} from "./messaging/Messenger"; +import {RabbitmqMessenger} from "./messaging/RabbitmqMessenger"; +import {Player} from "./model/Player"; + +// TODO This needs to have a rework using preferably MVC models instead const httpsEnabled = !!process.env.HTTPS; @@ -31,7 +39,11 @@ if (httpsEnabled) { } const io = socketIO(server); -const playerIds = new Map(); +// NOTE: You can use your own implementation of messenger or cache, here, Redis and RabbitMQ are the default ones +const cache: Cache = new RedisCache(process.env.REDIS_URL!); +const messenger: Messenger = new RabbitmqMessenger(process.env.RABBITMQ_URL!); + +const serverId = v4(); interface Signal { data: string; @@ -62,58 +74,84 @@ app.get('/health', (req, res) => { io.on('connection', (socket: socketIO.Socket) => { connectionCount++; logger.info("Total connected: %d", connectionCount); - let code: string | null = null; - - socket.on('join', (c: string, id: number) => { - if (typeof c !== 'string' || typeof id !== 'number') { + let player: Player = { + roomId: undefined, + serverId: serverId, + clientId: undefined, + id: socket.id, + }; + + socket.on('join', async (code: string, id: number) => { + if (typeof code !== 'string' || typeof id !== 'number') { socket.disconnect(); - logger.error(`Socket %s sent invalid join command: %s %d`, socket.id, c, id); + logger.error(`Socket %s sent invalid join command: %s %d`, socket.id, code, id); return; } - code = c; - socket.join(code); - socket.to(code).broadcast.emit('join', socket.id, id); + player.roomId = code; - let socketsInLobby = Object.keys(io.sockets.adapter.rooms[code].sockets); + const playersInRoom = await cache.retrieveRoomPlayers(code); let ids: any = {}; - for (let s of socketsInLobby) { - if (s !== socket.id) - ids[s] = playerIds.get(s); + for (const player of playersInRoom) { + ids[player.id] = player.clientId; } socket.emit('setIds', ids); + + socket.join(code); + await cache.addPlayerToRoom(player.roomId, player); + await messenger.broadcastToRoom(player.roomId, { + command: "join", + args: [socket.id, id], + }); }); - socket.on('id', (id: number) => { + socket.on('id', async (id: number) => { if (typeof id !== 'number') { socket.disconnect(); logger.error(`Socket %s sent invalid id command: %d`, socket.id, id); return; } - playerIds.set(socket.id, id); - socket.to(code).broadcast.emit('setId', socket.id, id); - }) + + player.clientId = id; + if (!player.roomId) { + socket.disconnect(); + logger.error('Socket %s is not a in room.', socket.id); + return; + } + + // Cache player update + await cache.addPlayerToRoom(player.roomId, player); + await messenger.broadcastToRoom(player.roomId, { + command: "setId", + args: [id], + }); + }); socket.on('leave', () => { - if (code) socket.leave(code); + if (player.roomId) socket.leave(player.roomId); }) - socket.on('signal', (signal: Signal) => { + socket.on('signal', async (signal: Signal) => { if (typeof signal !== 'object' || !signal.data || !signal.to || typeof signal.to !== 'string') { socket.disconnect(); logger.error(`Socket %s sent invalid signal command: %j`, socket.id, signal); return; } + const { to, data } = signal; - io.to(to).emit('signal', { - data, - from: socket.id + await messenger.sendToPlayer(to, { + command: "signal", + args: [ + { + data, + from: socket.id + } + ] }); }); socket.on('disconnect', () => { connectionCount--; - playerIds.delete(socket.id); logger.info("Total connected: %d", connectionCount); }) @@ -124,4 +162,4 @@ server.listen(port); if (!address) address = `http://${await publicIp.v4()}:${port}`; logger.info('CrewLink Server started: %s', address); -})(); \ No newline at end of file +})(); diff --git a/src/manager/PlayerSessionsManager.ts b/src/manager/PlayerSessionsManager.ts new file mode 100644 index 0000000..dfb4266 --- /dev/null +++ b/src/manager/PlayerSessionsManager.ts @@ -0,0 +1,17 @@ +import {Player} from "../model/Player"; + +export class PlayerSessionsManager { + private players: Map = new Map(); + + getPlayer(socketId: string): Player { + return this.players.get(socketId); + } + + updatePlayer(socketId: string, player: Player): void { + this.players.set(player.id, player); + } + + clearPlayer(socketId: string): void { + this.players.delete(socketId); + } +} diff --git a/src/messaging/Messenger.ts b/src/messaging/Messenger.ts new file mode 100644 index 0000000..81f64f2 --- /dev/null +++ b/src/messaging/Messenger.ts @@ -0,0 +1,30 @@ +export interface Message { + command: string; + args: Array; +} + +export abstract class Messenger { + protected listeners: Array<(message: Message) => void> = []; + + /** + * Send a message to a specific player + * @param playerId The player's session id + * @param message The message to send (will be serialized to JSON) + */ + abstract async sendToPlayer(playerId: string, message: Message): Promise; + + /** + * Broadcast a message to a specific room + * @param roomId The room's id + * @param message The message to send (will be serialized to JSON) + */ + abstract async broadcastToRoom(roomId: string, message: Message): Promise; + + addListener(listener: (message: Message) => void): void { + this.listeners.push(listener); + } + + protected dispatchMessage(message: Message): void { + this.listeners.forEach(listener => listener(message)); + } +} diff --git a/src/messaging/RabbitmqMessenger.ts b/src/messaging/RabbitmqMessenger.ts new file mode 100644 index 0000000..a5f1943 --- /dev/null +++ b/src/messaging/RabbitmqMessenger.ts @@ -0,0 +1,15 @@ +import {Message, Messenger} from "./Messenger"; + +export class RabbitmqMessenger extends Messenger { + constructor(rabbitmqUrl: string) { + super(); + } + + async broadcastToRoom(roomId: string, message: Message): Promise { + return Promise.resolve(undefined); + } + + async sendToPlayer(playerId: string, message: Message): Promise { + return Promise.resolve(undefined); + } +} diff --git a/src/model/Player.ts b/src/model/Player.ts new file mode 100644 index 0000000..3bc2490 --- /dev/null +++ b/src/model/Player.ts @@ -0,0 +1,6 @@ +export interface Player { + id: string; + clientId: number; + serverId: string; + roomId: string; +} diff --git a/tsconfig.json b/tsconfig.json index 0d84041..7264644 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "experimentalDecorators": true, "module": "commonjs", "noImplicitAny": true, "sourceMap": true, @@ -15,4 +16,4 @@ "include": [ "src/**/*" ] -} \ No newline at end of file +} diff --git a/yarn-error.log b/yarn-error.log index d9ea048..2790c2a 100644 --- a/yarn-error.log +++ b/yarn-error.log @@ -1,48 +1,59 @@ Arguments: - C:\Program Files\nodejs\node.exe C:\Users\otto\AppData\Roaming\npm\node_modules\yarn\bin\yarn.js add --dev @types/simple-node-logger + C:\Program Files\nodejs\node.exe C:\Program Files (x86)\Yarn\bin\yarn.js add @types/tracer --dev PATH: - C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\bin;C:\Users\otto\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\Oculus\Support\oculus-runtime;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\System32\OpenSSH;C:\Program Files\ojdkbuild\java-11-openjdk-11.0.2-1\bin;C:\Program Files (x86)\GtkSharp\2.12\bin;C:\Program Files\dotnet;C:\Program Files\Git\cmd;C:\Users\otto\Documents\ffmpeg;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0;C:\WINDOWS\System32\OpenSSH;C:\Users\otto\AppData\Roaming\nvm;C:\Program Files\nodejs;C:\ProgramData\chocolatey\bin;C:\Program Files\CMake\bin;C:\Users\otto\.windows-build-tools\python27;C:\Users\otto\AppData\Local\Programs\Python\Python38-32\Scripts;C:\Users\otto\AppData\Local\Programs\Python\Python38-32;C:\Users\otto\AppData\Local\Microsoft\WindowsApps;C:\Users\otto\AppData\Roaming\npm;C:\Users\otto\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\otto\Anaconda3;C:\Users\otto\Anaconda3\Scripts;C:\Users\otto\Anaconda3\Library\mingw-w64\bin;C:\Users\otto\Anaconda3\Library\usr\bin;C:\Users\otto\Anaconda3\Library\bin;C:\Users\otto\Anaconda3\bin;C:\Users\otto\Anaconda3\condabin;C:\Users\otto\AppData\Local\Microsoft\WindowsApps;C:\Users\otto\flutter\bin;C:\Users\otto\AppData\Roaming\nvm;C:\Program Files\nodejs;C:\MinGW\bin;C:\Users\otto\.dotnet\tools;C:\Users\otto\.dotnet\tools + C:\Users\alexm\Desktop\Projects\CrewLink-server\node_modules\.bin;C:\Python38\Scripts\;C:\Python38\;C:\Program Files\AdoptOpenJDK\jdk-8.0.252.09-hotspot\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\NVIDIA Corporation\NVSMI;C:\Program Files\Git\cmd;C:\apache-maven-3.6.2\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Users\alexm\AppData\Roaming\nvm;C:\Program Files\nodejs;C:\Program Files (x86)\Yarn\bin\;C:\Program Files\Amazon\AWSCLI\bin\;C:\terraform\;C:\ProgramData\chocolatey\bin;C:\Program Files\nodejs\;C:\Users\alexm\AppData\Local\Microsoft\WindowsApps;C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.1\bin;;C:\Users\alexm\AppData\Roaming\nvm;C:\Program Files\nodejs;C:\Users\alexm\AppData\Local\Yarn\bin;C:\Users\alexm\AppData\Local\BeefLang\bin;C:\Program Files\JetBrains\JetBrains Rider 2020.1.3\bin;;C:\Users\alexm\AppData\Roaming\npm;C:\ffmpeg\bin; Yarn version: - 1.22.0 + 1.22.4 Node version: - 12.13.0 + 12.18.3 Platform: win32 x64 Trace: - Error: https://registry.yarnpkg.com/@types%2fsimple-node-logger: Not found - at Request.params.callback [as _callback] (C:\Users\otto\AppData\Roaming\npm\node_modules\yarn\lib\cli.js:66975:18) - at Request.self.callback (C:\Users\otto\AppData\Roaming\npm\node_modules\yarn\lib\cli.js:140727:22) - at Request.emit (events.js:210:5) - at Request. (C:\Users\otto\AppData\Roaming\npm\node_modules\yarn\lib\cli.js:141699:10) - at Request.emit (events.js:210:5) - at IncomingMessage. (C:\Users\otto\AppData\Roaming\npm\node_modules\yarn\lib\cli.js:141621:12) - at Object.onceWrapper (events.js:299:28) - at IncomingMessage.emit (events.js:215:7) - at endReadableNT (_stream_readable.js:1183:12) - at processTicksAndRejections (internal/process/task_queues.js:80:21) + Error: https://registry.yarnpkg.com/@types%2ftracer: Not found + at Request.params.callback [as _callback] (C:\Program Files (x86)\Yarn\lib\cli.js:66096:18) + at Request.self.callback (C:\Program Files (x86)\Yarn\lib\cli.js:140748:22) + at Request.emit (events.js:315:20) + at Request. (C:\Program Files (x86)\Yarn\lib\cli.js:141720:10) + at Request.emit (events.js:315:20) + at IncomingMessage. (C:\Program Files (x86)\Yarn\lib\cli.js:141642:12) + at Object.onceWrapper (events.js:421:28) + at IncomingMessage.emit (events.js:327:22) + at endReadableNT (_stream_readable.js:1220:12) + at processTicksAndRejections (internal/process/task_queues.js:84:21) npm manifest: { - "name": "server", - "version": "1.0.0", + "name": "crewlink-server", + "version": "1.0.1", "main": "index.js", - "license": "MIT", + "license": "GPL-3.0-or-later", "dependencies": { - "@types/express": "^4.17.8", - "@types/socket.io": "^2.1.11", "express": "^4.17.1", - "simple-node-logger": "^18.12.24", - "socket.io": "^2.3.0" + "morgan": "^1.10.0", + "public-ip": "^4.0.2", + "pug": "^3.0.0", + "redis": "^3.0.2", + "redlock": "^4.2.0", + "socket.io": "^2.3.0", + "tracer": "^1.1.4", + "uuid": "^8.3.2" }, "scripts": { - "dev": "tsc && node dist/index.js" + "start": "yarn compile && node dist/index.js", + "compile": "tsc", + "postinstall": "yarn compile" }, "devDependencies": { + "@types/express": "^4.17.8", + "@types/morgan": "^1.9.2", + "@types/public-ip": "^3.1.0", + "@types/socket.io": "^2.1.11", + "@types/uuid": "^8.3.0", "typescript": "^4.0.5" } } @@ -55,6 +66,37 @@ Lockfile: # yarn lockfile v1 + "@babel/helper-validator-identifier@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" + integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== + + "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79" + integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg== + + "@babel/types@^7.6.1", "@babel/types@^7.9.6": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299" + integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ== + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + + "@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + + "@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + "@types/body-parser@*": version "1.19.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" @@ -64,9 +106,9 @@ Lockfile: "@types/node" "*" "@types/connect@*": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" - integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + version "3.4.34" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901" + integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ== dependencies: "@types/node" "*" @@ -78,18 +120,18 @@ Lockfile: "@types/node" "*" "@types/express-serve-static-core@*": - version "4.17.13" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz#d9af025e925fc8b089be37423b8d1eac781be084" - integrity sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA== + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.17.tgz#6ba02465165b6c9c3d8db3a28def6b16fc9b70f5" + integrity sha512-YYlVaCni5dnHc+bLZfY908IG1+x5xuibKZMGv8srKkvtul3wUuanYvpIj9GXXoWkQbaAdR+kgX46IETKUALWNQ== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" "@types/express@^4.17.8": - version "4.17.8" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.8.tgz#3df4293293317e61c60137d273a2e96cd8d5f27a" - integrity sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ== + version "4.17.9" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.9.tgz#f5f2df6add703ff28428add52bdec8a1091b0a78" + integrity sha512-SDzEIZInC4sivGIFY4Sz1GG6J9UObPwCInYJjko2jzOf/Imx/dlpume6Xxwj1ORL82tBbmN4cPDIDkLbWHk9hw== dependencies: "@types/body-parser" "*" "@types/express-serve-static-core" "*" @@ -101,10 +143,24 @@ Lockfile: resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q== + "@types/morgan@^1.9.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.2.tgz#450f958a4d3fb0694a3ba012b09c8106f9a2885e" + integrity sha512-edtGMEdit146JwwIeyQeHHg9yID4WSolQPxpEorHmN3KuytuCHyn2ELNr5Uxy8SerniFbbkmgKMrGM933am5BQ== + dependencies: + "@types/node" "*" + "@types/node@*": - version "14.14.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.3.tgz#e1c09064121f894baaad2bd9f12ce4a41bffb274" - integrity sha512-33/L34xS7HVUx23e0wOT2V1qPF1IrHgQccdJVm9uXGTB9vFBrrzBtkQymT8VskeKOxjz55MSqMv0xuLq+u98WQ== + version "14.14.16" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.16.tgz#3cc351f8d48101deadfed4c9e4f116048d437b4b" + integrity sha512-naXYePhweTi+BMv11TgioE2/FXU4fSl29HAH1ffxVciNsH3rYXjNP2yM8wqmSm7jS20gM8TIklKiTen+1iVncw== + + "@types/public-ip@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/public-ip/-/public-ip-3.1.0.tgz#d86c2825dd53c6f1b825338df73f33a8bf331935" + integrity sha512-OgI5S2NovvE3Do0/Yt+Rm4s8bvlUqc3sN+7VJDpGVERsFt+r/M4TVXGokVd7nQGxieVXJ1zTWGmFvFPBDuUFyQ== + dependencies: + public-ip "*" "@types/qs@*": version "6.9.5" @@ -117,20 +173,33 @@ Lockfile: integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== "@types/serve-static@*": - version "1.13.6" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.6.tgz#866b1b8dec41c36e28c7be40ac725b88be43c5c1" - integrity sha512-nuRJmv7jW7VmCVTn+IgYDkkbbDGyIINOeu/G0d74X3lm6E5KfMeQPJhxIt1ayQeQB3cSxvYs1RA/wipYoFB4EA== + version "1.13.8" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.8.tgz#851129d434433c7082148574ffec263d58309c46" + integrity sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA== dependencies: "@types/mime" "*" "@types/node" "*" + "@types/socket.io-parser@*": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/socket.io-parser/-/socket.io-parser-2.2.1.tgz#dc94aed303839487f4975249a32a548109ea3647" + integrity sha512-+JNb+7N7tSINyXPxAJb62+NcpC1x/fPn7z818W4xeNCdPTp6VsO/X8fCsg6+ug4a56m1v9sEiTIIUKVupcHOFQ== + dependencies: + "@types/node" "*" + "@types/socket.io@^2.1.11": - version "2.1.11" - resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.11.tgz#e0d6759880e5f9818d5297a3328b36641bae996b" - integrity sha512-bVprmqPhJMLb9ZCm8g0Xy8kwBFRbnanOWSxzWkDkkIwxTvud5tKMfAJymXX6LQbizUKCS1yima7JM4BeLqjNqA== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.12.tgz#91187f826a5dd2ed1113e935815bbaf9627e5cb0" + integrity sha512-oStc5VFkpb0AsjOxQUj9ztX5Iziatyla/rjZTYbFGoVrrKwd+JU2mtxk7iSl5RGYx9WunLo6UXW1fBzQok/ZyA== dependencies: "@types/engine.io" "*" "@types/node" "*" + "@types/socket.io-parser" "*" + + "@types/uuid@^8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" + integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== accepts@~1.3.4, accepts@~1.3.7: version "1.3.7" @@ -140,6 +209,11 @@ Lockfile: mime-types "~2.1.24" negotiator "0.6.2" + acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" @@ -155,11 +229,28 @@ Lockfile: resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== + asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + + assert-never@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe" + integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw== + async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + babel-walk@3.0.0-canary-5: + version "3.0.0-canary-5" + resolved "https://registry.yarnpkg.com/babel-walk/-/babel-walk-3.0.0-canary-5.tgz#f66ecd7298357aee44955f235a6ef54219104b11" + integrity sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw== + dependencies: + "@babel/types" "^7.9.6" + backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" @@ -180,6 +271,13 @@ Lockfile: resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + basic-auth@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" @@ -192,6 +290,11 @@ Lockfile: resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== + bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + body-parser@1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -213,11 +316,43 @@ Lockfile: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + callsite@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + character-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" + integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A= + dependencies: + is-regex "^1.0.3" + + clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + + colors@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -238,6 +373,14 @@ Lockfile: resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + constantinople@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-4.0.1.tgz#0def113fa0e4dc8de83331a5cf79c8b325213151" + integrity sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw== + dependencies: + "@babel/parser" "^7.6.0" + "@babel/types" "^7.6.1" + content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -265,6 +408,11 @@ Lockfile: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + dateformat@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" + integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -286,16 +434,62 @@ Lockfile: dependencies: ms "^2.1.1" + decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + + defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + + denque@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf" + integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + depd@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + dns-packet@^5.1.2: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.2.1.tgz#26cec0be92252a1b97ed106482921192a7e08f72" + integrity sha512-JHj2yJeKOqlxzeuYpN1d56GfhzivAxavNwHj9co3qptECel27B1rLY5PifJAvubsInX5pGLDjAHuCfCUc2Zv/w== + dependencies: + ip "^1.1.5" + + dns-socket@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/dns-socket/-/dns-socket-4.2.1.tgz#c260f46e5649d1c2476763b78e2ee48f7abef531" + integrity sha512-fNvDq86lS522+zMbh31X8cQzYQd6xumCNlxsuZF5TKxQThF/e+rJbVM6K8mmlsdcSm6yNjKJQq3Sf38viAJj8g== + dependencies: + dns-packet "^5.1.2" + + doctypes@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" + integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= + + duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -306,6 +500,13 @@ Lockfile: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + engine.io-client@~3.4.0: version "3.4.4" resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.4.tgz#77d8003f502b0782dd792b073a4d2cf7ca5ab967" @@ -415,6 +616,42 @@ Lockfile: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + + get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + + get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + + got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + has-binary2@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" @@ -427,6 +664,23 @@ Lockfile: resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + + has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + + http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + http-errors@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" @@ -471,21 +725,100 @@ Lockfile: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + ip-regex@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.2.0.tgz#a03f5eb661d9a154e3973a03de8b23dd0ad6892e" + integrity sha512-n5cDDeTWWRwK1EBoWwRti+8nP4NbytBBY0pldmnIkq6Z55KNFmWofh4rl9dPZpj+U/nVq7gweR3ylrvMt4YZ5A== + + ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + is-core-module@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" + integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== + dependencies: + has "^1.0.3" + + is-expression@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab" + integrity sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A== + dependencies: + acorn "^7.1.1" + object-assign "^4.1.1" + + is-ip@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8" + integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q== + dependencies: + ip-regex "^4.0.0" + + is-promise@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + + is-regex@^1.0.3: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== + dependencies: + has-symbols "^1.0.1" + isarray@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= - lodash@^4.17.12: + js-stringify@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" + integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= + + json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + + jstransformer@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" + integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM= + dependencies: + is-promise "^2.0.0" + promise "^7.0.1" + + keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + + lodash@^4.17.19: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + + lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -518,10 +851,26 @@ Lockfile: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - moment@^2.20.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" - integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + + mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + + morgan@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" + integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== + dependencies: + basic-auth "~2.0.1" + debug "2.6.9" + depd "~2.0.0" + on-finished "~2.3.0" + on-headers "~1.0.2" ms@2.0.0: version "2.0.0" @@ -534,15 +883,25 @@ Lockfile: integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + normalize-url@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" + integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== + + object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" @@ -555,6 +914,23 @@ Lockfile: dependencies: ee-first "1.1.1" + on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + + once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + + p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + parseqs@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" @@ -584,11 +960,28 @@ Lockfile: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + + promise@^7.0.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -597,6 +990,126 @@ Lockfile: forwarded "~0.1.2" ipaddr.js "1.9.1" + public-ip@*, public-ip@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-ip/-/public-ip-4.0.3.tgz#ca96979ddbd3e14d3378fd92b94a657b5696f288" + integrity sha512-IofiJJWoZ8hZHBk25l4ozLvcET0pjZSxocbUfh4sGkjidMOm4iZNzzWxezGqGsVY7HuxiK7SkyJKHNeT0YQ7uw== + dependencies: + dns-socket "^4.2.1" + got "^9.6.0" + is-ip "^3.1.0" + + pug-attrs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-3.0.0.tgz#b10451e0348165e31fad1cc23ebddd9dc7347c41" + integrity sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA== + dependencies: + constantinople "^4.0.1" + js-stringify "^1.0.2" + pug-runtime "^3.0.0" + + pug-code-gen@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-3.0.1.tgz#ff3b337b100c494ea63ef766091d27f7d73acb7e" + integrity sha512-xJIGvmXTQlkJllq6hqxxjRWcay2F9CU69TuAuiVZgHK0afOhG5txrQOcZyaPHBvSWCU/QQOqEp5XCH94rRZpBQ== + dependencies: + constantinople "^4.0.1" + doctypes "^1.1.0" + js-stringify "^1.0.2" + pug-attrs "^3.0.0" + pug-error "^2.0.0" + pug-runtime "^3.0.0" + void-elements "^3.1.0" + with "^7.0.0" + + pug-error@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-2.0.0.tgz#5c62173cb09c34de2a2ce04f17b8adfec74d8ca5" + integrity sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ== + + pug-filters@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e" + integrity sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A== + dependencies: + constantinople "^4.0.1" + jstransformer "1.0.0" + pug-error "^2.0.0" + pug-walk "^2.0.0" + resolve "^1.15.1" + + pug-lexer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-5.0.0.tgz#0b779e7d8cbf0f103803675be96351942fd9a727" + integrity sha512-52xMk8nNpuyQ/M2wjZBN5gXQLIylaGkAoTk5Y1pBhVqaopaoj8Z0iVzpbFZAqitL4RHNVDZRnJDsqEYe99Ti0A== + dependencies: + character-parser "^2.2.0" + is-expression "^4.0.0" + pug-error "^2.0.0" + + pug-linker@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-4.0.0.tgz#12cbc0594fc5a3e06b9fc59e6f93c146962a7708" + integrity sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw== + dependencies: + pug-error "^2.0.0" + pug-walk "^2.0.0" + + pug-load@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-3.0.0.tgz#9fd9cda52202b08adb11d25681fb9f34bd41b662" + integrity sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ== + dependencies: + object-assign "^4.1.1" + pug-walk "^2.0.0" + + pug-parser@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-6.0.0.tgz#a8fdc035863a95b2c1dc5ebf4ecf80b4e76a1260" + integrity sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw== + dependencies: + pug-error "^2.0.0" + token-stream "1.0.0" + + pug-runtime@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-3.0.0.tgz#d523025fdc0a1efe70929d1fd3a2d24121ffffb6" + integrity sha512-GoEPcmQNnaTsePEdVA05bDpY+Op5VLHKayg08AQiqJBWU/yIaywEYv7TetC5dEQS3fzBBoyb2InDcZEg3mPTIA== + + pug-strip-comments@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz#f94b07fd6b495523330f490a7f554b4ff876303e" + integrity sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ== + dependencies: + pug-error "^2.0.0" + + pug-walk@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe" + integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ== + + pug@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.0.tgz#101eecd7a236cd9906e420e17799d4d57f2b7d93" + integrity sha512-inmsJyFBSHZaiGLaguoFgJGViX0If6AcfcElimvwj9perqjDpUpw79UIEDZbWFmoGVidh08aoE+e8tVkjVJPCw== + dependencies: + pug-code-gen "^3.0.0" + pug-filters "^4.0.0" + pug-lexer "^5.0.0" + pug-linker "^4.0.0" + pug-load "^3.0.0" + pug-parser "^6.0.0" + pug-runtime "^3.0.0" + pug-strip-comments "^2.0.0" + + pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -617,6 +1130,55 @@ Lockfile: iconv-lite "0.4.24" unpipe "1.0.0" + redis-commands@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.6.0.tgz#36d4ca42ae9ed29815cdb30ad9f97982eba1ce23" + integrity sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ== + + redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + + redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + + redis@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/redis/-/redis-3.0.2.tgz#bd47067b8a4a3e6a2e556e57f71cc82c7360150a" + integrity sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ== + dependencies: + denque "^1.4.1" + redis-commands "^1.5.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + + redlock@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/redlock/-/redlock-4.2.0.tgz#c26590768559afd5fff76aa1133c94b411ff4f5f" + integrity sha512-j+oQlG+dOwcetUt2WJWttu4CZVeRzUrcVcISFmEmfyuwCVSJ93rDT7YSgg7H7rnxwoRyk/jU46kycVka5tW7jA== + dependencies: + bluebird "^3.7.2" + + resolve@^1.15.1: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== + dependencies: + is-core-module "^2.1.0" + path-parse "^1.0.6" + + responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + safe-buffer@5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -661,14 +1223,6 @@ Lockfile: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - simple-node-logger@^18.12.24: - version "18.12.24" - resolved "https://registry.yarnpkg.com/simple-node-logger/-/simple-node-logger-18.12.24.tgz#d1961b83cf3302a2c2a7b292e736b1601d838b4e" - integrity sha512-4dTqpYecHsvPjWo+i+J3pLty8WJDNbxOVesNj5ch8pYH95LIGAFH4dxMSqyf+Os0RTchXifEtI/mfm3AVJftmg== - dependencies: - lodash "^4.17.12" - moment "^2.20.1" - socket.io-adapter@~1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" @@ -729,16 +1283,46 @@ Lockfile: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + tinytim@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/tinytim/-/tinytim-0.1.1.tgz#c968a1e5559ad9553224ef7627bab34e3caef8a8" + integrity sha1-yWih5VWa2VUyJO92J7qzTjyu+Kg= + to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + + to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + token-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4" + integrity sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ= + + tracer@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/tracer/-/tracer-1.1.4.tgz#6c01904be4b13b4df6a42d8850908fac2299bdd4" + integrity sha512-43Ws4c/V6VK9i2MLjmeYVtXZ+YUHU/qFXznJqYgI8F5nNrIQ4v9ImBAk+JjfPHS4StlpmaHzgR5qpBydbD9TkA== + dependencies: + colors "1.4.0" + dateformat "3.0.3" + mkdirp "^1.0.4" + tinytim "0.1.1" + type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -748,29 +1332,61 @@ Lockfile: mime-types "~2.1.24" typescript@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389" - integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ== + version "4.1.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" + integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + void-elements@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= + + with@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/with/-/with-7.0.2.tgz#ccee3ad542d25538a7a7a80aad212b9828495bac" + integrity sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w== + dependencies: + "@babel/parser" "^7.9.6" + "@babel/types" "^7.9.6" + assert-never "^1.2.1" + babel-walk "3.0.0-canary-5" + + wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + ws@^7.1.2: - version "7.3.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" - integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== + version "7.4.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.1.tgz#a333be02696bd0e54cea0434e21dcc8a9ac294bb" + integrity sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ== ws@~6.1.0: version "6.1.4" diff --git a/yarn.lock b/yarn.lock index baeb50d..4ab6c83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,22 +2,22 @@ # yarn lockfile v1 -"@babel/helper-validator-identifier@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" - integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== +"@babel/helper-validator-identifier@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" + integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": - version "7.12.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.7.tgz#fee7b39fe809d0e73e5b25eecaf5780ef3d73056" - integrity sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg== + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79" + integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg== "@babel/types@^7.6.1", "@babel/types@^7.9.6": - version "7.12.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.7.tgz#6039ff1e242640a29452c9ae572162ec9a8f5d13" - integrity sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ== + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299" + integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ== dependencies: - "@babel/helper-validator-identifier" "^7.10.4" + "@babel/helper-validator-identifier" "^7.12.11" lodash "^4.17.19" to-fast-properties "^2.0.0" @@ -33,6 +33,19 @@ dependencies: defer-to-connect "^1.0.1" +"@types/amqplib@^0.5.16": + version "0.5.16" + resolved "https://registry.yarnpkg.com/@types/amqplib/-/amqplib-0.5.16.tgz#8297c53a1aa0455ea2ac51f923613e886a513ef0" + integrity sha512-M/D13gVboXAA07A6GX8df3H/Wew1CjfIceVasnVK5SiSB9PfRyPl8TKppVb/DeR1zIffToxOU5otDcoIsn2C6g== + dependencies: + "@types/bluebird" "*" + "@types/node" "*" + +"@types/bluebird@*": + version "3.5.33" + resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.33.tgz#d79c020f283bd50bd76101d7d300313c107325fc" + integrity sha512-ndEo1xvnYeHxm7I/5sF6tBvnsA4Tdi3zj1keRKRs12SP+2ye2A27NDJ1B6PqkfMbGAcT+mqQVqbZRIrhfOp5PQ== + "@types/body-parser@*": version "1.19.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" @@ -42,9 +55,9 @@ "@types/node" "*" "@types/connect@*": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" - integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + version "3.4.34" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901" + integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ== dependencies: "@types/node" "*" @@ -56,18 +69,18 @@ "@types/node" "*" "@types/express-serve-static-core@*": - version "4.17.13" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz#d9af025e925fc8b089be37423b8d1eac781be084" - integrity sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA== + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.17.tgz#6ba02465165b6c9c3d8db3a28def6b16fc9b70f5" + integrity sha512-YYlVaCni5dnHc+bLZfY908IG1+x5xuibKZMGv8srKkvtul3wUuanYvpIj9GXXoWkQbaAdR+kgX46IETKUALWNQ== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" -"@types/express@^4.17.8": - version "4.17.8" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.8.tgz#3df4293293317e61c60137d273a2e96cd8d5f27a" - integrity sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ== +"@types/express@^4.17.9": + version "4.17.9" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.9.tgz#f5f2df6add703ff28428add52bdec8a1091b0a78" + integrity sha512-SDzEIZInC4sivGIFY4Sz1GG6J9UObPwCInYJjko2jzOf/Imx/dlpume6Xxwj1ORL82tBbmN4cPDIDkLbWHk9hw== dependencies: "@types/body-parser" "*" "@types/express-serve-static-core" "*" @@ -87,9 +100,16 @@ "@types/node" "*" "@types/node@*": - version "14.14.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.3.tgz#e1c09064121f894baaad2bd9f12ce4a41bffb274" - integrity sha512-33/L34xS7HVUx23e0wOT2V1qPF1IrHgQccdJVm9uXGTB9vFBrrzBtkQymT8VskeKOxjz55MSqMv0xuLq+u98WQ== + version "14.14.16" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.16.tgz#3cc351f8d48101deadfed4c9e4f116048d437b4b" + integrity sha512-naXYePhweTi+BMv11TgioE2/FXU4fSl29HAH1ffxVciNsH3rYXjNP2yM8wqmSm7jS20gM8TIklKiTen+1iVncw== + +"@types/public-ip@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/public-ip/-/public-ip-3.1.0.tgz#d86c2825dd53c6f1b825338df73f33a8bf331935" + integrity sha512-OgI5S2NovvE3Do0/Yt+Rm4s8bvlUqc3sN+7VJDpGVERsFt+r/M4TVXGokVd7nQGxieVXJ1zTWGmFvFPBDuUFyQ== + dependencies: + public-ip "*" "@types/qs@*": version "6.9.5" @@ -101,21 +121,41 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== +"@types/redis@^2.8.28": + version "2.8.28" + resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.28.tgz#5862b2b64aa7f7cbc76dafd7e6f06992b52c55e3" + integrity sha512-8l2gr2OQ969ypa7hFOeKqtFoY70XkHxISV0pAwmQ2nm6CSPb1brmTmqJCGGrekCo+pAZyWlNXr+Kvo6L/1wijA== + dependencies: + "@types/node" "*" + "@types/serve-static@*": - version "1.13.6" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.6.tgz#866b1b8dec41c36e28c7be40ac725b88be43c5c1" - integrity sha512-nuRJmv7jW7VmCVTn+IgYDkkbbDGyIINOeu/G0d74X3lm6E5KfMeQPJhxIt1ayQeQB3cSxvYs1RA/wipYoFB4EA== + version "1.13.8" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.8.tgz#851129d434433c7082148574ffec263d58309c46" + integrity sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA== dependencies: "@types/mime" "*" "@types/node" "*" +"@types/socket.io-parser@*": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/socket.io-parser/-/socket.io-parser-2.2.1.tgz#dc94aed303839487f4975249a32a548109ea3647" + integrity sha512-+JNb+7N7tSINyXPxAJb62+NcpC1x/fPn7z818W4xeNCdPTp6VsO/X8fCsg6+ug4a56m1v9sEiTIIUKVupcHOFQ== + dependencies: + "@types/node" "*" + "@types/socket.io@^2.1.11": - version "2.1.11" - resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.11.tgz#e0d6759880e5f9818d5297a3328b36641bae996b" - integrity sha512-bVprmqPhJMLb9ZCm8g0Xy8kwBFRbnanOWSxzWkDkkIwxTvud5tKMfAJymXX6LQbizUKCS1yima7JM4BeLqjNqA== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.12.tgz#91187f826a5dd2ed1113e935815bbaf9627e5cb0" + integrity sha512-oStc5VFkpb0AsjOxQUj9ztX5Iziatyla/rjZTYbFGoVrrKwd+JU2mtxk7iSl5RGYx9WunLo6UXW1fBzQok/ZyA== dependencies: "@types/engine.io" "*" "@types/node" "*" + "@types/socket.io-parser" "*" + +"@types/uuid@^8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" + integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== accepts@~1.3.4, accepts@~1.3.7: version "1.3.7" @@ -135,6 +175,18 @@ after@0.8.2: resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= +amqplib@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/amqplib/-/amqplib-0.6.0.tgz#87857c7c95d56d22438ced4cf1f7e5f0dc43b309" + integrity sha512-zXCh4jQ77TBZe1YtvZ1n7sUxnTjnNagpy8MVi2yc1ive239pS3iLwm4e4d5o4XZGx1BdTKQ/U0ZmaDU3c8MxYQ== + dependencies: + bitsyntax "~0.1.0" + bluebird "^3.5.2" + buffer-more-ints "~1.0.0" + readable-stream "1.x >=1.1.9" + safe-buffer "~5.1.2" + url-parse "~1.4.3" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -201,11 +253,25 @@ better-assert@~1.0.0: dependencies: callsite "1.0.0" +bitsyntax@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/bitsyntax/-/bitsyntax-0.1.0.tgz#b0c59acef03505de5a2ed62a2f763c56ae1d6205" + integrity sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q== + dependencies: + buffer-more-ints "~1.0.0" + debug "~2.6.9" + safe-buffer "~5.1.2" + blob@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== +bluebird@^3.5.2, bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + body-parser@1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -222,6 +288,11 @@ body-parser@1.19.0: raw-body "2.4.0" type-is "~1.6.17" +buffer-more-ints@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz#ef4f8e2dddbad429ed3828a9c55d44f05c611422" + integrity sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg== + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -319,12 +390,17 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + dateformat@3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@2.6.9: +debug@2.6.9, debug@~2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -357,6 +433,11 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== +denque@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf" + integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -626,7 +707,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -inherits@2.0.4: +inherits@2.0.4, inherits@~2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -680,6 +761,11 @@ is-regex@^1.0.3: dependencies: has-symbols "^1.0.1" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + isarray@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" @@ -789,9 +875,9 @@ ms@2.1.1: integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== negotiator@0.6.2: version "0.6.2" @@ -896,10 +982,10 @@ proxy-addr@~2.0.5: forwarded "~0.1.2" ipaddr.js "1.9.1" -public-ip@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/public-ip/-/public-ip-4.0.2.tgz#83158edd7665da6d51138ccdfa0413f0936fb7ff" - integrity sha512-ZHqUjaYT/+FuSiy5/o2gBxvj0PF7M3MXGnaLJBsJNMCyXI4jzuXXHJKrk0gDxx1apiF/jYsBwjTQOM9V8G6oCQ== +public-ip@*, public-ip@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-ip/-/public-ip-4.0.3.tgz#ca96979ddbd3e14d3378fd92b94a657b5696f288" + integrity sha512-IofiJJWoZ8hZHBk25l4ozLvcET0pjZSxocbUfh4sGkjidMOm4iZNzzWxezGqGsVY7HuxiK7SkyJKHNeT0YQ7uw== dependencies: dns-socket "^4.2.1" got "^9.6.0" @@ -1021,6 +1107,11 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -1036,6 +1127,55 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +"readable-stream@1.x >=1.1.9": + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +redis-commands@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.6.0.tgz#36d4ca42ae9ed29815cdb30ad9f97982eba1ce23" + integrity sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + +redis@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/redis/-/redis-3.0.2.tgz#bd47067b8a4a3e6a2e556e57f71cc82c7360150a" + integrity sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ== + dependencies: + denque "^1.4.1" + redis-commands "^1.5.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + +redlock@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/redlock/-/redlock-4.2.0.tgz#c26590768559afd5fff76aa1133c94b411ff4f5f" + integrity sha512-j+oQlG+dOwcetUt2WJWttu4CZVeRzUrcVcISFmEmfyuwCVSJ93rDT7YSgg7H7rnxwoRyk/jU46kycVka5tW7jA== + dependencies: + bluebird "^3.7.2" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + resolve@^1.15.1: version "1.19.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" @@ -1051,7 +1191,7 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -safe-buffer@5.1.2: +safe-buffer@5.1.2, safe-buffer@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -1155,6 +1295,11 @@ socket.io@^2.3.0: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + tinytim@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/tinytim/-/tinytim-0.1.1.tgz#c968a1e5559ad9553224ef7627bab34e3caef8a8" @@ -1204,9 +1349,9 @@ type-is@~1.6.17, type-is@~1.6.18: mime-types "~2.1.24" typescript@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389" - integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ== + version "4.1.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" + integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" @@ -1220,11 +1365,24 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +url-parse@~1.4.3: + version "1.4.7" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" + integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -1251,9 +1409,9 @@ wrappy@1: integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= ws@^7.1.2: - version "7.3.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" - integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== + version "7.4.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.1.tgz#a333be02696bd0e54cea0434e21dcc8a9ac294bb" + integrity sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ== ws@~6.1.0: version "6.1.4" From 12a38f30ecb8b782be92442b0c696e94596b0a3a Mon Sep 17 00:00:00 2001 From: AlexMog Date: Fri, 25 Dec 2020 20:21:00 +0100 Subject: [PATCH 2/3] Messaging AMQP ready for usage --- src/cache/Cache.ts | 3 + src/cache/RedisCache.ts | 37 ++++ src/index.ts | 263 ++++++++++++++------------- src/manager/PlayerSessionsManager.ts | 17 -- src/messaging/Messenger.ts | 12 +- src/messaging/RabbitmqMessenger.ts | 45 ++++- 6 files changed, 227 insertions(+), 150 deletions(-) delete mode 100644 src/manager/PlayerSessionsManager.ts diff --git a/src/cache/Cache.ts b/src/cache/Cache.ts index 84c062c..23f62f5 100644 --- a/src/cache/Cache.ts +++ b/src/cache/Cache.ts @@ -14,4 +14,7 @@ export interface Cache { */ addPlayerToRoom(roomId: string, player: Player): Promise; removePlayerFromRoom(roomId: string, playerId: string): Promise; + updateSession(socketId: string, serverId: string): Promise; + clearSession(socketId: string): Promise; + getSession(socketId: string): Promise; } diff --git a/src/cache/RedisCache.ts b/src/cache/RedisCache.ts index e2de812..0b0406d 100644 --- a/src/cache/RedisCache.ts +++ b/src/cache/RedisCache.ts @@ -4,6 +4,7 @@ import Redis, {RedisClient} from "redis"; export class RedisCache implements Cache { private readonly ROOM_KEY_PRE = process.env.REDIS_ROOM_KEY_PRE || "crewlink:room:"; + private readonly SESSION_KEY_PRE = process.env.REDIS_ROOM_KEY_PRE || "crewlink:session:"; private readonly redis: RedisClient; constructor(redisUrl: string) { @@ -43,4 +44,40 @@ export class RedisCache implements Cache { }) }); } + + clearSession(socketId: string): Promise { + return new Promise((resolve, reject) => { + this.redis.del(`${this.SESSION_KEY_PRE}{${socketId}}`, (err, reply) => { + if (err) { + reject(err); + } + resolve(); + }); + }); + } + + updateSession(socketId: string, serverId: string): Promise { + // FIXME: In a ideal world, a ping-pong mechanism must exist between client and server and this + // should have a TTL and the expire value of this TTL should be updated on each ping, to avoid memory leaks + // on redis + return new Promise((resolve, reject) => { + this.redis.set(`${this.SESSION_KEY_PRE}{${socketId}}`, serverId,(err, reply) => { + if (err) { + reject(err); + } + resolve(); + }); + }); + } + + getSession(socketId: string): Promise { + return new Promise((resolve, reject) => { + this.redis.get(`${this.SESSION_KEY_PRE}{${socketId}}`,(err, reply) => { + if (err) { + reject(err); + } + resolve(reply); + }); + }); + } } diff --git a/src/index.ts b/src/index.ts index 78dbb11..f96bd34 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,149 +16,160 @@ import {Player} from "./model/Player"; // TODO This needs to have a rework using preferably MVC models instead -const httpsEnabled = !!process.env.HTTPS; +(async function() { + const httpsEnabled = !!process.env.HTTPS; -const port = parseInt(process.env.PORT || (httpsEnabled ? '443' : '9736')); + const port = parseInt(process.env.PORT || (httpsEnabled ? '443' : '9736')); -const sslCertificatePath = process.env.SSLPATH || process.cwd(); -const supportedVersions = readdirSync(join(process.cwd(), 'offsets')).map(file => file.replace('.yml', '')); + const sslCertificatePath = process.env.SSLPATH || process.cwd(); + const supportedVersions = readdirSync(join(process.cwd(), 'offsets')).map(file => file.replace('.yml', '')); -const logger = Tracer.colorConsole({ - format: "{{timestamp}} <{{title}}> {{message}}" -}); - -const app = express(); -let server: HttpsServer | Server; -if (httpsEnabled) { - server = new HttpsServer({ - key: readFileSync(join(sslCertificatePath, 'privkey.pem')), - cert: readFileSync(join(sslCertificatePath, 'fullchain.pem')) - }, app); -} else { - server = new Server(app); -} -const io = socketIO(server); + const logger = Tracer.colorConsole({ + format: "{{timestamp}} <{{title}}> {{message}}" + }); + const app = express(); + let server: HttpsServer | Server; + if (httpsEnabled) { + server = new HttpsServer({ + key: readFileSync(join(sslCertificatePath, 'privkey.pem')), + cert: readFileSync(join(sslCertificatePath, 'fullchain.pem')) + }, app); + } else { + server = new Server(app); + } + const io = socketIO(server); + + const serverId = v4(); // NOTE: You can use your own implementation of messenger or cache, here, Redis and RabbitMQ are the default ones -const cache: Cache = new RedisCache(process.env.REDIS_URL!); -const messenger: Messenger = new RabbitmqMessenger(process.env.RABBITMQ_URL!); - -const serverId = v4(); - -interface Signal { - data: string; - to: string; -} - -app.set('view engine', 'pug') -app.use(morgan('combined')) -app.use(express.static('offsets')) -let connectionCount = 0; -let address = process.env.ADDRESS; - -app.get('/', (_, res) => { - res.render('index', { connectionCount, address }); -}); - -app.get('/health', (req, res) => { - res.json({ - uptime: process.uptime(), - connectionCount, - address, - name: process.env.NAME, - supportedVersions + const cache: Cache = new RedisCache(process.env.REDIS_URL!); + const messenger = new RabbitmqMessenger(process.env.RABBITMQ_URL!, cache, serverId); + await messenger.connect(); + + + interface Signal { + data: string; + to: string; + } + + app.set('view engine', 'pug') + app.use(morgan('combined')) + app.use(express.static('offsets')) + let connectionCount = 0; + let address = process.env.ADDRESS; + + messenger.addListener(message => { + io.to(message.to).emit(message.command, ...message.args); }); -}) - - -io.on('connection', (socket: socketIO.Socket) => { - connectionCount++; - logger.info("Total connected: %d", connectionCount); - let player: Player = { - roomId: undefined, - serverId: serverId, - clientId: undefined, - id: socket.id, - }; - - socket.on('join', async (code: string, id: number) => { - if (typeof code !== 'string' || typeof id !== 'number') { - socket.disconnect(); - logger.error(`Socket %s sent invalid join command: %s %d`, socket.id, code, id); - return; - } - player.roomId = code; - - const playersInRoom = await cache.retrieveRoomPlayers(code); - let ids: any = {}; - for (const player of playersInRoom) { - ids[player.id] = player.clientId; - } - socket.emit('setIds', ids); - - socket.join(code); - await cache.addPlayerToRoom(player.roomId, player); - await messenger.broadcastToRoom(player.roomId, { - command: "join", - args: [socket.id, id], - }); + + app.get('/', (_, res) => { + res.render('index', { connectionCount, address }); }); - socket.on('id', async (id: number) => { - if (typeof id !== 'number') { - socket.disconnect(); - logger.error(`Socket %s sent invalid id command: %d`, socket.id, id); - return; - } - - player.clientId = id; - if (!player.roomId) { - socket.disconnect(); - logger.error('Socket %s is not a in room.', socket.id); - return; - } - - // Cache player update - await cache.addPlayerToRoom(player.roomId, player); - await messenger.broadcastToRoom(player.roomId, { - command: "setId", - args: [id], + app.get('/health', (req, res) => { + res.json({ + uptime: process.uptime(), + connectionCount, + address, + name: process.env.NAME, + supportedVersions }); }); + io.on('connection', (socket: socketIO.Socket) => { + connectionCount++; + logger.info("Total connected: %d", connectionCount); + let player: Player = { + roomId: undefined, + serverId: serverId, + clientId: undefined, + id: socket.id, + }; + let sessionCreated = false; + + socket.on('join', async (code: string, id: number) => { + if (typeof code !== 'string' || typeof id !== 'number') { + socket.disconnect(); + logger.error(`Socket %s sent invalid join command: %s %d`, socket.id, code, id); + return; + } + + if (!sessionCreated) { + await cache.updateSession(socket.id, serverId); + } + + // NOTE: This part might need a cluster-wide lock to avoid race conditions with other nodes + const playersInRoom = await cache.retrieveRoomPlayers(code); + let ids: any = {}; + for (const player of playersInRoom) { + ids[player.id] = player.clientId; + } + socket.emit('setIds', ids); + + player.roomId = code; + socket.join(code); + await cache.addPlayerToRoom(player.roomId, player); + await messenger.broadcastToRoom(player.roomId, { + command: "join", + args: [socket.id, id], + }); + }); + + socket.on('id', async (id: number) => { + if (typeof id !== 'number') { + socket.disconnect(); + logger.error(`Socket %s sent invalid id command: %d`, socket.id, id); + return; + } + + player.clientId = id; + if (!player.roomId) { + socket.disconnect(); + logger.error('Socket %s is not a in room.', socket.id); + return; + } + + // Cache player update + await cache.addPlayerToRoom(player.roomId, player); + await messenger.broadcastToRoom(player.roomId, { + command: "setId", + args: [id], + }); + }); - socket.on('leave', () => { - if (player.roomId) socket.leave(player.roomId); - }) - socket.on('signal', async (signal: Signal) => { - if (typeof signal !== 'object' || !signal.data || !signal.to || typeof signal.to !== 'string') { - socket.disconnect(); - logger.error(`Socket %s sent invalid signal command: %j`, socket.id, signal); - return; - } - - const { to, data } = signal; - await messenger.sendToPlayer(to, { - command: "signal", - args: [ - { - data, - from: socket.id - } - ] + socket.on('leave', () => { + if (player.roomId) socket.leave(player.roomId); + }) + + socket.on('signal', async (signal: Signal) => { + if (typeof signal !== 'object' || !signal.data || !signal.to || typeof signal.to !== 'string') { + socket.disconnect(); + logger.error(`Socket %s sent invalid signal command: %j`, socket.id, signal); + return; + } + + const { to, data } = signal; + await messenger.sendToPlayer(to, { + command: "signal", + args: [ + { + data, + from: socket.id + } + ] + }); }); - }); - socket.on('disconnect', () => { - connectionCount--; - logger.info("Total connected: %d", connectionCount); - }) + socket.on('disconnect', () => { + connectionCount--; + cache.clearSession(socket.id); + logger.info("Total connected: %d", connectionCount); + }) -}) + }) -server.listen(port); -(async () => { + server.listen(port); if (!address) address = `http://${await publicIp.v4()}:${port}`; logger.info('CrewLink Server started: %s', address); diff --git a/src/manager/PlayerSessionsManager.ts b/src/manager/PlayerSessionsManager.ts deleted file mode 100644 index dfb4266..0000000 --- a/src/manager/PlayerSessionsManager.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {Player} from "../model/Player"; - -export class PlayerSessionsManager { - private players: Map = new Map(); - - getPlayer(socketId: string): Player { - return this.players.get(socketId); - } - - updatePlayer(socketId: string, player: Player): void { - this.players.set(player.id, player); - } - - clearPlayer(socketId: string): void { - this.players.delete(socketId); - } -} diff --git a/src/messaging/Messenger.ts b/src/messaging/Messenger.ts index 81f64f2..6b7c6c9 100644 --- a/src/messaging/Messenger.ts +++ b/src/messaging/Messenger.ts @@ -3,6 +3,10 @@ export interface Message { args: Array; } +export interface ReceivedMessage extends Message { + to: string; +} + export abstract class Messenger { protected listeners: Array<(message: Message) => void> = []; @@ -11,20 +15,20 @@ export abstract class Messenger { * @param playerId The player's session id * @param message The message to send (will be serialized to JSON) */ - abstract async sendToPlayer(playerId: string, message: Message): Promise; + abstract sendToPlayer(playerId: string, message: Message): Promise; /** * Broadcast a message to a specific room * @param roomId The room's id * @param message The message to send (will be serialized to JSON) */ - abstract async broadcastToRoom(roomId: string, message: Message): Promise; + abstract broadcastToRoom(roomId: string, message: Message): Promise; - addListener(listener: (message: Message) => void): void { + addListener(listener: (message: ReceivedMessage) => void): void { this.listeners.push(listener); } - protected dispatchMessage(message: Message): void { + protected dispatchMessage(message: ReceivedMessage): void { this.listeners.forEach(listener => listener(message)); } } diff --git a/src/messaging/RabbitmqMessenger.ts b/src/messaging/RabbitmqMessenger.ts index a5f1943..7891bee 100644 --- a/src/messaging/RabbitmqMessenger.ts +++ b/src/messaging/RabbitmqMessenger.ts @@ -1,15 +1,54 @@ import {Message, Messenger} from "./Messenger"; +import Amqp from "amqplib"; +import {Cache} from "../cache/Cache"; +import {Player} from "../model/Player"; export class RabbitmqMessenger extends Messenger { - constructor(rabbitmqUrl: string) { + private readonly EXCHANGE_NAME = process.env.AMQP_EXCHANGE_NAME || "crewlink:messaging"; + private connection: Amqp.Connection; + private channel: Amqp.Channel; + + constructor(private rabbitmqUrl: string, private cache: Cache, private serverId: string) { super(); } + async connect() { + this.connection = await Amqp.connect(this.rabbitmqUrl); + this.channel = await this.connection.createChannel(); + await this.channel.assertExchange(this.EXCHANGE_NAME, "direct", { + durable: true, + }); + const queue = await this.channel.assertQueue('', { + exclusive: true, + }); + await this.channel.bindQueue(queue.queue, this.EXCHANGE_NAME, this.serverId); + await this.channel.consume(queue.queue, msg => { + this.dispatchMessage(JSON.parse(msg.content.toString())); + }); + } + async broadcastToRoom(roomId: string, message: Message): Promise { - return Promise.resolve(undefined); + const promises: Promise[] = []; + (await this.cache.retrieveRoomPlayers(roomId)).forEach(player => { + promises.push(this.sendTo(player, message)); + }); + await Promise.all(promises); + } + + private async sendTo(player: Player, message: Message): Promise { + this.channel.publish(this.EXCHANGE_NAME, player.serverId, Buffer.from(JSON.stringify({ + to: player.id, + ...message + }))); } async sendToPlayer(playerId: string, message: Message): Promise { - return Promise.resolve(undefined); + const session = await this.cache.getSession(playerId); + if (session) { + this.channel.publish(this.EXCHANGE_NAME, session, Buffer.from(JSON.stringify({ + to: playerId, + ...message + }))); + } } } From c6efebcfd554f651be2e40e4f1faff850b9fec84 Mon Sep 17 00:00:00 2001 From: AlexMog Date: Fri, 25 Dec 2020 21:03:07 +0100 Subject: [PATCH 3/3] Added local server, non-clustered workflow --- src/cache/LocalCache.ts | 47 +++++++++++++++++++++++++++++++++ src/index.ts | 21 ++++++++++----- src/messaging/LocalMessenger.ts | 17 ++++++++++++ 3 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 src/cache/LocalCache.ts create mode 100644 src/messaging/LocalMessenger.ts diff --git a/src/cache/LocalCache.ts b/src/cache/LocalCache.ts new file mode 100644 index 0000000..3f56884 --- /dev/null +++ b/src/cache/LocalCache.ts @@ -0,0 +1,47 @@ +import {Cache} from "./Cache"; +import {Player} from "../model/Player"; + +export class LocalCache implements Cache { + private rooms: Map> = new Map(); + + async addPlayerToRoom(roomId: string, player: Player): Promise { + let room = this.rooms.get(roomId); + if (!room) { + room = []; + this.rooms.set(roomId, room); + } + room.push(player); + } + + async clearSession(socketId: string): Promise { + return Promise.resolve(undefined); + } + + async getSession(socketId: string): Promise { + return Promise.resolve(""); + } + + async removePlayerFromRoom(roomId: string, playerId: string): Promise { + const room = this.rooms.get(roomId); + if (room) { + let i = room.length; + while (--i) { + if (room[i].id == playerId) { + room.splice(i, 1); + } + } + if (room.length == 0) { + this.rooms.delete(roomId); + } + } + } + + async retrieveRoomPlayers(roomId: string): Promise> { + return this.rooms.get(roomId) || []; + } + + async updateSession(socketId: string, serverId: string): Promise { + return Promise.resolve(undefined); + } + +} diff --git a/src/index.ts b/src/index.ts index f96bd34..5ce47b4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,9 +10,10 @@ import publicIp from 'public-ip'; import { v4 } from "uuid"; import {Cache} from "./cache/Cache"; import {RedisCache} from "./cache/RedisCache"; -import {Messenger} from "./messaging/Messenger"; import {RabbitmqMessenger} from "./messaging/RabbitmqMessenger"; import {Player} from "./model/Player"; +import {LocalCache} from "./cache/LocalCache"; +import {LocalMessenger} from "./messaging/LocalMessenger"; // TODO This needs to have a rework using preferably MVC models instead @@ -41,11 +42,15 @@ import {Player} from "./model/Player"; const io = socketIO(server); const serverId = v4(); -// NOTE: You can use your own implementation of messenger or cache, here, Redis and RabbitMQ are the default ones - const cache: Cache = new RedisCache(process.env.REDIS_URL!); - const messenger = new RabbitmqMessenger(process.env.RABBITMQ_URL!, cache, serverId); - await messenger.connect(); - + // Comment this part and uncomment next part to activate cluster mode + // NOTE: This part replicate a local, non-clustered server + const cache = new LocalCache(); + const messenger = new LocalMessenger(); + // Uncomment this part if you want to activate the cluster mode + // NOTE: You can use your own implementation of messenger or cache, here, Redis and RabbitMQ are the default ones + // const cache: Cache = new RedisCache(process.env.REDIS_URL!); + // const messenger = new RabbitmqMessenger(process.env.RABBITMQ_URL!, cache, serverId); + // await messenger.connect(); interface Signal { data: string; @@ -95,6 +100,7 @@ import {Player} from "./model/Player"; } if (!sessionCreated) { + sessionCreated = true; await cache.updateSession(socket.id, serverId); } @@ -163,6 +169,9 @@ import {Player} from "./model/Player"; socket.on('disconnect', () => { connectionCount--; + if (player.roomId) { + cache.removePlayerFromRoom(player.roomId, player.id); + } cache.clearSession(socket.id); logger.info("Total connected: %d", connectionCount); }) diff --git a/src/messaging/LocalMessenger.ts b/src/messaging/LocalMessenger.ts new file mode 100644 index 0000000..359e2ee --- /dev/null +++ b/src/messaging/LocalMessenger.ts @@ -0,0 +1,17 @@ +import {Message, Messenger} from "./Messenger"; + +export class LocalMessenger extends Messenger { + async broadcastToRoom(roomId: string, message: Message): Promise { + this.dispatchMessage({ + to: roomId, + ...message + }); + } + + async sendToPlayer(playerId: string, message: Message): Promise { + this.dispatchMessage({ + to: playerId, + ...message + }) + } +}