diff --git a/libs/common/src/constants.ts b/libs/common/src/constants.ts index ff3fa27..1098b75 100644 --- a/libs/common/src/constants.ts +++ b/libs/common/src/constants.ts @@ -15,7 +15,9 @@ export const CORDIS_META: { } = { url: pkg.homepage.split('#')[0], version: pkg.version -}; +} as const; + +Object.freeze(CORDIS_META); /** * Root endpoints for Discord @@ -28,3 +30,44 @@ export const ENDPOINTS = { } as const; Object.freeze(ENDPOINTS); + +/** + * Interface representing configuration for the gateway service + */ +export interface GatewayServiceConfig { + auth: string; + amqpHost: string; + debug: boolean; + shardCount: number | 'auto'; + startingShard: number; + totalShardCount: number | 'auto'; + ws: { + compress: boolean; + encoding: 'json' | 'etf'; + timeouts: { + open: number; + hello: number; + ready: number; + guild: number; + reconnect: number; + }; + largeThreshold: number; + intents: string[]; + }; +} + +/** + * Injection tokens used by the gateway service + */ +export const GATEWAY_INJECTION_TOKENS = { + kConfig: Symbol('parsed configuration options'), + amqp: { + kChannel: Symbol('amqp channel object'), + kConnection: Symbol('amqp connection object'), + kService: Symbol('RoutingServer instance for distributing the incoming packets'), + kCommandsServer: Symbol('"server" recieving payloads (called commands) to send to Discord') + }, + kCluster: Symbol('Cluster instance') +} as const; + +Object.freeze(GATEWAY_INJECTION_TOKENS); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a2c1b7c..628a56d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -194,18 +194,6 @@ importers: node-fetch: ^2.6.1 tslib: ^2.1.0 typescript: ^4.2.2 - libs/routers: - dependencies: - '@cordis/rest': link:../rest - tslib: 2.1.0 - devDependencies: - '@types/node': 14.14.31 - typescript: 4.2.2 - specifiers: - '@cordis/rest': workspace:^0.1.7 - '@types/node': ^14.14.31 - tslib: ^2.1.0 - typescript: ^4.2.2 libs/store: dependencies: '@cordis/error': link:../error @@ -238,7 +226,9 @@ importers: '@cordis/common': link:../../libs/common '@cordis/gateway': link:../../libs/gateway erlpack: github.com/discord/erlpack/e27db8f82892bdb9b28a0547cc394d68b5d2242d + reflect-metadata: 0.1.13 tslib: 2.1.0 + tsyringe: 4.4.0 yargs: 15.4.1 zlib-sync: 0.1.7 devDependencies: @@ -254,7 +244,9 @@ importers: '@types/yargs': ^15.0.13 discord-api-types: ^0.12.1 erlpack: github:discord/erlpack + reflect-metadata: ^0.1.13 tslib: ^2.1.0 + tsyringe: ^4.4.0 typescript: ^4.2.2 yargs: ^15.4.1 zlib-sync: ^0.1.7 @@ -5041,6 +5033,10 @@ packages: node: '>=4' resolution: integrity: sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + /reflect-metadata/0.1.13: + dev: false + resolution: + integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== /regenerate-unicode-properties/8.2.0: dependencies: regenerate: 1.4.2 @@ -5802,7 +5798,6 @@ packages: resolution: integrity: sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== /tslib/1.14.1: - dev: true resolution: integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== /tslib/2.1.0: @@ -5820,6 +5815,14 @@ packages: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' resolution: integrity: sha512-RYbuQuvkhuqVeXweWT3tJLKOEJ/UUw9GjNEZGWdrLLlM+611o1gwLHBpxoFJKKl25fLprp2eVthtKs5JOrNeXg== + /tsyringe/4.4.0: + dependencies: + tslib: 1.14.1 + dev: false + engines: + node: '>= 6.0.0' + resolution: + integrity: sha512-SlMApe1lhIq546CDp7bF+IdF4RB6d+9C5T7B0AS0P/Bm+Qpizj/gEmZzvw9J/KlXPEt4qHTbi1TRvX3rCPSdTg== /tunnel-agent/0.6.0: dependencies: safe-buffer: 5.2.1 diff --git a/services/gateway/package.json b/services/gateway/package.json index 96a09ab..d32a94c 100644 --- a/services/gateway/package.json +++ b/services/gateway/package.json @@ -32,7 +32,9 @@ "@cordis/common": "workspace:^0.1.7", "@cordis/gateway": "workspace:^0.1.7", "erlpack": "github:discord/erlpack", + "reflect-metadata": "^0.1.13", "tslib": "^2.1.0", + "tsyringe": "^4.4.0", "yargs": "^15.4.1", "zlib-sync": "^0.1.7" } diff --git a/services/gateway/src/index.ts b/services/gateway/src/index.ts index 19f34a4..05ba1c2 100644 --- a/services/gateway/src/index.ts +++ b/services/gateway/src/index.ts @@ -1,9 +1,19 @@ +import 'reflect-metadata'; +import { container } from 'tsyringe'; import * as yargs from 'yargs'; import { createAmqp, RoutingServer, PubSubClient } from '@cordis/brokers'; import { Cluster, IntentKeys } from '@cordis/gateway'; -import type { DiscordEvents } from '@cordis/common'; +import { DiscordEvents, GatewayServiceConfig, GATEWAY_INJECTION_TOKENS } from '@cordis/common'; import type { GatewaySendPayload } from 'discord-api-types/v8'; +const loadExtension = async (name: string) => { + try { + await require(`../extensions/${name}`); + } catch (e) { + if (e.code !== 'MODULE_NOT_FOUND') console.error(`[${name.toUpperCase()} EXTENSION ERROR]`, e); + } +}; + const main = async () => { const { argv } = yargs .env('CORDIS') @@ -45,12 +55,6 @@ const main = async () => { 'demandOption': false, 'default': 'auto' as const }) - .option('redis-url', { - global: true, - description: 'URL for connecting to your redis instance', - type: 'string', - demandOption: false - }) .option('ws-compress', { 'global': true, 'description': 'Whether or not to use compression', @@ -61,7 +65,7 @@ const main = async () => { 'global': true, 'description': 'What websocket encoding to use, JSON or ETF', 'type': 'string', - 'default': 'etf' + 'default': 'etf' as const }) .option('ws-open-timeout', { 'global': true, @@ -115,6 +119,32 @@ const main = async () => { }) .help(); + const config: GatewayServiceConfig = { + auth: argv.auth, + amqpHost: argv['amqp-host'], + debug: argv.debug, + shardCount: argv['shard-count'], + startingShard: argv['starting-shard'], + totalShardCount: argv['total-shard-count'], + ws: { + compress: argv['ws-compress'], + encoding: argv['ws-encoding'], + timeouts: { + open: argv['ws-open-timeout'], + hello: argv['ws-hello-timeout'], + ready: argv['ws-ready-timeout'], + guild: argv['ws-guild-timeout'], + reconnect: argv['ws-reconnect-timeout'] + }, + largeThreshold: argv['ws-large-threshold'], + intents: argv['ws-intents'] + } + }; + + container.register(GATEWAY_INJECTION_TOKENS.kConfig, { useValue: config }); + + await loadExtension('pre-setup'); + const { channel, connection } = await createAmqp(argv['amqp-host']); connection .on('error', e => console.error(`[AMQP ERROR]: ${e}`)) @@ -149,6 +179,12 @@ const main = async () => { cb: req => cluster.broadcast(req) }); + container.register(GATEWAY_INJECTION_TOKENS.amqp.kChannel, { useValue: channel }); + container.register(GATEWAY_INJECTION_TOKENS.amqp.kConnection, { useValue: connection }); + container.register(GATEWAY_INJECTION_TOKENS.amqp.kService, { useValue: service }); + container.register(GATEWAY_INJECTION_TOKENS.amqp.kCommandsServer, { useValue: gatewayCommandsServer }); + container.register(GATEWAY_INJECTION_TOKENS.kCluster, { useValue: cluster }); + cluster .on('disconnecting', id => console.log(`[DISCONNECTING]: Shard id ${id}`)) .on('reconnecting', id => console.log(`[RECONNECTING]: Shard id ${id}`)) @@ -157,11 +193,15 @@ const main = async () => { .on('ready', () => console.log('[READY]: All shards have fully connected')) .on('dispatch', data => service.publish(data.t, data.d)); + await loadExtension('pre-init'); + if (argv.debug) cluster.on('debug', (info, id) => console.log(`[DEBUG]: Shard id ${id}`, info)); try { await service.init({ name: 'gateway', topicBased: false }); await cluster.connect(); + + await loadExtension('post-init'); } catch (e) { console.error('Failed to initialize the service or the cluster', e); process.exit(1);