- Introduce BaseService as a foundational class for services, providing standardized dependency injection and initialization logic. - Refactor ChatService to extend BaseService, enhancing its initialization process and dependency handling. - Implement service metadata and structured initialization in ChatService, allowing for better tracking and error handling during service setup. - Update chat module to initialize ChatService with dependency management, ensuring readiness before use.
139 lines
No EOL
3.2 KiB
TypeScript
139 lines
No EOL
3.2 KiB
TypeScript
import type { DIContainer, ServiceToken } from './types'
|
|
|
|
export type { ServiceToken } from './types'
|
|
|
|
interface ServiceRegistration {
|
|
service: any
|
|
scope: 'singleton' | 'transient'
|
|
instance?: any
|
|
}
|
|
|
|
/**
|
|
* Dependency Injection Container
|
|
* Manages service registration and injection across modules
|
|
*/
|
|
export class DIContainerImpl implements DIContainer {
|
|
private services = new Map<ServiceToken, ServiceRegistration>()
|
|
|
|
/**
|
|
* Register a service in the container
|
|
*/
|
|
provide<T>(token: ServiceToken, service: T, scope: 'singleton' | 'transient' = 'singleton'): void {
|
|
this.services.set(token, {
|
|
service,
|
|
scope,
|
|
instance: scope === 'singleton' ? service : undefined
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Inject a service from the container
|
|
*/
|
|
inject<T>(token: ServiceToken): T | undefined {
|
|
const registration = this.services.get(token)
|
|
|
|
if (!registration) {
|
|
return undefined
|
|
}
|
|
|
|
if (registration.scope === 'singleton') {
|
|
return registration.instance as T
|
|
}
|
|
|
|
// For transient services, create new instance
|
|
// Note: This assumes the service is a constructor function
|
|
if (typeof registration.service === 'function') {
|
|
try {
|
|
return new registration.service() as T
|
|
} catch (error) {
|
|
console.error(`Error creating transient service for token ${String(token)}:`, error)
|
|
return undefined
|
|
}
|
|
}
|
|
|
|
return registration.service as T
|
|
}
|
|
|
|
/**
|
|
* Remove a service from the container
|
|
*/
|
|
remove(token: ServiceToken): boolean {
|
|
return this.services.delete(token)
|
|
}
|
|
|
|
/**
|
|
* Clear all services
|
|
*/
|
|
clear(): void {
|
|
this.services.clear()
|
|
}
|
|
|
|
/**
|
|
* Get all registered service tokens
|
|
*/
|
|
getRegisteredTokens(): ServiceToken[] {
|
|
return Array.from(this.services.keys())
|
|
}
|
|
|
|
/**
|
|
* Check if a service is registered
|
|
*/
|
|
has(token: ServiceToken): boolean {
|
|
return this.services.has(token)
|
|
}
|
|
|
|
/**
|
|
* Get service registration info
|
|
*/
|
|
getServiceInfo(token: ServiceToken): { scope: string; hasInstance: boolean } | undefined {
|
|
const registration = this.services.get(token)
|
|
if (!registration) {
|
|
return undefined
|
|
}
|
|
|
|
return {
|
|
scope: registration.scope,
|
|
hasInstance: registration.instance !== undefined
|
|
}
|
|
}
|
|
}
|
|
|
|
// Global DI container instance
|
|
export const container = new DIContainerImpl()
|
|
|
|
// Service token constants
|
|
export const SERVICE_TOKENS = {
|
|
// Core services
|
|
EVENT_BUS: Symbol('eventBus'),
|
|
ROUTER: Symbol('router'),
|
|
|
|
// Nostr services
|
|
RELAY_HUB: Symbol('relayHub'),
|
|
NOSTR_CLIENT_HUB: Symbol('nostrClientHub'),
|
|
|
|
// Auth services
|
|
AUTH_SERVICE: Symbol('authService'),
|
|
|
|
// Market services
|
|
MARKET_STORE: Symbol('marketStore'),
|
|
PAYMENT_MONITOR: Symbol('paymentMonitor'),
|
|
|
|
// Chat services
|
|
CHAT_SERVICE: Symbol('chatService'),
|
|
|
|
// Events services
|
|
EVENTS_SERVICE: Symbol('eventsService'),
|
|
} as const
|
|
|
|
// Type-safe injection helpers
|
|
export function injectService<T>(token: ServiceToken): T {
|
|
const service = container.inject<T>(token)
|
|
if (!service) {
|
|
throw new Error(`Service not found for token: ${String(token)}`)
|
|
}
|
|
return service
|
|
}
|
|
|
|
export function tryInjectService<T>(token: ServiceToken): T | undefined {
|
|
return container.inject<T>(token)
|
|
} |