stock-bot/libs/core/handler-registry/src/registry.ts
2025-06-26 16:12:27 -04:00

218 lines
5.4 KiB
TypeScript

/**
* Handler Registry Implementation
* Manages handler metadata and configuration without circular dependencies
*/
import type { JobHandler, ScheduledJob } from '@stock-bot/types';
import type { HandlerConfiguration, HandlerMetadata, RegistryStats } from './types';
export class HandlerRegistry {
private handlers = new Map<string, HandlerMetadata>();
private configurations = new Map<string, HandlerConfiguration>();
private handlerServices = new Map<string, string>();
/**
* Register handler metadata
*/
registerMetadata(metadata: HandlerMetadata): void {
this.handlers.set(metadata.name, metadata);
if (metadata.service) {
this.handlerServices.set(metadata.name, metadata.service);
}
}
/**
* Register handler configuration with operation implementations
*/
registerConfiguration(config: HandlerConfiguration): void {
this.configurations.set(config.name, config);
}
/**
* Register both metadata and configuration
*/
register(metadata: HandlerMetadata, config: HandlerConfiguration): void {
this.registerMetadata(metadata);
this.registerConfiguration(config);
}
/**
* Get handler metadata
*/
getMetadata(handlerName: string): HandlerMetadata | undefined {
return this.handlers.get(handlerName);
}
/**
* Get handler configuration
*/
getConfiguration(handlerName: string): HandlerConfiguration | undefined {
return this.configurations.get(handlerName);
}
/**
* Get a specific operation handler
*/
getOperation(handlerName: string, operationName: string): JobHandler | undefined {
const config = this.configurations.get(handlerName);
return config?.operations[operationName];
}
/**
* Get all handler metadata
*/
getAllMetadata(): Map<string, HandlerMetadata> {
return new Map(this.handlers);
}
/**
* Get all handler names
*/
getHandlerNames(): string[] {
return Array.from(this.handlers.keys());
}
/**
* Check if a handler is registered
*/
hasHandler(handlerName: string): boolean {
return this.handlers.has(handlerName);
}
/**
* Set service ownership for a handler
*/
setHandlerService(handlerName: string, serviceName: string): void {
this.handlerServices.set(handlerName, serviceName);
// Update metadata if it exists
const metadata = this.handlers.get(handlerName);
if (metadata) {
metadata.service = serviceName;
}
}
/**
* Get the service that owns a handler
*/
getHandlerService(handlerName: string): string | undefined {
return this.handlerServices.get(handlerName);
}
/**
* Get all handlers for a specific service
*/
getServiceHandlers(serviceName: string): HandlerMetadata[] {
const handlers: HandlerMetadata[] = [];
for (const [handlerName, metadata] of this.handlers) {
if (
this.handlerServices.get(handlerName) === serviceName ||
metadata.service === serviceName
) {
handlers.push(metadata);
}
}
return handlers;
}
/**
* Get scheduled jobs for a handler
*/
getScheduledJobs(handlerName: string): ScheduledJob[] {
const config = this.configurations.get(handlerName);
return config?.scheduledJobs || [];
}
/**
* Get all handlers with their scheduled jobs
*/
getAllHandlersWithSchedule(): Map<
string,
{ metadata: HandlerMetadata; scheduledJobs: ScheduledJob[] }
> {
const result = new Map<string, { metadata: HandlerMetadata; scheduledJobs: ScheduledJob[] }>();
for (const [name, metadata] of this.handlers) {
const config = this.configurations.get(name);
result.set(name, {
metadata,
scheduledJobs: config?.scheduledJobs || [],
});
}
return result;
}
/**
* Get registry statistics
*/
getStats(): RegistryStats {
let operationCount = 0;
let scheduledJobCount = 0;
const services = new Set<string>();
for (const metadata of this.handlers.values()) {
operationCount += metadata.operations.length;
scheduledJobCount += metadata.schedules?.length || 0;
if (metadata.service) {
services.add(metadata.service);
}
}
return {
handlers: this.handlers.size,
operations: operationCount,
scheduledJobs: scheduledJobCount,
services: services.size,
};
}
/**
* Clear all registrations (useful for testing)
*/
clear(): void {
this.handlers.clear();
this.configurations.clear();
this.handlerServices.clear();
}
/**
* Export registry data for debugging or persistence
*/
export(): {
handlers: Array<[string, HandlerMetadata]>;
configurations: Array<[string, HandlerConfiguration]>;
services: Array<[string, string]>;
} {
return {
handlers: Array.from(this.handlers.entries()),
configurations: Array.from(this.configurations.entries()),
services: Array.from(this.handlerServices.entries()),
};
}
/**
* Import registry data
*/
import(data: {
handlers: Array<[string, HandlerMetadata]>;
configurations: Array<[string, HandlerConfiguration]>;
services: Array<[string, string]>;
}): void {
this.clear();
for (const [name, metadata] of data.handlers) {
this.handlers.set(name, metadata);
}
for (const [name, config] of data.configurations) {
this.configurations.set(name, config);
}
for (const [handler, service] of data.services) {
this.handlerServices.set(handler, service);
}
}
}