Feat : STRCHA Stream status

This commit is contained in:
jeanotx32
2026-08-11 00:52:33 +02:00
parent 6f11b72cbb
commit b529417940
13 changed files with 1038 additions and 14 deletions

View File

@@ -2,14 +2,24 @@
import os from 'node:os';
import { WebSocket } from 'ws';
import type {
AgentAction,
AgentStatus,
AgentToServer,
LogLevel,
ServerToAgent,
WatchSettings,
} from '@stream-control/shared';
import {
DEFAULT_WATCH_SETTINGS,
PROTOCOL_VERSION,
detectPlatform,
emptyStatus,
normalizeWatchSettings,
safeJsonParse,
} from '@stream-control/shared';
import { PROTOCOL_VERSION, detectPlatform, emptyStatus, safeJsonParse } from '@stream-control/shared';
import { loadConfig, persistIdentity, type AgentConfig } from './config.ts';
import { ObsController } from './obs.ts';
import { StreamWatcher } from './watcher.ts';
import { cpuUsagePercent, diskUsage, memoryUsage } from './system.ts';
const AGENT_VERSION = '0.1.0';
@@ -26,6 +36,16 @@ try {
const obs = new ObsController(config.obs);
const watcher = new StreamWatcher(DEFAULT_WATCH_SETTINGS, {
recordState: () => obs.recordState(),
pauseRecording: async () => {
await obs.execute('record.pause');
},
resumeRecording: async () => {
await obs.execute('record.resume');
},
});
let socket: WebSocket | null = null;
let statusTimer: NodeJS.Timeout | null = null;
let reconnectDelay = RECONNECT_MIN_MS;
@@ -47,6 +67,7 @@ function report(level: LogLevel, message: string): void {
}
obs.on('log', (level: LogLevel, message: string) => report(level, message));
watcher.on('log', (level: LogLevel, message: string) => report(level, message));
function connect(): void {
if (shuttingDown) return;
@@ -114,6 +135,7 @@ async function handleServerMessage(message: ServerToAgent): Promise<void> {
}
obs.applySettings(message.obs);
applyWatchSettings(message.watch);
report('info', `Agent « ${config.name} » rattaché au serveur (id ${message.agentId})`);
if (message.autoConnectObs && !obs.isConnected) {
@@ -125,6 +147,7 @@ async function handleServerMessage(message: ServerToAgent): Promise<void> {
case 'config': {
obs.applySettings(message.obs);
applyWatchSettings(message.watch);
if (message.autoConnectObs && !obs.isConnected) {
obs.connect().catch((err: Error) => report('warn', err.message));
}
@@ -133,7 +156,7 @@ async function handleServerMessage(message: ServerToAgent): Promise<void> {
case 'command': {
try {
const data = await obs.execute(message.action, message.params ?? {});
const data = await runAction(message.action, message.params ?? {});
send({ type: 'result', requestId: message.requestId, ok: true, data });
void pushStatus(); // état rafraîchi immédiatement après l'action
} catch (err) {
@@ -151,6 +174,25 @@ async function handleServerMessage(message: ServerToAgent): Promise<void> {
}
}
/**
* Aiguille une action : la surveillance et le clavier sont gérés par l'agent,
* tout le reste part vers obs-websocket.
*/
async function runAction(action: AgentAction, params: Record<string, unknown>): Promise<unknown> {
switch (action) {
case 'watch.check':
return watcher.checkNow();
case 'hotkey.fullscreen':
return watcher.restoreFullscreen();
default:
return obs.execute(action, params);
}
}
function applyWatchSettings(raw: WatchSettings | undefined): void {
watcher.applySettings(normalizeWatchSettings(raw ?? DEFAULT_WATCH_SETTINGS));
}
// --- Boucle de statut --------------------------------------------------------
async function buildStatus(): Promise<AgentStatus> {
@@ -161,6 +203,7 @@ async function buildStatus(): Promise<AgentStatus> {
return {
...emptyStatus(),
...snapshot,
watch: watcher.snapshot,
lastRecordingPath: obs.recordingPath,
systemCpu: cpuUsagePercent(),
systemMemoryUsed: memory.used,
@@ -199,6 +242,7 @@ async function shutdown(signal: string): Promise<void> {
shuttingDown = true;
console.log(`\n${signal} reçu, arrêt de l'agent…`);
stopStatusLoop();
watcher.stop();
// L'enregistrement OBS en cours n'est volontairement pas interrompu.
await obs.disconnect().catch(() => undefined);
socket?.close(1000, 'Arrêt de l\'agent');