Files
infoscreen/dashboard/callbacks/overview_callbacks.py

105 lines
3.8 KiB
Python

# dashboard/callbacks/overview_callbacks.py
import sys
print(sys.path)
import threading
import dash
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
from server.models import Client
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):
prefix = f"{client_uuid}_"
try:
files = [f for f in os.listdir('..', SCREENSHOT_DIR) if f.startswith(prefix)]
if not files:
return "/assets/placeholder.png"
latest = max(files, key=lambda x: os.path.getmtime(os.path.join('.', SCREENSHOT_DIR, x)))
return f"/received-screenshots/{latest}"
except Exception:
return "/assets/placeholder.png"
@dash.callback(
Output("clients-cards-container", "children"),
Input("interval-update", "n_intervals")
)
def update_clients(n):
# Auto-Login im Development-Modus
if "role" not in session:
if ENV == "development":
session["role"] = "admin"
else:
return dcc.Location(id="redirect-login", href="/login")
ensure_mqtt_running()
session_db = get_session()
clients = session_db.query(Client).all()
session_db.close()
cards = []
for client in clients:
uuid = client.uuid
screenshot = get_latest_screenshot(uuid)
card = dbc.Card(
[
dbc.CardHeader(client.location or client.hardware_hash),
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 ""