import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import type { ObsSettings } from '@stream-control/shared'; import { DEFAULT_OBS_SETTINGS } from '@stream-control/shared'; export interface AgentConfig { /** URL WebSocket du serveur de contrôle, ex. wss://control.exemple.com/ws/agent */ serverUrl: string; /** Jeton d'enrôlement au premier démarrage, puis jeton propre à l'agent. */ token: string; /** Attribué par le serveur lors de l'enrôlement. */ agentId?: string; /** Nom affiché dans le dashboard. */ name: string; /** Repli local si le serveur n'a pas encore poussé de configuration OBS. */ obs: ObsSettings; /** Ignorer les erreurs de certificat TLS (utile en auto-signé). */ insecureTls?: boolean; } const CONFIG_PATH = path.resolve( process.env.AGENT_CONFIG ?? path.join(process.cwd(), 'agent.config.json'), ); function readFile(): Partial { if (!fs.existsSync(CONFIG_PATH)) return {}; try { // Les éditeurs Windows (et Set-Content -Encoding UTF8) préfixent un BOM que // JSON.parse rejette. const raw = fs.readFileSync(CONFIG_PATH, 'utf8').replace(/^\uFEFF/, ''); return JSON.parse(raw) as Partial; } catch (err) { console.error(`Configuration illisible (${CONFIG_PATH}) :`, err); return {}; } } /** Le fichier fournit les valeurs par défaut, l'environnement a priorité. */ export function loadConfig(): AgentConfig { const file = readFile(); const config: AgentConfig = { serverUrl: process.env.SERVER_URL ?? file.serverUrl ?? 'ws://127.0.0.1:8080/ws/agent', token: process.env.AGENT_TOKEN ?? file.token ?? '', agentId: process.env.AGENT_ID ?? file.agentId, name: process.env.AGENT_NAME ?? file.name ?? os.hostname(), obs: { host: process.env.OBS_HOST ?? file.obs?.host ?? DEFAULT_OBS_SETTINGS.host, port: Number(process.env.OBS_PORT ?? file.obs?.port ?? DEFAULT_OBS_SETTINGS.port), password: process.env.OBS_PASSWORD ?? file.obs?.password ?? DEFAULT_OBS_SETTINGS.password, }, insecureTls: process.env.INSECURE_TLS === '1' || file.insecureTls === true, }; if (!config.token) { throw new Error( `Aucun jeton. Renseigne "token" dans ${CONFIG_PATH} (jeton d'enrôlement ou jeton d'agent) ou la variable AGENT_TOKEN.`, ); } return config; } /** * Persiste l'identité reçue du serveur pour que les redémarrages suivants * réutilisent le jeton permanent au lieu du jeton d'enrôlement. */ export function persistIdentity(agentId: string, token: string): void { const current = readFile(); const next = { ...current, agentId, token }; try { fs.writeFileSync(CONFIG_PATH, `${JSON.stringify(next, null, 2)}\n`, { mode: 0o600 }); console.log(`Identité d'agent enregistrée dans ${CONFIG_PATH}`); } catch (err) { console.error( `Impossible d'écrire ${CONFIG_PATH} — l'agent devra se ré-enrôler au prochain démarrage :`, err, ); } } export { CONFIG_PATH };