diff options
author | Egor Tensin <Egor.Tensin@gmail.com> | 2021-03-03 23:09:11 +0300 |
---|---|---|
committer | Egor Tensin <Egor.Tensin@gmail.com> | 2021-03-03 23:09:11 +0300 |
commit | 69580ef09cfb0f41fa50d3252f4a83cfb7f153b5 (patch) | |
tree | 87f2c4c07719f30698a0f34c61020c395181c7d3 | |
parent | prune obsolete entry from .gitignore (diff) | |
download | linux-status-69580ef09cfb0f41fa50d3252f4a83cfb7f153b5.tar.gz linux-status-69580ef09cfb0f41fa50d3252f4a83cfb7f153b5.zip |
add server.py
It runs a web server and imports the request handling classes from
get.py directly, hence eliminating the performance culprit (which was
the `import` processing for each request).
-rw-r--r-- | .gitignore | 1 | ||||
-rwxr-xr-x | cgi-bin/get.py | 46 | ||||
-rw-r--r-- | index.html | 6 | ||||
-rwxr-xr-x | server.py | 32 |
4 files changed, 76 insertions, 9 deletions
@@ -0,0 +1 @@ +__pycache__/ diff --git a/cgi-bin/get.py b/cgi-bin/get.py index 3831812..1453dc2 100755 --- a/cgi-bin/get.py +++ b/cgi-bin/get.py @@ -10,6 +10,7 @@ import cgi from collections import namedtuple from concurrent.futures import ThreadPoolExecutor from enum import Enum +import http.server import json import os import pwd @@ -38,16 +39,43 @@ class Response: def __init__(self, data): self.data = data - def print(self): - print("Content-Type: text/html; charset=utf-8") - print() - if self.data is not None: - print(self.dump_json(self.data)) + def headers(self): + yield 'Content-Type', 'text/html; charset=utf-8' @staticmethod def dump_json(data): return json.dumps(data, ensure_ascii=False) + def body(self): + return self.dump_json(self.data) + + def write_as_cgi_script(self): + self.write_headers_as_cgi_script() + self.write_body_as_cgi_script() + + def write_headers_as_cgi_script(self): + for name, val in self.headers(): + print(f'{name}: {val}') + print() + + def write_body_as_cgi_script(self): + if self.data is not None: + print(self.body()) + + def write_as_request_handler(self, handler): + handler.send_response(http.server.HTTPStatus.OK) + self.write_headers_as_request_handler(handler) + self.write_body_as_request_handler(handler) + + def write_headers_as_request_handler(self, handler): + for name, val in self.headers(): + handler.send_header(name, val) + handler.end_headers() + + def write_body_as_request_handler(self, handler): + if self.data is not None: + handler.wfile.write(self.body().encode(errors='replace')) + def run_do(*args, **kwargs): output = subprocess.run(args, stdin=DEVNULL, stdout=PIPE, stderr=STDOUT, universal_newlines=True, **kwargs) @@ -318,6 +346,12 @@ class Request(Enum): def __str__(self): return self.value + @staticmethod + def from_http_path(path): + if not path or path[0] != '/': + raise ValueError('HTTP path must start with a forward slash /') + return Request(path[1:]) + def process(self): if self is Request.STATUS: return StatusTask().complete() @@ -331,7 +365,7 @@ class Request(Enum): def process_cgi_request(): params = cgi.FieldStorage() what = params['what'].value - Request(what).process().print() + Request(what).process().write_as_cgi_script() def main(): @@ -76,7 +76,7 @@ function set_top(data) { } function refresh_top() { - $.get('cgi-bin/get.sh?what=top', function(data) { + $.get('top', function(data) { set_top(JSON.parse(data)); }); } @@ -162,7 +162,7 @@ function set_users(data) { } function refresh_status() { - $.get('cgi-bin/get.sh?what=status', function(data) { + $.get('status', function(data) { data = JSON.parse(data); set_top(data['top']); set_hostname(data['hostname']); @@ -172,7 +172,7 @@ function refresh_status() { } function refresh_timers() { - $.get('cgi-bin/get.sh?what=timers', function(data) { + $.get('timers', function(data) { data = JSON.parse(data); set_system(data['system']); set_users(data['user']); diff --git a/server.py b/server.py new file mode 100755 index 0000000..9533be7 --- /dev/null +++ b/server.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2021 Egor Tensin <Egor.Tensin@gmail.com> +# This file is part of the "linux-status" project. +# For details, see https://github.com/egor-tensin/linux-status. +# Distributed under the MIT License. + +import http.server + +from get import Request + + +class RequestHandler(http.server.CGIHTTPRequestHandler): + def do_GET(self): + try: + request = Request.from_http_path(self.path) + except ValueError: + return super().do_GET() + request.process().write_as_request_handler(self) + + +def main(): + addr = ('', 18101) + httpd = http.server.ThreadingHTTPServer(addr, RequestHandler) + try: + httpd.serve_forever() + except KeyboardInterrupt: + print('\nKeyboard interrupt received, exiting...') + + +if __name__ == '__main__': + main() |