// Implementation inspired from Outline import type { QueueClient } from "./queueing"; import type { RateLimitClient } from "./ratelimiting"; import logger from "./logger"; import { SearchIndexClient } from "./search"; export enum PluginType { Search = "search", Queue = "queue", RateLimit = "ratelimit", } interface PluginTypeMap { [PluginType.Search]: SearchIndexClient; [PluginType.Queue]: QueueClient; [PluginType.RateLimit]: RateLimitClient; } export interface TPlugin { type: T; name: string; provider: PluginProvider; } export interface PluginProvider { getClient(): Promise; } // Preserve the key-dependent value type: for K, store TPlugin[] type ProviderMap = { [K in PluginType]: TPlugin[] }; export class PluginManager { private static providers: ProviderMap = { [PluginType.Search]: [], [PluginType.Queue]: [], [PluginType.RateLimit]: [], }; static register(plugin: TPlugin): void { PluginManager.providers[plugin.type].push(plugin); } static async getClient( type: T, ): Promise { const providers: TPlugin[] = PluginManager.providers[type]; if (providers.length === 0) { return null; } return await providers[providers.length - 1]!.provider.getClient(); } static isRegistered(type: T): boolean { return PluginManager.providers[type].length > 0; } static getPluginName(type: T): string | null { const providers: TPlugin[] = PluginManager.providers[type]; if (providers.length === 0) { return null; } return providers[providers.length - 1]!.name; } static logAllPlugins() { logger.info("Plugins (Last one wins):"); for (const type of Object.values(PluginType)) { logger.info(` ${type}:`); const plugins = PluginManager.providers[type]; if (!plugins) { logger.info(" - None"); continue; } for (const plugin of plugins) { logger.info(` - ${plugin.name}`); } } } }