Way to V2 messaging

This commit is contained in:
RobbStarkAustria
2026-03-30 14:18:56 +02:00
parent 9d256788bc
commit 77db2bc565
4 changed files with 371 additions and 35 deletions

View File

@@ -664,7 +664,88 @@ def _read_and_clear_meta():
return None
def send_screenshot_heartbeat(client, client_id, capture_type: str = "periodic"):
def _build_dashboard_payload(client_id: str, screenshot_info: dict, health: dict, capture_type: str, trigger_meta: dict = None) -> dict:
"""Build the dashboard payload in one canonical place.
Keeping payload assembly centralized avoids schema drift across call sites.
"""
published_at = datetime.now(timezone.utc).isoformat()
screenshot_age_s = None
if screenshot_info:
try:
ts = datetime.fromisoformat(screenshot_info["timestamp"])
screenshot_age_s = round((datetime.now(timezone.utc) - ts).total_seconds(), 1)
except Exception:
pass
capture_meta = {
"type": capture_type,
"captured_at": (trigger_meta or {}).get("captured_at") or (screenshot_info or {}).get("timestamp"),
"age_s": screenshot_age_s,
"triggered": bool(trigger_meta and trigger_meta.get("send_immediately")),
"send_immediately": bool(trigger_meta and trigger_meta.get("send_immediately")),
}
process_health_payload = None
if health:
process_health_payload = {
"event_id": health.get("event_id"),
"event_type": health.get("event_type"),
"current_process": health.get("current_process"),
"process_pid": health.get("process_pid"),
"process_status": health.get("process_status"),
"restart_count": health.get("restart_count", 0)
}
payload = {
# Legacy fields kept during migration so existing server parsing remains intact.
"timestamp": published_at,
"client_id": client_id,
"status": "alive",
"screenshot_type": capture_type,
"screenshot": screenshot_info,
"screenshot_age_s": screenshot_age_s,
"system_info": {
"hostname": socket.gethostname(),
"ip": get_ip(),
"uptime": time.time() # Could be replaced with actual uptime
},
# New grouped schema (v2-compat)
"message": {
"client_id": client_id,
"status": "alive",
},
"content": {
"screenshot": screenshot_info,
},
"runtime": {
"system_info": {
"hostname": socket.gethostname(),
"ip": get_ip(),
"uptime": time.time(),
},
"process_health": process_health_payload,
},
"metadata": {
"schema_version": "2.0-compat",
"producer": "simclient",
"published_at": published_at,
"capture": capture_meta,
"transport": {
"topic": f"infoscreen/{client_id}/dashboard",
"qos": 0,
"publisher": "simclient",
},
},
}
if process_health_payload:
payload["process_health"] = process_health_payload
return payload
def send_screenshot_heartbeat(client, client_id, capture_type: str = "periodic", trigger_meta: dict = None):
"""Send heartbeat with screenshot to server for dashboard monitoring"""
try:
screenshot_info = get_latest_screenshot()
@@ -672,39 +753,13 @@ def send_screenshot_heartbeat(client, client_id, capture_type: str = "periodic")
# Also read health state and include in heartbeat
health = read_health_state()
# Compute screenshot age so the server can flag stale images
screenshot_age_s = None
if screenshot_info:
try:
ts = datetime.fromisoformat(screenshot_info["timestamp"])
screenshot_age_s = round((datetime.now(timezone.utc) - ts).total_seconds(), 1)
except Exception:
pass
heartbeat_data = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"client_id": client_id,
"status": "alive",
"screenshot_type": capture_type,
"screenshot": screenshot_info,
"screenshot_age_s": screenshot_age_s,
"system_info": {
"hostname": socket.gethostname(),
"ip": get_ip(),
"uptime": time.time() # Could be replaced with actual uptime
}
}
# Include health info if available (from display_manager)
if health:
heartbeat_data["process_health"] = {
"event_id": health.get("event_id"),
"event_type": health.get("event_type"),
"current_process": health.get("current_process"),
"process_pid": health.get("process_pid"),
"process_status": health.get("process_status"),
"restart_count": health.get("restart_count", 0)
}
heartbeat_data = _build_dashboard_payload(
client_id=client_id,
screenshot_info=screenshot_info,
health=health,
capture_type=capture_type,
trigger_meta=trigger_meta,
)
# Send to dashboard monitoring topic
dashboard_topic = f"infoscreen/{client_id}/dashboard"
@@ -757,7 +812,7 @@ def screenshot_service_thread(client, client_id):
capture_type = meta['type'] if (triggered and meta) else "periodic"
if triggered:
logging.info(f"Sending triggered screenshot: type={capture_type}")
send_screenshot_heartbeat(client, client_id, capture_type)
send_screenshot_heartbeat(client, client_id, capture_type, trigger_meta=meta)
last_sent = now
except Exception as e:
logging.error(f"Screenshot service error: {e}")