from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler import urllib.parse as urlparse import os import json import sys import traceback from pathlib import Path from rokuHandler import RokuWrapper, ROKU_IP from privatebinHandler import PrivateBinWrapper HOST = os.environ.get("HOST", "0.0.0.0") PORT = int(os.environ.get("PORT", "1331")) ROOT = Path(__file__).parent.resolve() print("root at", ROOT) class HTTPHandler(BaseHTTPRequestHandler): def setup(self): print("setting up...") super().setup() self.rapp = RokuWrapper(self) self.pbin = PrivateBinWrapper(self) def _cors(self): self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Access-Control-Allow-Headers", "*") self.send_header("Access-Control-Allow-Methods", "GET, OPTIONS") def _send(self, code=200, body=b''): self.send_response(code) self._cors() self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(body))) self.end_headers() if body: self.wfile.write(body) def _send_file(self, path: Path, content_type: str): if not path.exists() or not path.is_file(): self._send(404, json.dumps({"error": "file not found"}).encode()) return # send file content as JSON payload (openapi/spec are JSON) data = path.read_bytes() self._send(200, data) def do_OPTIONS(self): self.send_response(204) self._cors() self.end_headers() def do_GET(self): parsed = urlparse.urlparse(self.path) path = parsed.path.rstrip("/").lower() try: # specs if path.startswith("/roku"): if path == "/roku/openapi.json": return self._send_file(ROOT / "spec" / "roku.openapi.json", "application/json") return self.rapp.run_command(path.replace("/roku/", '')) if path.startswith("/privatebin"): if path == "/privatebin/openapi.json": return self._send_file(ROOT / "spec" / "privatebin.openapi.json", "application/json") return self.pbin.run_command(path.replace("/privatebin/", '')) # catch-all self._send(404, json.dumps({"error": "unknown endpoint"}).encode()) except Exception as ex: err = {"error": str(ex)} self.log_error("Handler error: %s\n%s", ex, traceback.format_exc()) self._send(500, json.dumps(err).encode()) def log_message(self, format, *args): # keep logs short and to stderr (default) sys.stderr.write("%s - - [%s] %s\n" % (self.client_address[0], self.log_date_time_string(), format % args)) def run(host=HOST, port=PORT): server = ThreadingHTTPServer((host, port), HTTPHandler) try: print(f"Listening on {host}:{port} - Roku at {ROKU_IP}") server.serve_forever() print('finished running') except KeyboardInterrupt: print("Shutting down") server.server_close() if __name__ == "__main__": run() else: print("Not running because this is not main")