Flere anlegg – hovedscene, resepsjon, crew – og ett sted å sende fra, med avkryssing for hvilke soner meldingen skal til. Sentralen er en vanlig announcer med [zones] i config. En sone er en vanlig announcer med ANNOUNCER_MESH_SECRET. Samme image, ingen mode, og en sone kan brukes alene hvis sentralen faller ut. Hver avhengighet med C-kode har aarch64-wheel i uv.lock, så det samme bildet går på en Raspberry Pi uten å kompilere noe. Sentralen syntetiserer én gang og sender ferdig WAV (POST /api/play, multipart). Sonen trenger da verken nett, edge-tts eller Pipers 670 MB for det den får – Item.wav er hele endringen i avspillingen. Køene forblir per sone: dispatcheren har egen tråd og egen kø, leverer til hver sone i hver sin tråd med timeout, og går videre. En opptatt hovedscene holder ikke igjen resepsjonen, og en sone som er nede feiler alene – synlig per sone i UI og revisjonslogg. Auth gjenbrukes: ny leverandør mesh på header X-Mesh-Key (ikke Bearer – den leses av JWT-leverandøren, som avviser alt som ikke er et JWT før neste får prøve), med én handling, play. To regler som fulgte med: - play følger aldri med «alt åpent». Uten det kunne hvem som helst POSTe en WAV til en åpen sone og få den spilt. Testen for åpen modus fanget det. - En legitimasjon som vises fram og er feil gir 401 også der gjester ellers har lov. Før slapp en feil PIN i åpen modus stille gjennom som gjest. mesh teller ikke som innlogging for folk: en sone med bare nøkkelen har fortsatt åpen side lokalt. Planlagte sendinger husker sonene sine og fordeles gjennom dispatcheren; planen ender som sent hvis minst én sone tok imot, med «hovedscene: kø #3, crew: nede» som note. Hodeløs Pi: install.sh kjører loginctl enable-linger, ellers finnes ikke lydsocketen når ingen logger inn. docs/mesh.md tar også raspi-config for jack framfor HDMI. 38 nye tester, 148 totalt. Fordelingen testes uten nett med stubbet transport; selve HTTP-en testes mot en levende werkzeug-server, så den håndrullede multiparten møter Flask sin parser. Verifisert i compose med sentral og to soner: til alle, bare til én, og én sone stoppet. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
58 lines
2.4 KiB
YAML
58 lines
2.4 KiB
YAML
# Announcer i drift på klienten ved anlegget.
|
|
#
|
|
# ./install.sh setter opp alt, inkludert .env
|
|
# docker compose up -d senere, for hånd
|
|
#
|
|
# Testoppsettet med dummy-IdP ligger i compose.test.yaml, ikke her.
|
|
name: announcer
|
|
|
|
services:
|
|
announcer:
|
|
build: .
|
|
image: announcer:local
|
|
restart: unless-stopped
|
|
|
|
# BIND_IP er sikkerhetsmekanismen her, ikke ufw. Dockers publiserte
|
|
# porter går forbi ufw, så en ufw-regel ville ikke stengt noen ute.
|
|
# install.sh setter den til NetBird-adressen når wt0 finnes.
|
|
ports:
|
|
- "${BIND_IP:-0.0.0.0}:${ANNOUNCER_PORT:-8090}:8090"
|
|
|
|
# Må være brukeren som eier lydsocketen på verten, ellers kommer det
|
|
# ingen lyd. install.sh fyller inn id -u / id -g.
|
|
user: "${PUID:-1000}:${PGID:-1000}"
|
|
|
|
environment:
|
|
ANNOUNCER_SINK: ${ANNOUNCER_SINK:-}
|
|
ANNOUNCER_TITLE: ${ANNOUNCER_TITLE:-}
|
|
ANNOUNCER_PUBLIC_URL: ${ANNOUNCER_PUBLIC_URL:-}
|
|
# Hemmeligheter: hører i .env, ikke i config.toml.
|
|
ANNOUNCER_PIN: ${ANNOUNCER_PIN:-}
|
|
ANNOUNCER_JWT_SECRET: ${ANNOUNCER_JWT_SECRET:-}
|
|
ANNOUNCER_OIDC_CLIENT_SECRET: ${ANNOUNCER_OIDC_CLIENT_SECRET:-}
|
|
ANNOUNCER_SECRET_KEY: ${ANNOUNCER_SECRET_KEY:-}
|
|
ANNOUNCER_MESH_SECRET: ${ANNOUNCER_MESH_SECRET:-}
|
|
XDG_RUNTIME_DIR: ${XDG_RUNTIME_DIR:-/run/user/1000}
|
|
# Planlagte sendinger lagres som absolutt tid, så TZ påvirker dem ikke.
|
|
# Men uten den står loggen i UTC mens du står i CEST, og da blir det
|
|
# vanskelig å se om noe gikk som det skulle.
|
|
TZ: ${TZ:-Europe/Oslo}
|
|
|
|
volumes:
|
|
# Stemmer, buffer, logg, sesjonsnøkkel, egne jingler og config.toml.
|
|
- ./data:/data
|
|
# Lyden. Hele XDG_RUNTIME_DIR, ikke bare én socket, så både
|
|
# PipeWire (pipewire-0) og PulseAudio (pulse/native + cookie) virker.
|
|
- ${XDG_RUNTIME_DIR:-/run/user/1000}:${XDG_RUNTIME_DIR:-/run/user/1000}
|
|
|
|
# Containeren starter ved boot, altså før noen er logget inn grafisk.
|
|
# Da finnes ikke lydsocketen ennå, og avspilling feiler. Det retter seg
|
|
# selv: player_cmd() slås opp per melding, så første utrop etter
|
|
# innlogging virker uten at noe må startes om.
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c",
|
|
"import urllib.request;urllib.request.urlopen('http://127.0.0.1:8090/api/config',timeout=5)"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
start_period: 180s # første oppstart laster ned ~670 MB stemmer
|
|
retries: 3
|