from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer import json import logging from threading import Thread # # This section might be a little fragile, but thankfully crashing this won't take the whole process down # Since it's running in it's own thread # Although the process might become unresponsive # class TinyRequestHandler(BaseHTTPRequestHandler): def log_message(self, format, *args): self.server._logger.debug(format % args) def _handle_request(self, method: str, data: bytes = None): _, name, *path = str(self.path).split("/") method_name = f"{method}_{name}" if hasattr(self.server._methods_instance, method_name): status, result = getattr(self.server._methods_instance, method_name)(path, data) self.send_response(status) try: stringified_result = json.dumps(result) content_type = 'application/json' except TypeError: stringified_result = str(result) content_type = 'text/plain; charset=UTF-8' self.send_header('Content-type', content_type) self.end_headers() self.wfile.write(stringified_result.encode('utf-8')) else: self.send_response(404) self.send_header('Content-type', 'text/plain') self.end_headers() self.wfile.write(b"NOT FOUND") def do_GET(self): self._handle_request('GET', None) def do_POST(self): if self.headers['Content-Length']: content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length) else: post_data = None self._handle_request('POST', post_data) class TinyHTTPServer(Thread): def __init__(self, methods_instance, port: int = 8000): super().__init__() self._logger = logging.getLogger("http") self._http_server = ThreadingHTTPServer(('', port), TinyRequestHandler) self._http_server._methods_instance = methods_instance self._http_server._logger = self._logger def run(self): self._logger.info(f"Starting HTTP Server (bind: {self._http_server.server_address})...") self._http_server.serve_forever() self._logger.info("Stopped HTTP Server...") def shutdown(self): self._http_server.shutdown()