Add API server and Caddy config
This commit is contained in:
parent
5ea3feb015
commit
210cf6b73a
2 changed files with 116 additions and 0 deletions
95
api_server.py
Normal file
95
api_server.py
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
#!/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()
|
||||||
21
nerdhalla.conf
Normal file
21
nerdhalla.conf
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
nerdhalla.nerdcade.cc {
|
||||||
|
root * /var/www/nerdhalla
|
||||||
|
file_server
|
||||||
|
|
||||||
|
# API reverse proxy
|
||||||
|
handle_path /api/* {
|
||||||
|
reverse_proxy 127.0.0.1:8081
|
||||||
|
}
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
header {
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "DENY"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/nerdhalla.log
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue