A Python port of the Invisible Internet Project (I2P)
at main 74 lines 2.0 kB view raw
1"""Minimal HTTP health endpoint using raw asyncio. 2 3No external dependencies — just a bare TCP server that speaks enough 4HTTP to return JSON status. Runs on a separate port from the NTCP2 5transport (default 9701). 6""" 7 8from __future__ import annotations 9 10import asyncio 11import json 12import logging 13 14logger = logging.getLogger(__name__) 15 16 17async def start_health_server( 18 get_status_fn, 19 host: str = "0.0.0.0", 20 port: int = 9701, 21) -> asyncio.Server: 22 """Start a minimal HTTP health server. 23 24 Parameters 25 ---------- 26 get_status_fn: 27 Callable that returns a dict with router status. 28 host: 29 Bind address. 30 port: 31 Listen port (default 9701). 32 33 Returns 34 ------- 35 asyncio.Server 36 The running server instance. 37 """ 38 39 async def handle_request( 40 reader: asyncio.StreamReader, 41 writer: asyncio.StreamWriter, 42 ) -> None: 43 try: 44 # Read the request line (we don't care about the path) 45 await asyncio.wait_for(reader.readline(), timeout=5.0) 46 # Drain remaining headers 47 while True: 48 line = await asyncio.wait_for(reader.readline(), timeout=5.0) 49 if line in (b"\r\n", b"\n", b""): 50 break 51 52 status = get_status_fn() 53 body = json.dumps(status, indent=2).encode() 54 response = ( 55 b"HTTP/1.1 200 OK\r\n" 56 b"Content-Type: application/json\r\n" 57 b"Connection: close\r\n" 58 b"Content-Length: " + str(len(body)).encode() + b"\r\n" 59 b"\r\n" + body 60 ) 61 writer.write(response) 62 await writer.drain() 63 except Exception: 64 pass 65 finally: 66 writer.close() 67 try: 68 await writer.wait_closed() 69 except Exception: 70 pass 71 72 server = await asyncio.start_server(handle_request, host, port) 73 logger.info("Health server started on %s:%d", host, port) 74 return server