Way to V2 messaging
This commit is contained in:
125
src/simclient.py
125
src/simclient.py
@@ -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}")
|
||||
|
||||
Reference in New Issue
Block a user