make listener robust to bad data

This commit is contained in:
2025-09-05 08:47:31 +00:00
parent 76629b8e30
commit 4c44b98d53
8 changed files with 1437 additions and 216 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,13 @@
"commitId": "a1b2c3d4e5f6"
},
"changelog": [
{
"version": "2025.1.0-alpha.4",
"date": "2025-09-01",
"changes": [
"Grundstruktur für Deployment getestet und optimiert."
]
},
{
"version": "2025.1.0-alpha.3",
"date": "2025-08-30",

View File

@@ -123,21 +123,18 @@ services:
- infoscreen-net
scheduler:
image: ghcr.io/robbstarkaustria/infoscreen-scheduler:latest # Oder wo auch immer Ihre Images liegen
image: ghcr.io/robbstarkaustria/infoscreen-scheduler:latest
container_name: infoscreen-scheduler
restart: unless-stopped
depends_on:
# HINZUGEFÜGT: Stellt sicher, dass die DB vor dem Scheduler startet
db:
condition: service_healthy
mqtt:
condition: service_healthy
environment:
# HINZUGEFÜGT: Datenbank-Verbindungsstring
DB_CONN: "mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}"
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
DB_NAME: ${DB_NAME}
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MQTT_BROKER_URL: mqtt
MQTT_PORT: 1883
networks:
- infoscreen-net

View File

@@ -5,8 +5,8 @@ networks:
services:
listener:
build:
context: ./listener
dockerfile: Dockerfile
context: .
dockerfile: listener/Dockerfile
image: infoscreen-listener:latest
container_name: infoscreen-listener
restart: unless-stopped
@@ -16,6 +16,7 @@ services:
mqtt:
condition: service_healthy
environment:
- DB_CONN=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}
- DB_URL=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}
# 🔧 ENTFERNT: Volume-Mount ist nur für die Entwicklung
networks:
@@ -80,8 +81,8 @@ services:
server:
build:
context: ./server
dockerfile: Dockerfile
context: .
dockerfile: server/Dockerfile
image: infoscreen-api:latest
container_name: infoscreen-api
restart: unless-stopped
@@ -111,8 +112,8 @@ services:
# ✅ GEÄNDERT: Dashboard jetzt mit Node.js/React statt Python/Dash
dashboard:
build:
context: ./dashboard
dockerfile: Dockerfile
context: .
dockerfile: dashboard/Dockerfile
# 🔧 VEREINFACHT: Build-Args werden durch Umgebungsvariablen gesetzt
args:
- VITE_API_URL=${API_URL}
@@ -140,22 +141,23 @@ services:
scheduler:
build:
context: ./scheduler
dockerfile: Dockerfile
dockerfile: scheduler/Dockerfile
image: infoscreen-scheduler:latest
container_name: infoscreen-scheduler
restart: unless-stopped
depends_on:
# HINZUGEFÜGT: Stellt sicher, dass die DB vor dem Scheduler startet
db:
condition: service_healthy
mqtt:
condition: service_healthy
environment:
DB_CONN: "mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}"
MQTT_BROKER_URL: mqtt
MQTT_PORT: 1883
# HINZUGEFÜGT: Datenbank-Verbindungsstring
- DB_CONN=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}
- MQTT_PORT=1883
networks:
- infoscreen-net
volumes:
db-data:
server-pip-cache:
db-data:

View File

@@ -50,32 +50,35 @@ def on_message(client, userdata, msg):
# Discovery-Handling
payload = json.loads(msg.payload.decode())
logging.info(f"Discovery empfangen: {payload}")
session = Session()
existing = session.query(Client).filter_by(
uuid=payload["uuid"]).first()
if not existing:
new_client = Client(
uuid=payload.get("uuid"),
hardware_token=payload.get("hardware_token"),
ip=payload.get("ip"),
type=payload.get("type"),
hostname=payload.get("hostname"),
os_version=payload.get("os_version"),
software_version=payload.get("software_version"),
macs=",".join(payload.get("macs", [])),
model=payload.get("model"),
registration_time=datetime.datetime.now(datetime.UTC),
)
session.add(new_client)
session.commit()
logging.info(f"Neuer Client registriert: {payload['uuid']}")
if "uuid" in payload:
uuid = payload["uuid"]
session = Session()
existing = session.query(Client).filter_by(uuid=uuid).first()
if not existing:
new_client = Client(
uuid=uuid,
hardware_token=payload.get("hardware_token"),
ip=payload.get("ip"),
type=payload.get("type"),
hostname=payload.get("hostname"),
os_version=payload.get("os_version"),
software_version=payload.get("software_version"),
macs=",".join(payload.get("macs", [])),
model=payload.get("model"),
registration_time=datetime.datetime.now(datetime.UTC),
)
session.add(new_client)
session.commit()
logging.info(f"Neuer Client registriert: {uuid}")
else:
logging.info(f"Client bereits bekannt: {uuid}")
session.close()
# Discovery-ACK senden
ack_topic = f"infoscreen/{uuid}/discovery_ack"
client.publish(ack_topic, json.dumps({"status": "ok"}))
logging.info(f"Discovery-ACK gesendet an {ack_topic}")
else:
logging.info(f"Client bereits bekannt: {payload['uuid']}")
session.close()
# Discovery-ACK senden
ack_topic = f"infoscreen/{payload['uuid']}/discovery_ack"
client.publish(ack_topic, json.dumps({"status": "ok"}))
logging.info(f"Discovery-ACK gesendet an {ack_topic}")
logging.warning("Discovery ohne UUID empfangen, ignoriert.")
except Exception as e:
logging.error(f"Fehler bei Verarbeitung: {e}")

View File

@@ -5,4 +5,4 @@ RUN pip install --no-cache-dir -r requirements.txt
COPY scheduler/ ./scheduler
COPY models/ ./models
ENV PYTHONPATH=/app
CMD ["python", "scheduler/scheduler.py"]
CMD ["python", "-m", "scheduler.scheduler"]

View File

@@ -2,7 +2,7 @@
import os
import logging
from db_utils import get_active_events
from .db_utils import get_active_events
import paho.mqtt.client as mqtt
import json
import datetime

View File

@@ -20,16 +20,16 @@ ENV LANG=de_DE.UTF-8 \
LC_ALL=de_DE.UTF-8
# Setze das Arbeitsverzeichnis auf den Workspace-Root, passend zu den Mounts.
WORKDIR /workspace
WORKDIR /app
# Kopiere die Anforderungsdateien in das korrekte Unterverzeichnis.
# ✅ KORRIGIERT: Pfade sind jetzt relativ zum Build-Kontext (dem 'server'-Verzeichnis)
COPY requirements.txt requirements-dev.txt ./
COPY server/requirements.txt server/requirements-dev.txt ./server/
# Installiere die Python-Abhängigkeiten
RUN pip install --upgrade pip \
&& pip install --no-cache-dir -r requirements.txt \
&& pip install --no-cache-dir -r requirements-dev.txt
&& pip install --no-cache-dir -r server/requirements.txt \
&& pip install --no-cache-dir -r server/requirements-dev.txt
# Das Kopieren des Codes ist nicht nötig, da das Verzeichnis gemountet wird.