From 4d547f65c472b303ae2aae7bcf62e4cae02baba4 Mon Sep 17 00:00:00 2001 From: Vish Date: Tue, 26 May 2026 10:27:01 +1000 Subject: [PATCH] factory: Add a hello endpoint # Hello Endpoint Implementation ## Summary Added a simple HTTP "hello" endpoint to the Silverforge factory project. ## Changes 1. **Created `factory/hello_server.py`** - New module implementing a basic HTTP server using Python's standard library `http.server` - Provides a `HelloHandler` class that responds to GET requests on the `/hello` path - Returns JSON response `{"message": "hello"}` on success, `{"error": "not found"}` on other paths - `run_server()` function starts the server on configurable host and port 2. **Updated `factory/cli.py`** - Added new `hello` CLI command to start the HTTP server - Supports `--port` (default 8000) and `--host` (default 0.0.0.0) options - Updated docstring to document the new command - Handles graceful shutdown on Ctrl-C ## Design Decisions - Used Python's built-in `http.server` module to avoid adding external dependencies - Simple GET-only endpoint following RESTful conventions - Returns JSON for consistency with modern APIs - Endpoint accessible at `/hello` path - Server runs in foreground (blocks CLI) until interrupted, which is typical for service commands ## Testing Code passes Python syntax validation. The endpoint can be tested by running: ```bash factory hello --port 8000 # Then in another terminal: curl http://localhost:8000/hello ``` --- factory/cli.py | 18 ++++++++++++++++++ factory/hello_server.py | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 factory/hello_server.py diff --git a/factory/cli.py b/factory/cli.py index 59d1509..3face0d 100644 --- a/factory/cli.py +++ b/factory/cli.py @@ -7,6 +7,7 @@ status [run_id] — show run(s) status eval — re-run eval commands for an existing run attach — SSH into the remote tmux session for a run + hello [--port PORT] — start a hello HTTP endpoint server """ from __future__ import annotations @@ -1035,6 +1036,23 @@ def poll( console.print() +# ── hello ───────────────────────────────────────────────────────────────────── + +@app.command() +def hello( + port: int = typer.Option(8000, "--port", "-p", help="Port to listen on"), + host: str = typer.Option("0.0.0.0", "--host", "-h", help="Host to bind to"), +) -> None: + """Start a simple HTTP server with a /hello endpoint that returns JSON.""" + from factory.hello_server import run_server + + console.print(f"[green]✓[/green] Starting hello server on http://{host}:{port}/hello") + try: + run_server(host=host, port=port) + except KeyboardInterrupt: + console.print("\n[yellow]Shutting down...[/yellow]") + + # ── slack-listen ───────────────────────────────────────────────────────────── @app.command(name="slack-listen") diff --git a/factory/hello_server.py b/factory/hello_server.py new file mode 100644 index 0000000..9541c1c --- /dev/null +++ b/factory/hello_server.py @@ -0,0 +1,39 @@ +""" +Simple HTTP server with a hello endpoint. + +Usage: + from factory.hello_server import run_server + run_server(port=8000) +""" +from http.server import HTTPServer, BaseHTTPRequestHandler +import json + + +class HelloHandler(BaseHTTPRequestHandler): + """HTTP request handler for the hello endpoint.""" + + def do_GET(self): + """Handle GET requests.""" + if self.path == "/hello": + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.end_headers() + response = json.dumps({"message": "hello"}) + self.wfile.write(response.encode()) + else: + self.send_response(404) + self.send_header("Content-Type", "application/json") + self.end_headers() + response = json.dumps({"error": "not found"}) + self.wfile.write(response.encode()) + + def log_message(self, format, *args): + """Suppress default logging.""" + pass + + +def run_server(host: str = "0.0.0.0", port: int = 8000) -> None: + """Start the HTTP server on the specified host and port.""" + server = HTTPServer((host, port), HelloHandler) + print(f"Hello server listening on http://{host}:{port}/hello") + server.serve_forever()