#!/usr/bin/env python3 # -*- coding: utf-8 -*- r"""静态目录服务 (viewer / sim 用) —— 替代 `python -m http.server`, 并接入统一日志格式。 为什么要单开一个: `python -m http.server` 的请求日志是 `127.0.0.1 - - [date] "GET …" 200 -` (Common Log 格式), 与其余 5 个服务的日志格式不一样, 也没法给它挂前缀 (那是 stdlib 的 main)。本器自己做三件事: 1. 每行都走 `src/logfile.py` 的统一格式: `YYYY-MM-DD HH:MM:SS INFO viewer GET /index.html 200 1234`; 2. 只服务**指定目录**(默认安装根下的相对目录), 不做目录列表以外的任何动态行为 (纯静态, 与原来等价); 3. `--comp` 指定组件名 (viewer / sim), 日志落到 `logs/<组件>.log`。 用法: python scripts/static_server.py --port 64292 --dir release/viewer --comp viewer python scripts/static_server.py --port 18791 --dir resources/oem_envision_sc1_rudong2014 --comp sim """ from __future__ import annotations import argparse import functools import pathlib import sys from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer ROOT = pathlib.Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT)) from src import logfile as L # noqa: E402 def main() -> int: ap = argparse.ArgumentParser() ap.add_argument('--port', type=int, required=True) ap.add_argument('--host', default='127.0.0.1') ap.add_argument('--dir', required=True, help='要服务的目录 (相对安装根或绝对路径)') ap.add_argument('--comp', default='static', help='日志组件名 (viewer / sim …)') a = ap.parse_args() L.prefix_stdout(a.comp) d = pathlib.Path(a.dir) d = d if d.is_absolute() else (ROOT / d) if not d.is_dir(): L.write(a.comp, f'目录不存在: {d}', 'ERROR') print(f'[X] 目录不存在: {d}') return 2 class H(SimpleHTTPRequestHandler): def log_message(self, fmt, *args): # 统一格式: 一行一条, 带状态码与字节数 print(f'{self.command} {self.path} {fmt % args}', flush=True) def log_error(self, fmt, *args): print(f'ERROR {self.path} {fmt % args}', flush=True) handler = functools.partial(H, directory=str(d)) print(f'静态服务 → http://{a.host}:{a.port}/ 目录 {d} (组件 {a.comp})', flush=True) ThreadingHTTPServer((a.host, a.port), handler).serve_forever() return 0 if __name__ == '__main__': sys.exit(main())