fixes button
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Мини-сервер на ПК для проверки HTTP-кнопок ButtonTask.
|
||||
|
||||
Запуск:
|
||||
python tools/button-test-server.py
|
||||
python tools/button-test-server.py --host 0.0.0.0 --port 8765
|
||||
|
||||
Примеры URL для кнопок (подставьте IP вашего ПК):
|
||||
http://192.168.1.10:8765/ok
|
||||
http://192.168.1.10:8765/fail
|
||||
http://192.168.1.10:8765/btn?bid=01
|
||||
http://192.168.1.10:8765/echo (тип: http_post, body: ping)
|
||||
http://192.168.1.10:8765/slow?sec=8 (таймаут кнопки по умолчанию 7 с)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
|
||||
def _now() -> str:
|
||||
return datetime.now().strftime("%H:%M:%S")
|
||||
|
||||
|
||||
class ButtonTestHandler(BaseHTTPRequestHandler):
|
||||
server_version = "ButtonTestHTTP/1.0"
|
||||
|
||||
def log_message(self, fmt: str, *args) -> None:
|
||||
print(f"[{_now()}] {self.address_string()} {fmt % args}", flush=True)
|
||||
|
||||
def _send(self, code: int, body: str, content_type: str = "text/plain; charset=utf-8") -> None:
|
||||
data = body.encode("utf-8")
|
||||
self.send_response(code)
|
||||
self.send_header("Content-Type", content_type)
|
||||
self.send_header("Content-Length", str(len(data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
|
||||
def _read_body(self) -> bytes:
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
return self.rfile.read(length) if length else b""
|
||||
|
||||
def do_GET(self) -> None:
|
||||
path = urlparse(self.path).path
|
||||
qs = parse_qs(urlparse(self.path).query)
|
||||
|
||||
if path in ("", "/"):
|
||||
self._send(200, HELP_TEXT)
|
||||
return
|
||||
|
||||
if path == "/ok":
|
||||
self._send(200, "OK\n")
|
||||
return
|
||||
|
||||
if path == "/fail":
|
||||
self._send(500, "server error\n")
|
||||
return
|
||||
|
||||
if path == "/btn":
|
||||
bid = (qs.get("bid") or ["?"])[0]
|
||||
payload = {"status": "ok", "bid": bid, "ts": time.time()}
|
||||
self._send(200, json.dumps(payload, ensure_ascii=False), "application/json")
|
||||
return
|
||||
|
||||
if path == "/slow":
|
||||
sec = float((qs.get("sec") or ["3"])[0])
|
||||
sec = max(0.0, min(sec, 60.0))
|
||||
time.sleep(sec)
|
||||
self._send(200, f"slept {sec:g}s\n")
|
||||
return
|
||||
|
||||
if path == "/redirect":
|
||||
self.send_response(302)
|
||||
self.send_header("Location", "/ok")
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
self._send(404, f"not found: {path}\n")
|
||||
|
||||
def do_POST(self) -> None:
|
||||
path = urlparse(self.path).path
|
||||
raw = self._read_body()
|
||||
text = raw.decode("utf-8", errors="replace")
|
||||
|
||||
if path == "/echo":
|
||||
ct = self.headers.get("Content-Type", "text/plain")
|
||||
out = (
|
||||
f"method=POST\n"
|
||||
f"content-type={ct}\n"
|
||||
f"body={text}\n"
|
||||
)
|
||||
self._send(200, out)
|
||||
return
|
||||
|
||||
if path == "/fail":
|
||||
self._send(500, "post failed\n")
|
||||
return
|
||||
|
||||
self._send(404, f"not found: {path}\n")
|
||||
|
||||
|
||||
HELP_TEXT = """ButtonTask test server
|
||||
|
||||
GET /ok -> 200 (зелёная обводка)
|
||||
GET /fail -> 500 (красная обводка)
|
||||
GET /btn?bid=01 -> 200 JSON (как в примере config.json)
|
||||
GET /slow?sec=3 -> задержка, проверка таймаута
|
||||
GET /redirect -> 302 -> /ok
|
||||
POST /echo -> эхо тела запроса
|
||||
POST /fail -> 500
|
||||
|
||||
Все запросы пишутся в консоль.
|
||||
"""
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Тестовый HTTP-сервер для кнопок ButtonTask")
|
||||
parser.add_argument("--host", default="0.0.0.0", help="адрес (0.0.0.0 — доступ с сети)")
|
||||
parser.add_argument("--port", type=int, default=8765, help="порт (по умолчанию 8765)")
|
||||
args = parser.parse_args()
|
||||
|
||||
httpd = ThreadingHTTPServer((args.host, args.port), ButtonTestHandler)
|
||||
print(f"ButtonTask test server: http://{args.host}:{args.port}/", flush=True)
|
||||
print("Остановка: Ctrl+C", flush=True)
|
||||
print(HELP_TEXT, flush=True)
|
||||
try:
|
||||
httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
print("\nstop", flush=True)
|
||||
finally:
|
||||
httpd.server_close()
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user