#!/usr/bin/env python3 """Nerdhalla API server — serves POI data and server status.""" import json import sqlite3 import subprocess import sys from http.server import HTTPServer, BaseHTTPRequestHandler from urllib.parse import urlparse, parse_qs DB_PATH = "/tmp/valheim_poi.db" NERDCADE_SSH = "aelith@100.86.206.39" NERDCADE_PORT = 46129 class APIHandler(BaseHTTPRequestHandler): def do_GET(self): parsed = urlparse(self.path) path = parsed.path params = parse_qs(parsed.query) if path == "/api/status": self._handle_status() elif path == "/api/pois": self._handle_pois(params) else: self.send_error(404, "Not found") def _handle_status(self): try: result = subprocess.run( ["ssh", "-p", str(NERDCADE_PORT), "-o", "ConnectTimeout=5", "-o", "StrictHostKeyChecking=no", NERDCADE_SSH, "systemctl --user is-active amp* 2>/dev/null || echo 'inactive'"], capture_output=True, text=True, timeout=10 ) online = "active" in result.stdout.lower() data = {"online": online, "players": None} except Exception: data = {"online": False, "players": None} self._json_response(data) def _handle_pois(self, params): try: limit = min(int(params.get("limit", [500])[0]), 11309) offset = int(params.get("offset", [0])[0]) biome = params.get("biome", [None])[0] search = params.get("search", [None])[0] conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row cur = conn.cursor() where_clauses = [] bindings = [] if biome: where_clauses.append("category = ?") bindings.append(biome) if search: where_clauses.append("prefab_name LIKE ?") bindings.append(f"%{search}%") where = "" if where_clauses: where = "WHERE " + " AND ".join(where_clauses) cur.execute(f"SELECT pos_x, pos_y, pos_z, prefab_name, category FROM locations {where} ORDER BY prefab_name LIMIT ? OFFSET ?", bindings + [limit, offset]) rows = [{ "x": r["pos_x"], "y": r["pos_z"], # Valheim uses Z as north-south "prefab": r["prefab_name"], "category": r["category"] } for r in cur.fetchall()] conn.close() self._json_response(rows) except Exception as e: self._json_response({"error": str(e)}, status=500) def _json_response(self, data, status=200): body = json.dumps(data).encode() self.send_response(status) self.send_header("Content-Type", "application/json") self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) def log_message(self, format, *args): sys.stderr.write("[API] %s - %s\n" % (self.client_address[0], format % args)) if __name__ == "__main__": port = 8081 server = HTTPServer(("127.0.0.1", port), APIHandler) print(f"[Nerdhalla API] Listening on 127.0.0.1:{port}") server.serve_forever()