# dashboard/callbacks/overview_callbacks.py import sys sys.path.append('/workspace') import threading import dash import requests from dash import Input, Output, State, MATCH, html, dcc from flask import session from utils.db import get_session # Diese Funktion muss eine SQLAlchemy-Session liefern! from utils.mqtt_client import publish, start_loop from config import ENV import dash_bootstrap_components as dbc import os API_BASE_URL = os.getenv("API_BASE_URL", "http://infoscreen-api:8000") mqtt_thread_started = False SCREENSHOT_DIR = "received-screenshots" def ensure_mqtt_running(): global mqtt_thread_started if not mqtt_thread_started: thread = threading.Thread(target=start_loop, daemon=True) thread.start() mqtt_thread_started = True def get_latest_screenshot(client_uuid): # TODO: Hier genau im Produkitv-Modus die IPs testen! # Wenn API_BASE_URL auf "http" beginnt, absolute URL verwenden (z.B. im lokalen Dev) if API_BASE_URL.startswith("http"): return f"{API_BASE_URL}/screenshots/{client_uuid}" # Sonst relative URL (nginx-Proxy übernimmt das Routing) return f"/screenshots/{client_uuid}" def fetch_clients(): try: resp = requests.get(f"{API_BASE_URL}/api/clients") resp.raise_for_status() return resp.json() except Exception as e: print("Fehler beim Abrufen der Clients:", e) return [] @dash.callback( Output("clients-cards-container", "children"), Input("interval-update", "n_intervals") ) def update_clients(n): # ... Session-Handling wie gehabt ... ensure_mqtt_running() clients = fetch_clients() cards = [] for client in clients: uuid = client["uuid"] # screenshot = get_latest_screenshot(uuid) screenshot = get_latest_screenshot(uuid) # if screenshot[-3] != "jpg": # screenshot += ".jpg" print(f"UUID: {uuid}, Screenshot: {screenshot}") card = dbc.Card( [ dbc.CardHeader(client["location"]), dbc.CardBody([ html.Img( src=screenshot, style={"width": "160px", "height": "90px", "object-fit": "cover"}, ), html.P(f"IP: {client["ip_address"] or '-'}", className="card-text"), html.P(f"Letzte Aktivität: {client["last_alive"] or '-'}", className="card-text"), dbc.ButtonGroup([ dbc.Button("Reload Page", color="primary", id={"type": "btn-reload", "index": uuid}, n_clicks=0), dbc.Button("Restart Client", color="danger", id={"type": "btn-restart", "index": uuid}, n_clicks=0), ], className="mt-2"), html.Div(id={"type": "restart-feedback", "index": uuid}), html.Div(id={"type": "reload-feedback", "index": uuid}), ]), ], className="mb-4", style={"width": "18rem"}, ) cards.append(dbc.Col(card, width=4)) return dbc.Row(cards) @dash.callback( Output({"type": "restart-feedback", "index": MATCH}, "children"), Input({"type": "btn-restart", "index": MATCH}, "n_clicks"), State({"type": "btn-restart", "index": MATCH}, "id") ) def on_restart(n_clicks, btn_id): if n_clicks and n_clicks > 0: cid = btn_id["index"] payload = '{"command": "restart"}' ok = publish(f"clients/{cid}/control", payload) return "Befehl gesendet." if ok else "Fehler beim Senden." return "" @dash.callback( Output({"type": "reload-feedback", "index": MATCH}, "children"), Input({"type": "btn-reload", "index": MATCH}, "n_clicks"), State({"type": "btn-reload", "index": MATCH}, "id") ) def on_reload(n_clicks, btn_id): if n_clicks and n_clicks > 0: cid = btn_id["index"] payload = '{"command": "reload"}' ok = publish(f"clients/{cid}/control", payload) return "Befehl gesendet." if ok else "Fehler beim Senden." return ""