Files
NebulaShell/oss/core/http_api/server.py
Falck bce27db4ac 重大重构:引擎模块拆分 + P0插件实现 + 55个Bug修复
核心变更:
- engine.py(1781行)拆分为8个独立模块: lifecycle/security/deps/
  datastore/pl_injector/watcher/signature/manager
- 新增plugin-bridge: 事件总线 + 服务注册 + RPC通信
- 新增i18n: 国际化/多语言翻译支持
- 新增plugin-storage: 插件键值/文件存储
- 新增ws-api: WebSocket实时通信(pub/sub + 自定义处理器)
- nodejs-adapter统一为Plugin ABC模式

Bug修复:
- 修复load_all()中store_dir未定义崩溃
- 修复DependencyResolver入度计算(拓扑排序)
- 修复PermissionError隐藏内置异常
- 修复CORS中间件头部未附加到响应
- 修复IntegrityChecker跳过__pycache__目录
- 修复版本号不一致(v2.0.0→v1.2.0)
- 修复测试文件的Logger导入/路径/私有方法调用
- 修复context.py缺少typing导入
- 修复config.py STORE_DIR默认路径(./mods→./store)

测试覆盖: 14→91个测试, 全部通过
2026-05-12 11:40:06 +08:00

127 lines
4.4 KiB
Python

"""HTTP 服务器核心"""
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
from typing import Any
from oss.config import get_config
from oss.logger.logger import Log
class Request:
"""请求对象"""
def __init__(self, method, path, headers, body):
self.method = method
self.path = path
self.headers = headers
self.body = body
class Response:
"""响应对象"""
def __init__(self, status=200, headers=None, body=""):
self.status = status
self.headers = headers or {}
self.body = body
class HttpServer:
"""HTTP 服务器"""
def __init__(self, router, middleware, host=None, port=None):
config = get_config()
self.host = host or config.get("HOST", "127.0.0.1")
self.port = port or config.get("HTTP_API_PORT", 8080)
self.router = router
self.middleware = middleware
self._server = None
self._thread = None
def start(self):
"""启动服务器"""
handler = self._create_handler()
self._server = HTTPServer((self.host, self.port), handler)
self._thread = threading.Thread(target=self._server.serve_forever, daemon=True)
self._thread.start()
Log.info("Core", f"HTTP 服务器启动: {self.host}:{self.port}")
def stop(self):
"""停止服务器"""
if self._server:
self._server.shutdown()
Log.info("Core", "HTTP 服务器已停止")
def _create_handler(self):
"""创建请求处理器"""
router = self.router
middleware = self.middleware
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self._handle("GET")
def do_POST(self):
self._handle("POST")
def do_PUT(self):
self._handle("PUT")
def do_DELETE(self):
self._handle("DELETE")
def do_OPTIONS(self):
"""处理 CORS 预检请求"""
config = get_config()
allowed_origins = config.get("CORS_ALLOWED_ORIGINS", ["http://localhost:3000", "http://127.0.0.1:3000"])
origin = self.headers.get("Origin", "")
if origin in allowed_origins or "*" in allowed_origins:
self.send_response(200)
self.send_header("Access-Control-Allow-Origin", origin if origin else "*")
self.send_header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
self.send_header("Access-Control-Allow-Headers", "Content-Type, Authorization")
self.send_header("Access-Control-Allow-Credentials", "true")
else:
self.send_response(204)
self.end_headers()
def _handle(self, method):
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length) if content_length else b""
req = Request(
method=method,
path=self.path,
headers=dict(self.headers),
body=body.decode("utf-8")
)
# 执行中间件
ctx = {"request": req, "response": None}
result = middleware.run(ctx)
if result:
self._send_response(result, ctx)
return
# 路由匹配
resp = router.handle(req)
self._send_response(resp, ctx)
def _send_response(self, resp: Response, ctx: dict = None):
try:
self.send_response(resp.status)
extra_headers = (ctx or {}).get("response_headers", {})
merged = {**extra_headers, **resp.headers}
for k, v in merged.items():
self.send_header(k, v)
self.end_headers()
if isinstance(resp.body, str):
self.wfile.write(resp.body.encode("utf-8"))
else:
self.wfile.write(resp.body)
except (BrokenPipeError, ConnectionAbortedError, ConnectionResetError):
pass
def log_message(self, format, *args):
Log.debug("Core", format % args)
return Handler