302 lines
8.0 KiB
TypeScript
302 lines
8.0 KiB
TypeScript
/**
|
|
* Arcadia Kernel - Entry Point
|
|
* Sistema nativo de gerenciamento de serviços
|
|
*
|
|
* V3.0 - Adicionado Service Registry + Docker Discovery
|
|
*/
|
|
|
|
import { readFileSync } from 'fs';
|
|
import { join, dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import { ProcessManager } from './core/ProcessManager';
|
|
import { HealthMonitor } from './core/HealthMonitor';
|
|
import { LogAggregator } from './core/LogAggregator';
|
|
import { DashboardServer } from './dashboard/DashboardServer';
|
|
import { ServiceConfig, ServiceState } from './types';
|
|
|
|
// NOVO: Service Registry e Discovery
|
|
import { ServiceRegistry } from './registry/ServiceRegistry';
|
|
import { DockerDiscovery } from './discovery/DockerDiscovery';
|
|
import { RegistryConfig, RegisteredService } from './registry/types';
|
|
|
|
// Suporte a ESM e CommonJS (build do Docker)
|
|
const __dirname = (() => {
|
|
try {
|
|
return dirname(fileURLToPath(import.meta.url));
|
|
} catch {
|
|
return join(process.cwd(), 'server', 'kernel');
|
|
}
|
|
})();
|
|
|
|
export interface KernelOptions {
|
|
configPath?: string;
|
|
dashboard?: {
|
|
enabled?: boolean;
|
|
port?: number;
|
|
host?: string;
|
|
};
|
|
autoStart?: boolean;
|
|
// NOVO: Opções do Service Registry
|
|
registry?: {
|
|
enabled?: boolean;
|
|
config?: Partial<RegistryConfig>;
|
|
};
|
|
}
|
|
|
|
export class ArcadiaKernel {
|
|
public processManager: ProcessManager;
|
|
public healthMonitor: HealthMonitor;
|
|
public logAggregator: LogAggregator;
|
|
public dashboard?: DashboardServer;
|
|
// NOVO: Service Registry
|
|
public serviceRegistry?: ServiceRegistry;
|
|
|
|
private options: Required<KernelOptions>;
|
|
private services: ServiceConfig[] = [];
|
|
private started = false;
|
|
|
|
constructor(options: KernelOptions = {}) {
|
|
this.options = {
|
|
configPath: join(__dirname, 'config', 'services.json'),
|
|
dashboard: {
|
|
enabled: true,
|
|
port: 5001,
|
|
host: '0.0.0.0',
|
|
},
|
|
autoStart: false,
|
|
// NOVO: Registry ativado por padrão
|
|
registry: {
|
|
enabled: true,
|
|
config: {
|
|
enableAutoDiscovery: true,
|
|
discoveryInterval: 30000,
|
|
healthCheckInterval: 15000,
|
|
},
|
|
},
|
|
...options,
|
|
};
|
|
|
|
// Inicializa componentes existentes
|
|
this.logAggregator = new LogAggregator({ maxLines: 10000 });
|
|
|
|
this.processManager = new ProcessManager({
|
|
onLog: (entry) => this.logAggregator.add(entry),
|
|
onStateChange: (serviceId, state) => {
|
|
console.log(`[Kernel] ${serviceId}: ${state.status}`);
|
|
},
|
|
onHealthChange: (serviceId, health) => {
|
|
console.log(`[Kernel] ${serviceId} health: ${health}`);
|
|
},
|
|
});
|
|
|
|
this.healthMonitor = new HealthMonitor({
|
|
onHealthChange: (serviceId, health, error) => {
|
|
this.processManager.setHealth(serviceId, health);
|
|
if (error) {
|
|
console.log(`[Kernel] ${serviceId} health error: ${error}`);
|
|
}
|
|
},
|
|
});
|
|
|
|
// NOVO: Inicializa Service Registry se habilitado
|
|
if (this.options.registry.enabled) {
|
|
this.serviceRegistry = new ServiceRegistry({
|
|
config: this.options.registry.config,
|
|
discoveryProviders: [
|
|
new DockerDiscovery({ networkName: 'arcadia' }),
|
|
],
|
|
});
|
|
|
|
// Escuta eventos do registry
|
|
this.serviceRegistry.on('event', (event) => {
|
|
console.log(`[Registry] ${event.type}: ${event.serviceId}`);
|
|
});
|
|
}
|
|
|
|
// Carrega configurações
|
|
this.loadConfig();
|
|
}
|
|
|
|
/**
|
|
* Inicia o Kernel
|
|
*/
|
|
async start(): Promise<void> {
|
|
if (this.started) {
|
|
return;
|
|
}
|
|
|
|
console.log('[Kernel] Iniciando Arcadia Kernel...');
|
|
console.log(`[Kernel] ${this.services.length} serviços configurados (services.json)`);
|
|
|
|
// Registra serviços no ProcessManager
|
|
for (const config of this.services) {
|
|
this.processManager.registerService(config);
|
|
}
|
|
|
|
// NOVO: Inicia Service Registry
|
|
if (this.serviceRegistry) {
|
|
await this.serviceRegistry.start();
|
|
}
|
|
|
|
// Inicia Dashboard
|
|
if (this.options.dashboard.enabled) {
|
|
this.dashboard = new DashboardServer(
|
|
this.processManager,
|
|
this.healthMonitor,
|
|
this.logAggregator,
|
|
{
|
|
port: this.options.dashboard.port,
|
|
host: this.options.dashboard.host,
|
|
}
|
|
);
|
|
await this.dashboard.start();
|
|
}
|
|
|
|
// Auto-start serviços
|
|
if (this.options.autoStart) {
|
|
console.log('[Kernel] Auto-iniciando serviços...');
|
|
await this.processManager.startAll(true);
|
|
|
|
// Inicia health monitoring para serviços em execução
|
|
for (const state of this.processManager.getAllStates()) {
|
|
if (state.status === 'running') {
|
|
this.healthMonitor.startMonitoring(state.config.id, state);
|
|
}
|
|
}
|
|
}
|
|
|
|
this.started = true;
|
|
console.log('[Kernel] Kernel iniciado com sucesso!');
|
|
|
|
// Eventos de shutdown
|
|
this.setupShutdownHandlers();
|
|
}
|
|
|
|
/**
|
|
* Para o Kernel
|
|
*/
|
|
async stop(): Promise<void> {
|
|
if (!this.started) {
|
|
return;
|
|
}
|
|
|
|
console.log('[Kernel] Parando Kernel...');
|
|
|
|
// NOVO: Para Service Registry
|
|
this.serviceRegistry?.stop();
|
|
|
|
// Para health monitor
|
|
this.healthMonitor.stopAll();
|
|
|
|
// Para todos os serviços
|
|
await this.processManager.stopAll(true);
|
|
|
|
// Para dashboard
|
|
await this.dashboard?.stop();
|
|
|
|
this.started = false;
|
|
console.log('[Kernel] Kernel parado.');
|
|
}
|
|
|
|
/**
|
|
* Retorna se o kernel está rodando
|
|
*/
|
|
isRunning(): boolean {
|
|
return this.started;
|
|
}
|
|
|
|
/**
|
|
* NOVO: Retorna estatísticas combinadas (ProcessManager + Registry)
|
|
*/
|
|
getStats(): { processManager: any; registry: any } {
|
|
return {
|
|
processManager: {
|
|
total: this.services.length,
|
|
states: this.processManager.getAllStates(),
|
|
},
|
|
registry: this.serviceRegistry?.getStats(),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* NOVO: Lista serviços descobertos (via Registry)
|
|
*/
|
|
getDiscoveredServices(): RegisteredService[] {
|
|
return this.serviceRegistry?.getServices() || [];
|
|
}
|
|
|
|
/**
|
|
* Carrega configurações dos serviços
|
|
*/
|
|
private loadConfig(): void {
|
|
try {
|
|
const configData = readFileSync(this.options.configPath, 'utf-8');
|
|
const config = JSON.parse(configData);
|
|
this.services = config.services || [];
|
|
} catch (error) {
|
|
console.error('[Kernel] Erro ao carregar config:', error);
|
|
this.services = [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Configura handlers de shutdown
|
|
*/
|
|
private setupShutdownHandlers(): void {
|
|
const shutdown = async (signal: string) => {
|
|
console.log(`\n[Kernel] Sinal ${signal} recebido. Desligando...`);
|
|
await this.stop();
|
|
process.exit(0);
|
|
};
|
|
|
|
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
|
|
process.on('uncaughtException', (error) => {
|
|
console.error('[Kernel] Uncaught Exception:', error);
|
|
});
|
|
|
|
process.on('unhandledRejection', (reason) => {
|
|
console.error('[Kernel] Unhandled Rejection:', reason);
|
|
});
|
|
}
|
|
}
|
|
|
|
// Exporta componentes individuais
|
|
export { ProcessManager } from './core/ProcessManager';
|
|
export { HealthMonitor } from './core/HealthMonitor';
|
|
export { LogAggregator } from './core/LogAggregator';
|
|
export { DashboardServer } from './dashboard/DashboardServer';
|
|
export { KernelWebSocket } from './websocket/KernelWebSocket';
|
|
export { createKernelRoutes } from './api/routes';
|
|
|
|
// NOVO: Exports do Registry e Discovery
|
|
export { ServiceRegistry } from './registry/ServiceRegistry';
|
|
export { DockerDiscovery } from './discovery/DockerDiscovery';
|
|
export type {
|
|
RegisteredService,
|
|
ServiceFilter,
|
|
RegistryEvent,
|
|
DiscoverySource,
|
|
ServiceCategory,
|
|
} from './registry/types';
|
|
|
|
export * from './types';
|
|
|
|
// Entry point para execução direta
|
|
try {
|
|
if (import.meta.url && import.meta.url === `file://${process.argv[1]}`) {
|
|
const kernel = new ArcadiaKernel({
|
|
dashboard: { enabled: true, port: 5001 },
|
|
autoStart: true,
|
|
});
|
|
|
|
kernel.start().catch((error) => {
|
|
console.error('[Kernel] Falha ao iniciar:', error);
|
|
process.exit(1);
|
|
});
|
|
}
|
|
} catch {
|
|
// No build CommonJS, o Kernel é iniciado pelo server/index.ts
|
|
}
|