"""Node endpoints — /v1/nodes/*""" from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession from meshbay_hub.api.deps import get_current_user from meshbay_hub.db.engine import get_db from meshbay_hub.db.models import IPLog, Node, User router = APIRouter(prefix="/v1/nodes", tags=["nodes"]) class NodeAnnounceRequest(BaseModel): pk_node: str endpoint_hint: str | None = None @router.post("/announce", status_code=201) async def announce_node( body: NodeAnnounceRequest, request: Request, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): node = Node( user_id=current_user.id, pk_node=body.pk_node, endpoint_hint=body.endpoint_hint, ) db.add(node) db.add(IPLog( user_id=current_user.id, event="node_announce", ip_address=_ip(request), detail=body.endpoint_hint, )) await db.commit() await db.refresh(node) return {"node_id": node.id} @router.get("/{node_id}") async def get_node( node_id: str, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): node = await db.get(Node, node_id) if not node: raise HTTPException(status_code=404, detail="Node not found") owner = await db.get(User, node.user_id) return { "node_id": node.id, "username": owner.username if owner else "", "pk_node": node.pk_node, "endpoint_hint": node.endpoint_hint, "announced_at": node.announced_at.isoformat(), } def _ip(request: Request) -> str: fwd = request.headers.get("X-Forwarded-For") if fwd: return fwd.split(",")[0].strip() return request.client.host if request.client else "unknown"