|
|
| from datetime import datetime, timedelta |
| import json |
| import logging |
| from typing import Any, Dict, List, Optional |
| from sqlalchemy.dialects.postgresql import insert |
| from sqlalchemy.orm import Session |
|
|
| from core.database import SessionLocal |
| from core.models import DeviceNode, Workspace |
|
|
| logger = logging.getLogger("DEVICE_NODE_SERVICE") |
|
|
| class DeviceNodeService: |
| def __init__(self): |
| pass |
| |
| def get_db(self): |
| |
| return SessionLocal() |
|
|
| def register_node(self, db: Session, workspace_id: str, node_data: Dict[str, Any]) -> DeviceNode: |
| """ |
| Register or update a device node. |
| """ |
| device_id = node_data.get("deviceId") |
| if not device_id: |
| raise ValueError("deviceId is required") |
| |
| |
| name = node_data.get("name", "Unknown Device") |
| node_type = node_data.get("type", "desktop_marketing") |
| capabilities = node_data.get("capabilities", []) |
| metadata = node_data.get("metadata", {}) |
| |
| |
| node = db.query(DeviceNode).filter( |
| DeviceNode.workspace_id == workspace_id, |
| DeviceNode.device_id == device_id |
| ).first() |
| |
| if node: |
| |
| node.name = name |
| node.node_type = node_type |
| node.capabilities = capabilities |
| node.metadata_json = metadata |
| node.status = 'online' |
| node.last_seen = datetime.utcnow() |
| logger.info(f"Updated device node: {name} ({device_id})") |
| else: |
| |
| node = DeviceNode( |
| workspace_id=workspace_id, |
| device_id=device_id, |
| name=name, |
| node_type=node_type, |
| capabilities=capabilities, |
| metadata_json=metadata, |
| status='online', |
| last_seen=datetime.utcnow() |
| ) |
| db.add(node) |
| logger.info(f"Registered new device node: {name} ({device_id})") |
| |
| db.commit() |
| db.refresh(node) |
| return node |
| |
| def heartbeat(self, db: Session, workspace_id: str, device_id: str): |
| """ |
| Update last_seen for a node. |
| """ |
| node = db.query(DeviceNode).filter( |
| DeviceNode.workspace_id == workspace_id, |
| DeviceNode.device_id == device_id |
| ).first() |
| |
| if node: |
| node.last_seen = datetime.utcnow() |
| node.status = 'online' |
| db.commit() |
| |
| def get_active_nodes(self, db: Session, workspace_id: str, timeout_minutes: int = 5) -> List[DeviceNode]: |
| """ |
| Get all online nodes for a workspace. |
| """ |
| cutoff = datetime.utcnow() - timedelta(minutes=timeout_minutes) |
| return db.query(DeviceNode).filter( |
| DeviceNode.workspace_id == workspace_id, |
| DeviceNode.last_seen > cutoff |
| ).all() |
| |
| def set_status(self, db: Session, workspace_id: str, device_id: str, status: str): |
| """ |
| Manually set status (e.g. 'busy'). |
| """ |
| node = db.query(DeviceNode).filter( |
| DeviceNode.workspace_id == workspace_id, |
| DeviceNode.device_id == device_id |
| ).first() |
| |
| if node: |
| node.status = status |
| db.commit() |
|
|
| |
| device_node_service = DeviceNodeService() |
|
|