feat: implement async command execution, improve client status tracking, and expand takeleap diagnostic commands.

This commit is contained in:
2026-06-04 15:48:38 +05:30
parent c4a96adfc1
commit 25e9b5e120
3 changed files with 199 additions and 39 deletions

View File

@@ -123,8 +123,25 @@ def append_to_logs(log_type: str, client_id: str, detail: Any):
except Exception as e:
print(f"[!] Error writing log to MongoDB: {e}")
def mark_client_active(client_id: str, clients: Dict[str, Any]):
if client_id in clients:
was_active = clients[client_id].get("active", False)
if not was_active:
if client_id in last_down_notification_times:
send_rocketchat_notification(
text=f"✅ **System UP:** Client `{client_id}` has recovered and is back online.",
color="#2ecc71"
)
last_down_notification_times.pop(client_id, None)
clients[client_id]["active"] = True
clients[client_id]["last_seen"] = datetime.now().isoformat()
def load_clients() -> Dict[str, Any]:
try:
# Clean up any ghost clients with empty or whitespace-only keys
clients_collection.delete_many({"_id": {"$in": ["", None]}})
clients_collection.delete_many({"_id": {"$regex": "^\\s*$"}})
# If collection is empty, seed it with default registry
if clients_collection.count_documents({}) == 0:
default_data = {
@@ -248,6 +265,9 @@ async def get_command(client_id: str):
Endpoint for clients to poll for pending commands.
Client Agent hits this endpoint to ask: "Do I have any work to do?"
"""
if not client_id or not client_id.strip():
raise HTTPException(status_code=400, detail="client_id cannot be empty")
clients = load_clients()
# 1. Auto-register new client if we haven't seen it yet
@@ -264,8 +284,7 @@ async def get_command(client_id: str):
# 3. Reset the command to "none", mark active, and update last_seen timestamp
clients[client_id]["pending_command"] = "none"
clients[client_id]["active"] = True
clients[client_id]["last_seen"] = datetime.now().isoformat()
mark_client_active(client_id, clients)
save_clients(clients)
return {"command": cmd}
@@ -297,6 +316,9 @@ async def receive_telemetry(client_id: str, payload: TelemetryPayload):
"""
Endpoint for agents to push their live hardware telemetry.
"""
if not client_id or not client_id.strip():
raise HTTPException(status_code=400, detail="client_id cannot be empty")
clients = load_clients()
# Auto-register new client if we see it through telemetry first
@@ -305,8 +327,7 @@ async def receive_telemetry(client_id: str, payload: TelemetryPayload):
clients[client_id] = {"pending_command": "none", "last_seen": None, "active": True}
# Update last_seen timestamp, active status, and store the current telemetry details
clients[client_id]["last_seen"] = datetime.now().isoformat()
clients[client_id]["active"] = True
mark_client_active(client_id, clients)
clients[client_id]["telemetry"] = payload.dict()
save_clients(clients)
@@ -397,6 +418,9 @@ async def receive_command_result(client_id: str, payload: CommandResultPayload):
"""
Endpoint for remote agents to push execution results back to the central server.
"""
if not client_id or not client_id.strip():
raise HTTPException(status_code=400, detail="client_id cannot be empty")
append_to_logs("command_result", client_id, payload.dict())
return {"status": "success"}