Feat : added and tweaked state machine
This commit is contained in:
@@ -3,6 +3,15 @@ import { DEFAULT_WATCH_SETTINGS, fetchStripchatStatus } from '@stream-control/sh
|
||||
import { config } from './config.ts';
|
||||
import { targetsRepo } from './db.ts';
|
||||
import { hub } from './hub.ts';
|
||||
import { startTargetRecording } from './recorder.ts';
|
||||
|
||||
/**
|
||||
* Tentatives d'amorçage automatique par diffusion. Les causes d'échec restantes
|
||||
* une fois les garde-fous passés (OBS injoignable, par exemple) sont surtout
|
||||
* persistantes : réessayer indéfiniment toutes les dix secondes noierait le
|
||||
* journal sans rien changer.
|
||||
*/
|
||||
const MAX_AUTO_ATTEMPTS = 3;
|
||||
|
||||
/**
|
||||
* Sonde périodiquement les profils surveillés et signale les passages en direct.
|
||||
@@ -14,6 +23,8 @@ import { hub } from './hub.ts';
|
||||
class Watchlist {
|
||||
private timer: NodeJS.Timeout | null = null;
|
||||
private running = false;
|
||||
/** Tentatives déjà faites pour la diffusion en cours, par profil. */
|
||||
private readonly autoAttempts = new Map<string, number>();
|
||||
|
||||
start(): void {
|
||||
if (this.timer) return;
|
||||
@@ -102,6 +113,7 @@ class Watchlist {
|
||||
if (!updated) return;
|
||||
|
||||
hub.publishTarget(updated);
|
||||
this.maybeAutoRecord(updated);
|
||||
|
||||
if (changed) {
|
||||
const name = updated.label ?? updated.username;
|
||||
@@ -113,6 +125,67 @@ class Watchlist {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Déclenche l'enregistrement d'un profil en automatisme, une fois qu'il est en
|
||||
* direct depuis assez longtemps.
|
||||
*
|
||||
* Le délai d'amorçage n'est pas une précaution de style : un modèle qui sort
|
||||
* d'un show privé repasse « public » quelques secondes avant de se remettre en
|
||||
* place, et un flux qui redémarre alterne parfois plusieurs fois. Enregistrer
|
||||
* sur la première lecture produirait des fichiers de dix secondes.
|
||||
*/
|
||||
private maybeAutoRecord(target: WatchTarget): void {
|
||||
if (target.state !== 'public') {
|
||||
// Diffusion terminée : la suivante aura droit à ses propres tentatives.
|
||||
this.autoAttempts.delete(target.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.autoRecord || !target.agentId) return;
|
||||
if ((this.autoAttempts.get(target.id) ?? 0) >= MAX_AUTO_ATTEMPTS) return;
|
||||
|
||||
// `statusChangedAt` vient de la plateforme et vaut mieux que notre première
|
||||
// observation : il survit à un redémarrage du serveur.
|
||||
const liveSince = target.statusChangedAt ?? target.stateSince;
|
||||
if (Date.now() - liveSince < config.autoRecordDelayMs) return;
|
||||
|
||||
if (!hub.isOnline(target.agentId)) return;
|
||||
// Une VM déjà occupée n'est jamais préemptée : l'enregistrement en cours
|
||||
// prime sur celui qu'on allait lancer.
|
||||
if (hub.statusOf(target.agentId).recording) return;
|
||||
|
||||
const agentId = target.agentId;
|
||||
const name = target.label ?? target.username;
|
||||
// Marqué avant l'appel : la séquence de capture dure plusieurs secondes, et
|
||||
// le cycle suivant ne doit pas en lancer une seconde en parallèle.
|
||||
const attempt = (this.autoAttempts.get(target.id) ?? 0) + 1;
|
||||
this.autoAttempts.set(target.id, attempt);
|
||||
|
||||
void startTargetRecording(target)
|
||||
.then(() => {
|
||||
this.autoAttempts.set(target.id, MAX_AUTO_ATTEMPTS);
|
||||
hub.log(
|
||||
agentId,
|
||||
'info',
|
||||
`Automatisme : enregistrement de ${name} démarré`,
|
||||
Date.now(),
|
||||
'capture.started',
|
||||
);
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const giveUp = attempt >= MAX_AUTO_ATTEMPTS;
|
||||
hub.log(
|
||||
agentId,
|
||||
'warn',
|
||||
`Automatisme : démarrage de ${name} en échec (${attempt}/${MAX_AUTO_ATTEMPTS}) — ${message}` +
|
||||
(giveUp ? '. Abandon jusqu\'à la prochaine diffusion.' : ''),
|
||||
Date.now(),
|
||||
'command.failed',
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function labelOf(state: StreamState): string {
|
||||
|
||||
Reference in New Issue
Block a user