summaryrefslogtreecommitdiff
path: root/playground/web/server.py
blob: 56ae42994cae8a34208a97d5300eb2a685f2fe0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/usr/bin/env python3
"""
Playground demo service — stdlib HTTP status page on port 9090.
Registered behind doot's auth layer at /playground/.
Start: python3 playground/web/server.py
"""

import http.server
import json
import os
import platform
import socket
import time
from datetime import datetime, timezone

START_TIME = time.monotonic()
PORT = int(os.environ.get("PLAYGROUND_PORT", "9090"))

STATUS_HTML = """\
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Playground — System Status</title>
<style>
  body {{ font-family: monospace; background: #0f111a; color: #cdd6f4; margin: 0; padding: 2rem; }}
  h1 {{ color: #89b4fa; margin-bottom: 0.25rem; }}
  .subtitle {{ color: #6c7086; font-size: 0.85rem; margin-bottom: 2rem; }}
  table {{ border-collapse: collapse; width: 100%; max-width: 640px; }}
  td {{ padding: 0.4rem 0.8rem; border-bottom: 1px solid #313244; }}
  td:first-child {{ color: #a6e3a1; width: 200px; }}
  .badge {{ display: inline-block; background: #1e6e3a; color: #a6e3a1;
             padding: 0.1rem 0.5rem; border-radius: 3px; font-size: 0.8rem; }}
</style>
</head>
<body>
<h1>Playground</h1>
<p class="subtitle">doot service gateway demo &mdash; authenticated via doot session</p>
<table>
  <tr><td>status</td><td><span class="badge">ok</span></td></tr>
  <tr><td>hostname</td><td>{hostname}</td></tr>
  <tr><td>python</td><td>{python}</td></tr>
  <tr><td>platform</td><td>{platform}</td></tr>
  <tr><td>uptime</td><td>{uptime}</td></tr>
  <tr><td>server time</td><td>{now}</td></tr>
  <tr><td>pid</td><td>{pid}</td></tr>
  <tr><td>port</td><td>{port}</td></tr>
</table>
</body>
</html>
"""


def _uptime() -> str:
    elapsed = int(time.monotonic() - START_TIME)
    h, rem = divmod(elapsed, 3600)
    m, s = divmod(rem, 60)
    return f"{h}h {m}m {s}s"


class Handler(http.server.BaseHTTPRequestHandler):
    def log_message(self, fmt, *args):  # quieter logs
        print(f"{self.address_string()} {fmt % args}")

    def do_GET(self):
        if self.path in ("/health", "/health/"):
            body = json.dumps({"status": "ok", "uptime": _uptime()}).encode()
            self._respond(200, "application/json", body)
            return

        html = STATUS_HTML.format(
            hostname=socket.gethostname(),
            python=platform.python_version(),
            platform=platform.system() + " " + platform.release(),
            uptime=_uptime(),
            now=datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC"),
            pid=os.getpid(),
            port=PORT,
        ).encode()
        self._respond(200, "text/html; charset=utf-8", html)

    def _respond(self, code, content_type, body):
        self.send_response(code)
        self.send_header("Content-Type", content_type)
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


if __name__ == "__main__":
    server = http.server.HTTPServer(("127.0.0.1", PORT), Handler)
    print(f"playground listening on http://127.0.0.1:{PORT}  (pid {os.getpid()})")
    server.serve_forever()