FP
This commit is contained in:
161
README.md
Normal file
161
README.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Stream Control
|
||||
|
||||
Plan de contrôle web pour piloter des enregistrements OBS répartis sur plusieurs VM/VPS
|
||||
(Windows et Ubuntu) depuis une seule interface.
|
||||
|
||||
```
|
||||
┌────────────┐ HTTPS + WS ┌──────────────────┐ WS sortant ┌──────────────────┐
|
||||
│ Navigateur │ ───────────────►│ Serveur de │◄────────────────│ Agent (VM) │
|
||||
│ dashboard │◄─── temps réel ─│ contrôle │──── commandes ─►│ └► OBS (4455) │
|
||||
└────────────┘ │ Express + SQLite│ └──────────────────┘
|
||||
└──────────────────┘ ┌──────────────────┐
|
||||
◄────────────────│ Agent (VM) … │
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
**Le sens des connexions est le point clé** : ce sont les agents qui se connectent au
|
||||
serveur, pas l'inverse. Aucun port entrant à ouvrir sur les VM d'enregistrement, aucune
|
||||
IP publique nécessaire, et obs-websocket reste sur `127.0.0.1`.
|
||||
|
||||
## Fonctionnalités
|
||||
|
||||
- Découverte automatique des agents par jeton d'enrôlement, ou provisionnement manuel.
|
||||
- État temps réel par VM : OBS connecté, enregistrement en cours, durée, taille du
|
||||
fichier, scène active, FPS, frames perdues, CPU, espace disque restant.
|
||||
- Commandes unitaires ou groupées : démarrer/arrêter/mettre en pause/découper un
|
||||
enregistrement, démarrer/arrêter un stream, changer de scène, de profil, de collection,
|
||||
changer le dossier d'enregistrement.
|
||||
- Journal d'évènements horodaté, persistant et diffusé en direct.
|
||||
- Reconnexion automatique de bout en bout (agent → serveur, agent → OBS, dashboard → serveur).
|
||||
|
||||
## Prérequis
|
||||
|
||||
- Node.js **22+** sur le serveur et sur chaque VM (le serveur utilise `node:sqlite`).
|
||||
- OBS **28+** sur chaque VM, avec *Outils → Paramètres du serveur WebSocket* activé.
|
||||
Note le port (4455 par défaut) et le mot de passe.
|
||||
|
||||
## Démarrage rapide (développement)
|
||||
|
||||
```bash
|
||||
npm install
|
||||
cp .env.example .env # renseigne ADMIN_PASSWORD, SESSION_SECRET, ENROLLMENT_TOKEN
|
||||
npm run dev # serveur :8080 + dashboard Vite :5173
|
||||
```
|
||||
|
||||
Puis, dans un autre terminal, un agent local :
|
||||
|
||||
```bash
|
||||
cd packages/agent
|
||||
cp agent.config.example.json agent.config.json # colle le ENROLLMENT_TOKEN dans "token"
|
||||
npm run dev
|
||||
```
|
||||
|
||||
L'agent s'enrôle, reçoit son jeton permanent, le réécrit dans `agent.config.json`, et
|
||||
apparaît dans le dashboard sur <http://localhost:5173>.
|
||||
|
||||
## Déploiement
|
||||
|
||||
### Serveur de contrôle
|
||||
|
||||
```bash
|
||||
npm ci && npm run build
|
||||
npm start # sert l'API, le WebSocket et le dashboard compilé sur $PORT
|
||||
```
|
||||
|
||||
Mets-le derrière un reverse proxy TLS ([exemple nginx](deploy/nginx.conf.example)) et
|
||||
installe l'unité systemd [`deploy/stream-control-server.service`](deploy/stream-control-server.service).
|
||||
`ADMIN_PASSWORD` et `SESSION_SECRET` sont obligatoires hors développement.
|
||||
|
||||
### Agent Ubuntu
|
||||
|
||||
Copie `packages/agent/dist`, `packages/agent/node_modules` et `agent.config.json` dans
|
||||
`/opt/stream-control-agent`, puis installe
|
||||
[`deploy/stream-control-agent.service`](deploy/stream-control-agent.service).
|
||||
|
||||
### Agent Windows
|
||||
|
||||
Un service Windows classique tourne en session 0 et ne verrait pas OBS. Utilise la tâche
|
||||
planifiée « à l'ouverture de session » fournie :
|
||||
|
||||
```powershell
|
||||
.\deploy\windows-agent-task.ps1 -AgentDir 'C:\stream-control-agent' -RunAsUser 'VM01\obs'
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Serveur — `.env` (voir [.env.example](.env.example))
|
||||
|
||||
| Variable | Rôle |
|
||||
| --- | --- |
|
||||
| `PORT`, `HOST` | Écoute HTTP/WebSocket |
|
||||
| `ADMIN_PASSWORD` | Mot de passe du dashboard |
|
||||
| `SESSION_SECRET` | Clé HMAC des sessions (32+ octets aléatoires) |
|
||||
| `ENROLLMENT_TOKEN` | Jeton d'auto-enregistrement ; vide = désactivé |
|
||||
| `DB_PATH` | Fichier SQLite |
|
||||
| `STATUS_INTERVAL_MS` | Fréquence de remontée d'état des agents |
|
||||
| `AGENT_TIMEOUT_MS` | Délai avant de déclarer un agent hors-ligne |
|
||||
|
||||
### Agent — `agent.config.json` (ou variables d'environnement)
|
||||
|
||||
| Clé | Variable | Rôle |
|
||||
| --- | --- | --- |
|
||||
| `serverUrl` | `SERVER_URL` | `wss://control.exemple.com/ws/agent` |
|
||||
| `token` | `AGENT_TOKEN` | Jeton d'enrôlement puis jeton propre à l'agent |
|
||||
| `name` | `AGENT_NAME` | Nom affiché (défaut : hostname) |
|
||||
| `obs.host/port/password` | `OBS_HOST` / `OBS_PORT` / `OBS_PASSWORD` | Repli local ; le serveur pousse la config de référence |
|
||||
| `insecureTls` | `INSECURE_TLS=1` | Accepter un certificat auto-signé |
|
||||
|
||||
Les paramètres OBS édités dans le dashboard sont poussés à chaud vers l'agent : pas
|
||||
besoin de se connecter à la VM pour changer un mot de passe obs-websocket.
|
||||
|
||||
## API HTTP
|
||||
|
||||
Toutes les routes hors `/api/login` exigent `Authorization: Bearer <jeton de session>`.
|
||||
|
||||
| Méthode | Route | Rôle |
|
||||
| --- | --- | --- |
|
||||
| `POST` | `/api/login` | Ouvre une session (`{ password }`) |
|
||||
| `GET` | `/api/agents` | Liste des agents et de leur état |
|
||||
| `POST` | `/api/agents` | Provisionne un agent, renvoie son jeton **une seule fois** |
|
||||
| `PATCH` | `/api/agents/:id` | Nom, notes, paramètres OBS, auto-connexion |
|
||||
| `POST` | `/api/agents/:id/token` | Régénère le jeton (coupe la session en cours) |
|
||||
| `DELETE` | `/api/agents/:id` | Supprime l'agent |
|
||||
| `POST` | `/api/agents/:id/command` | `{ action, params }`, attend le résultat de l'agent |
|
||||
| `POST` | `/api/commands/bulk` | Même action sur plusieurs agents, résultat par agent |
|
||||
| `GET` | `/api/logs?limit=` | Journal récent |
|
||||
| `GET` | `/healthz` | Sonde de vie (non authentifiée) |
|
||||
|
||||
Actions disponibles : `obs.connect`, `obs.disconnect`, `obs.refresh`, `record.start`,
|
||||
`record.stop`, `record.pause`, `record.resume`, `record.split`, `stream.start`,
|
||||
`stream.stop`, `scene.set`, `profile.set`, `collection.set`, `recordDirectory.set`,
|
||||
`agent.ping`.
|
||||
|
||||
## Structure
|
||||
|
||||
| Paquet | Rôle |
|
||||
| --- | --- |
|
||||
| [packages/shared/](packages/shared/) | Types du protocole, partagés par les trois autres |
|
||||
| [packages/server/](packages/server/) | API REST, passerelle agents, diffusion dashboard, SQLite |
|
||||
| [packages/agent/](packages/agent/) | Binaire à déployer sur chaque VM, pilote OBS |
|
||||
| [packages/web/](packages/web/) | Dashboard React/Vite |
|
||||
|
||||
Points d'entrée utiles : [packages/shared/src/index.ts](packages/shared/src/index.ts)
|
||||
(le protocole), [packages/server/src/hub.ts](packages/server/src/hub.ts) (état central et
|
||||
dispatch), [packages/agent/src/obs.ts](packages/agent/src/obs.ts) (traduction
|
||||
action → obs-websocket).
|
||||
|
||||
## Sécurité
|
||||
|
||||
- Les jetons d'agent ne sont stockés qu'en SHA-256 ; le clair n'est affiché qu'à la création.
|
||||
- Le mot de passe obs-websocket n'est jamais renvoyé au navigateur (masqué en `********`).
|
||||
- Les sessions dashboard sont des jetons HMAC à durée limitée, sans état serveur.
|
||||
- **Sers l'application en HTTPS/WSS** : jetons d'agent et de session circulent dans les
|
||||
en-têtes et les URL de WebSocket.
|
||||
- Après un `POST /api/agents/:id/token`, l'agent est déconnecté jusqu'à ce que son
|
||||
`agent.config.json` soit mis à jour.
|
||||
|
||||
## Pistes d'évolution
|
||||
|
||||
Enregistrements programmés (cron par agent), rapatriement automatique des fichiers
|
||||
(rclone/S3 déclenché à `record.stop`), alertes sur seuil d'espace disque ou de frames
|
||||
perdues, comptes utilisateurs multiples, groupes d'agents.
|
||||
Reference in New Issue
Block a user