Refatora infraestrutura de dados, build e provisionamento de streams

---

- Movido streams.json para /app/data/streams/streams.json; volume do compose mapeado especificamente em /app/data/streams, deixando logs fora do volume persistido;
- Adicionado scripts/reprovision.mjs que regenera stream.conf e tokens VNC a partir dos templates da imagem no startup, garantindo que updates de container não exijam recriar o volume;
- Removido autologin.template.sh por-stream; substituído por scripts/autologin.sh global na imagem, com variáveis passadas via environment= no supervisor conf (com valores entre aspas
para compatibilidade com valores vazios);
- Logs de processos por stream movidos de /app/data/streams/{id}/ para /app/data/logs/{id}/;
- Adicionada função recreateStream em supervisor.ts e rota POST /api/streams/[id]/recreate; botão "Recreate" adicionado ao menu do card para limpar chrome-profile e re-provisionar;
- Adicionado auto-disparo de captureThumb no GET /api/streams/[id]/thumb quando thumb.jpg não existe e nenhuma captura está em andamento;
- Dockerfile: adicionado --mount=type=cache para /var/cache/apt e /var/lib/apt/lists (não /var/lib/apt inteiro para evitar corrupção de estado); removido --no-cache do Makefile; remoção
de pacotes limitada a curl gnupg para evitar cascata em dependências do chromium/novnc;
- Migração automática de streams.json do caminho antigo adicionada ao entrypoint.sh;

---
This commit is contained in:
2026-04-25 15:08:25 -03:00
parent f6879781c1
commit 40824c08a4
13 changed files with 174 additions and 82 deletions
+12 -7
View File
@@ -42,6 +42,7 @@ export function normalizeScale(scale: string): string {
export function provisionStream(stream: Stream): void {
const dir = streamDir(stream.id)
fs.mkdirSync(path.join(dir, "chrome-profile"), { recursive: true })
fs.mkdirSync(path.join(DATA_DIR, "logs", stream.id), { recursive: true })
const vars: Record<string, string | number> = {
STREAM_ID: stream.id,
@@ -64,14 +65,8 @@ export function provisionStream(stream: Stream): void {
PASS: stream.pass ?? "",
}
const autologinTpl = fs.readFileSync("/opt/scripts/autologin.template.sh", "utf-8")
const autologinPath = path.join(dir, "autologin.sh")
fs.writeFileSync(autologinPath, render(autologinTpl, vars), "utf-8")
fs.chmodSync(autologinPath, 0o755)
const confTpl = fs.readFileSync("/opt/scripts/stream.template.conf", "utf-8")
const confPath = path.join(dir, "stream.conf")
fs.writeFileSync(confPath, render(confTpl, vars), "utf-8")
fs.writeFileSync(path.join(dir, "stream.conf"), render(confTpl, vars), "utf-8")
fs.mkdirSync(VNC_TOKENS_DIR, { recursive: true })
fs.writeFileSync(
@@ -84,6 +79,16 @@ export function provisionStream(stream: Stream): void {
supervisorctl("update")
}
export function recreateStream(id: string): void {
const stream = getStream(id)
if (!stream) return
stopStream(id)
const dir = streamDir(id)
fs.rmSync(path.join(dir, "chrome-profile"), { recursive: true, force: true })
provisionStream(stream)
startStream(id)
}
export function startStream(id: string): void {
const programs = ["xvfb", "chromium", "autologin", "x11vnc", "ffmpeg"]
for (const p of programs) supervisorctl(`start ${p}-${id}`)