177 lines
5.2 KiB
TypeScript
177 lines
5.2 KiB
TypeScript
/**
|
|
* Static Discovery Provider
|
|
* Descobre serviços pela rede Docker interna (DNS)
|
|
* Arcadia Kernel - Módulo de Service Discovery
|
|
*/
|
|
|
|
import { DiscoveryProvider, RegisteredService, ServiceCategory } from '../registry/types';
|
|
import { HealthStatus } from '../types';
|
|
|
|
// Lista de serviços Arcádia conhecidos
|
|
const ARCADIA_SERVICES = [
|
|
{
|
|
id: 'motor-contabil',
|
|
name: 'motor-contabil',
|
|
displayName: 'Motor Contábil',
|
|
type: 'python' as const,
|
|
category: 'contabil' as ServiceCategory,
|
|
host: 'arcadia-prod-contabil-1',
|
|
port: 8003,
|
|
capabilities: ['lancamentos', 'dre', 'balancete', 'razao'],
|
|
requiresIA: false,
|
|
description: 'Contabilidade - Lançamentos, DRE, Balancete, Razão',
|
|
},
|
|
{
|
|
id: 'motor-bi',
|
|
name: 'motor-bi',
|
|
displayName: 'Motor BI',
|
|
type: 'python' as const,
|
|
category: 'bi' as ServiceCategory,
|
|
host: 'arcadia-prod-bi-1',
|
|
port: 8004,
|
|
capabilities: ['sql', 'charts', 'microbi', 'cache'],
|
|
requiresIA: true,
|
|
iaPolicies: ['bi', 'lgpd'],
|
|
description: 'Business Intelligence - SQL, Charts, Micro-BI, Cache',
|
|
},
|
|
{
|
|
id: 'motor-fiscal',
|
|
name: 'motor-fiscal',
|
|
displayName: 'Motor Fiscal',
|
|
type: 'python' as const,
|
|
category: 'fiscal' as ServiceCategory,
|
|
host: 'arcadia-prod-fisco-1',
|
|
port: 8002,
|
|
capabilities: ['nfe', 'nfce', 'ncm', 'cfop', 'cest', 'sefaz'],
|
|
requiresIA: true,
|
|
iaPolicies: ['fiscal'],
|
|
description: 'NF-e/NFC-e - NCMs, CFOPs, CESTs, SEFAZ',
|
|
},
|
|
{
|
|
id: 'motor-automacao',
|
|
name: 'motor-automacao',
|
|
displayName: 'Motor Automação',
|
|
type: 'python' as const,
|
|
category: 'automation' as ServiceCategory,
|
|
host: 'arcadia-prod-automation-1',
|
|
port: 8005,
|
|
capabilities: ['scheduler', 'eventbus', 'workflow'],
|
|
requiresIA: true,
|
|
iaPolicies: ['automation'],
|
|
description: 'Scheduler, Event Bus, Workflow Executor',
|
|
},
|
|
{
|
|
id: 'servico-embeddings',
|
|
name: 'servico-embeddings',
|
|
displayName: 'Serviço Embeddings',
|
|
type: 'python' as const,
|
|
category: 'ai' as ServiceCategory,
|
|
host: 'arcadia-prod-embeddings-1',
|
|
port: 8001,
|
|
capabilities: ['embeddings', 'vectorsearch'],
|
|
requiresIA: true,
|
|
iaPolicies: ['ai', 'lgpd'],
|
|
description: 'Embeddings e Vector Search com pgvector',
|
|
},
|
|
{
|
|
id: 'metaset-bi',
|
|
name: 'metaset-bi',
|
|
displayName: 'MetaSet BI',
|
|
type: 'java' as const,
|
|
category: 'data' as ServiceCategory,
|
|
host: 'arcadia-prod-superset-1',
|
|
port: 8088,
|
|
capabilities: ['dashboards', 'charts', 'sql_lab', 'datasets'],
|
|
requiresIA: false,
|
|
description: 'Motor de BI - Consultas, Dashboards, Gráficos, Análises',
|
|
version: '4.1.0',
|
|
},
|
|
{
|
|
id: 'motor-comunicacao',
|
|
name: 'motor-comunicacao',
|
|
displayName: 'Motor Comunicação',
|
|
type: 'node' as const,
|
|
category: 'communication' as ServiceCategory,
|
|
host: 'arcadia-prod-miroflow-1',
|
|
port: 8006,
|
|
capabilities: ['inbox', 'whatsapp', 'canais'],
|
|
requiresIA: true,
|
|
iaPolicies: ['communication'],
|
|
description: 'Inbox Unificada, Contatos, Threads, Canais',
|
|
},
|
|
];
|
|
|
|
export class StaticDiscovery implements DiscoveryProvider {
|
|
public readonly name = 'StaticDiscovery';
|
|
|
|
async isAvailable(): Promise<boolean> {
|
|
// Sempre disponível - não depende de Docker
|
|
return true;
|
|
}
|
|
|
|
async discover(): Promise<RegisteredService[]> {
|
|
const services: RegisteredService[] = [];
|
|
const now = new Date();
|
|
|
|
for (const config of ARCADIA_SERVICES) {
|
|
try {
|
|
// Tenta fazer health check no serviço
|
|
const isHealthy = await this.checkHealth(config.host, config.port);
|
|
|
|
if (isHealthy) {
|
|
services.push({
|
|
id: `static-${config.id}`,
|
|
name: config.name,
|
|
displayName: config.displayName,
|
|
type: config.type,
|
|
category: config.category,
|
|
description: config.description,
|
|
host: config.host,
|
|
port: config.port,
|
|
endpoint: `http://${config.host}:${config.port}`,
|
|
healthCheckPath: '/health',
|
|
healthStatus: 'healthy' as HealthStatus,
|
|
lastHealthCheck: now,
|
|
capabilities: config.capabilities.map(cap => ({
|
|
name: cap,
|
|
version: '1.0.0',
|
|
endpoints: [`/${cap}`],
|
|
})),
|
|
requiresIA: config.requiresIA,
|
|
iaPolicies: config.iaPolicies,
|
|
metadata: {
|
|
source: 'static',
|
|
discoveredAt: now,
|
|
lastUpdated: now,
|
|
labels: {},
|
|
},
|
|
enabled: true,
|
|
version: config.version,
|
|
});
|
|
}
|
|
} catch (error) {
|
|
// Serviço não respondeu, não adiciona
|
|
console.log(`[StaticDiscovery] ${config.displayName} não respondeu`);
|
|
}
|
|
}
|
|
|
|
return services;
|
|
}
|
|
|
|
private async checkHealth(host: string, port: number): Promise<boolean> {
|
|
try {
|
|
const controller = new AbortController();
|
|
const timeout = setTimeout(() => controller.abort(), 3000);
|
|
|
|
const response = await fetch(`http://${host}:${port}/health`, {
|
|
signal: controller.signal,
|
|
});
|
|
|
|
clearTimeout(timeout);
|
|
return response.ok;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
}
|