171 lines
No EOL
6.4 KiB
TypeScript
171 lines
No EOL
6.4 KiB
TypeScript
import { createContainer, InjectionMode, type AwilixContainer } from 'awilix';
|
|
import type { AppConfig as StockBotAppConfig } from '@stock-bot/config';
|
|
import { appConfigSchema, type AppConfig } from '../config/schemas';
|
|
import {
|
|
registerCoreServices,
|
|
registerCacheServices,
|
|
registerDatabaseServices,
|
|
registerApplicationServices
|
|
} from '../registrations';
|
|
import { ServiceLifecycleManager } from '../utils/lifecycle';
|
|
import type { ServiceDefinitions, ContainerBuildOptions } from './types';
|
|
|
|
export class ServiceContainerBuilder {
|
|
private config: Partial<AppConfig> = {};
|
|
private options: ContainerBuildOptions = {
|
|
enableCache: true,
|
|
enableQueue: true,
|
|
enableMongoDB: true,
|
|
enablePostgres: true,
|
|
enableQuestDB: true,
|
|
enableBrowser: true,
|
|
enableProxy: true,
|
|
skipInitialization: false,
|
|
initializationTimeout: 30000,
|
|
};
|
|
|
|
withConfig(config: AppConfig | StockBotAppConfig): this {
|
|
this.config = this.transformStockBotConfig(config);
|
|
return this;
|
|
}
|
|
|
|
withOptions(options: Partial<ContainerBuildOptions>): this {
|
|
Object.assign(this.options, options);
|
|
return this;
|
|
}
|
|
|
|
enableService(service: keyof Omit<ContainerBuildOptions, 'skipInitialization' | 'initializationTimeout'>, enabled = true): this {
|
|
this.options[service] = enabled;
|
|
return this;
|
|
}
|
|
|
|
skipInitialization(skip = true): this {
|
|
this.options.skipInitialization = skip;
|
|
return this;
|
|
}
|
|
|
|
async build(): Promise<AwilixContainer<ServiceDefinitions>> {
|
|
// Validate and prepare config
|
|
const validatedConfig = this.prepareConfig();
|
|
|
|
// Create container
|
|
const container = createContainer<ServiceDefinitions>({
|
|
injectionMode: InjectionMode.PROXY,
|
|
strict: true,
|
|
});
|
|
|
|
// Register services
|
|
this.registerServices(container, validatedConfig);
|
|
|
|
// Initialize services if not skipped
|
|
if (!this.options.skipInitialization) {
|
|
const lifecycleManager = new ServiceLifecycleManager();
|
|
await lifecycleManager.initializeServices(container, this.options.initializationTimeout);
|
|
}
|
|
|
|
return container;
|
|
}
|
|
|
|
private prepareConfig(): AppConfig {
|
|
const finalConfig = this.applyServiceOptions(this.config);
|
|
return appConfigSchema.parse(finalConfig);
|
|
}
|
|
|
|
private applyServiceOptions(config: Partial<AppConfig>): AppConfig {
|
|
return {
|
|
redis: {
|
|
enabled: this.options.enableCache ?? true,
|
|
host: config.redis?.host || 'localhost',
|
|
port: config.redis?.port || 6379,
|
|
password: config.redis?.password,
|
|
username: config.redis?.username,
|
|
db: config.redis?.db || 0,
|
|
},
|
|
mongodb: {
|
|
enabled: this.options.enableMongoDB ?? true,
|
|
uri: config.mongodb?.uri || '',
|
|
database: config.mongodb?.database || '',
|
|
},
|
|
postgres: {
|
|
enabled: this.options.enablePostgres ?? true,
|
|
host: config.postgres?.host || 'localhost',
|
|
port: config.postgres?.port || 5432,
|
|
database: config.postgres?.database || '',
|
|
user: config.postgres?.user || '',
|
|
password: config.postgres?.password || '',
|
|
},
|
|
questdb: this.options.enableQuestDB ? config.questdb : undefined,
|
|
proxy: this.options.enableProxy ? (config.proxy || { cachePrefix: 'proxy:', ttl: 3600 }) : undefined,
|
|
browser: this.options.enableBrowser ? config.browser : undefined,
|
|
queue: this.options.enableQueue ? { enabled: this.options.enableQueue } : undefined,
|
|
};
|
|
}
|
|
|
|
private registerServices(container: AwilixContainer<ServiceDefinitions>, config: AppConfig): void {
|
|
registerCoreServices(container, config);
|
|
registerCacheServices(container, config);
|
|
registerDatabaseServices(container, config);
|
|
registerApplicationServices(container, config);
|
|
|
|
// Register service container aggregate
|
|
container.register({
|
|
serviceContainer: asFunction(({
|
|
config, logger, cache, proxyManager, browser,
|
|
queueManager, mongoClient, postgresClient, questdbClient
|
|
}) => ({
|
|
logger,
|
|
cache,
|
|
proxy: proxyManager, // Map proxyManager to proxy
|
|
browser,
|
|
queue: queueManager, // Map queueManager to queue
|
|
mongodb: mongoClient, // Map mongoClient to mongodb
|
|
postgres: postgresClient, // Map postgresClient to postgres
|
|
questdb: questdbClient, // Map questdbClient to questdb
|
|
})).singleton(),
|
|
});
|
|
}
|
|
|
|
private transformStockBotConfig(config: AppConfig | StockBotAppConfig): Partial<AppConfig> {
|
|
// If it's already in the new format, return as is
|
|
if ('redis' in config) {
|
|
return config as AppConfig;
|
|
}
|
|
|
|
// Transform from StockBotAppConfig format
|
|
const stockBotConfig = config as StockBotAppConfig;
|
|
return {
|
|
redis: stockBotConfig.database?.dragonfly ? {
|
|
enabled: true,
|
|
host: stockBotConfig.database.dragonfly.host || 'localhost',
|
|
port: stockBotConfig.database.dragonfly.port || 6379,
|
|
password: stockBotConfig.database.dragonfly.password,
|
|
db: stockBotConfig.database.dragonfly.db || 0,
|
|
} : undefined,
|
|
mongodb: stockBotConfig.database?.mongodb ? {
|
|
enabled: true,
|
|
uri: stockBotConfig.database.mongodb.uri ||
|
|
`mongodb://${stockBotConfig.database.mongodb.user || ''}:${stockBotConfig.database.mongodb.password || ''}@${stockBotConfig.database.mongodb.host || 'localhost'}:${stockBotConfig.database.mongodb.port || 27017}/${stockBotConfig.database.mongodb.database || 'test'}?authSource=${stockBotConfig.database.mongodb.authSource || 'admin'}`,
|
|
database: stockBotConfig.database.mongodb.database || 'test',
|
|
} : undefined,
|
|
postgres: stockBotConfig.database?.postgres ? {
|
|
enabled: true,
|
|
host: stockBotConfig.database.postgres.host || 'localhost',
|
|
port: stockBotConfig.database.postgres.port || 5432,
|
|
database: stockBotConfig.database.postgres.database || 'test',
|
|
user: stockBotConfig.database.postgres.user || 'test',
|
|
password: stockBotConfig.database.postgres.password || 'test',
|
|
} : undefined,
|
|
questdb: stockBotConfig.database?.questdb ? {
|
|
enabled: true,
|
|
host: stockBotConfig.database.questdb.host || 'localhost',
|
|
httpPort: stockBotConfig.database.questdb.httpPort || 9000,
|
|
pgPort: stockBotConfig.database.questdb.pgPort || 8812,
|
|
influxPort: stockBotConfig.database.questdb.ilpPort || 9009,
|
|
database: stockBotConfig.database.questdb.database || 'questdb',
|
|
} : undefined,
|
|
};
|
|
}
|
|
}
|
|
|
|
// Add missing import
|
|
import { asFunction } from 'awilix'; |