Initial commit — DRB server stack

Includes c2-core (FastAPI/MQTT/Firestore), discord-bot (slash commands),
frontend (Next.js admin UI), and mosquitto config.
This commit is contained in:
Logan
2026-04-05 19:01:39 -04:00
commit 2f0597c81b
77 changed files with 4126 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
import asyncio
from datetime import datetime, timezone, timedelta
from app.config import settings
from app.internal.logger import logger
from app.internal import firestore as fstore
SWEEP_INTERVAL = 30 # seconds
async def sweeper_loop():
"""
Periodically check for nodes that haven't checked in recently
and mark them offline in Firestore.
"""
logger.info("Node sweeper started.")
while True:
await asyncio.sleep(SWEEP_INTERVAL)
try:
await _sweep()
except Exception as e:
logger.error(f"Sweeper error: {e}")
async def _sweep():
threshold = datetime.now(timezone.utc) - timedelta(seconds=settings.node_offline_threshold)
def _query():
from app.internal.firestore import db
return [
doc.to_dict()
for doc in db.collection("nodes").stream()
]
nodes = await asyncio.to_thread(_query)
for node in nodes:
status = node.get("status", "offline")
if status == "offline":
continue
last_seen_raw = node.get("last_seen")
if not last_seen_raw:
continue
# last_seen may be a Firestore Timestamp, a datetime, or an ISO string
if isinstance(last_seen_raw, str):
last_seen = datetime.fromisoformat(last_seen_raw)
else:
last_seen = last_seen_raw
if last_seen.tzinfo is None:
last_seen = last_seen.replace(tzinfo=timezone.utc)
if last_seen < threshold:
node_id = node.get("node_id")
await fstore.doc_update("nodes", node_id, {"status": "offline"})
logger.info(f"Node {node_id} marked offline (last seen: {last_seen.isoformat()})")