Files
NebulaShell/oss/shared/router.py
Falck 3a096f59a9 重构:核心迁移至 oss/core + NBPF 多重签名加密 + NIR 编译器 + README 全面升级
- 核心功能从 store/ 迁移至 oss/core/ 框架层
- 实现 NBPF 包格式:多重签名(Ed25519+RSA-PSS+HMAC)+ 多重加密(AES-256-GCM)
- 实现 NIR 编译器:基于 compile()+marshal 的跨平台中间表示
- 新增 nebula nbpf CLI 命令组(pack/unpack/verify/sign/keygen)
- 新增 19 个 NBPF 测试用例,覆盖全链路
- 彻底重写 README,大型项目标准框架风格,所有图表使用 SVG
- 更新 LICENSE 版权声明
- 清理旧版 store 插件目录(已迁移至 oss/core)
2026-05-05 07:29:43 +08:00

116 lines
3.2 KiB
Python

from typing import Callable
from functools import lru_cache
class BaseRoute:
__slots__ = ('method', 'path', 'handler', '_pattern_parts')
def __init__(self, method: str, path: str, handler: Callable):
self.method = method
self.path = path
self.handler = handler
self._pattern_parts = path.strip("/").split("/") if ":" in path else None
def _get_pattern_parts(pattern: str):
if ":" not in pattern:
return None
return pattern.strip("/").split("/")
def _is_wildcard_param(param: str) -> bool:
return param.startswith(":") and param.endswith("*")
@lru_cache(maxsize=1024)
def match_path(pattern: str, path: str) -> bool:
if pattern == path:
return True
pattern_parts = _get_pattern_parts(pattern)
if pattern_parts is None:
return False
path_parts = path.strip("/").split("/")
last_pattern = pattern_parts[-1]
is_wildcard = _is_wildcard_param(last_pattern)
if is_wildcard and len(path_parts) >= len(pattern_parts):
for i, p in enumerate(pattern_parts[:-1]):
if i >= len(path_parts):
return False
if not p.startswith(":") and p != path_parts[i]:
return False
return True
if len(pattern_parts) != len(path_parts):
return False
for p, a in zip(pattern_parts, path_parts):
if not p.startswith(":") and p != a:
return False
return True
@lru_cache(maxsize=1024)
def extract_path_params(pattern: str, path: str) -> dict[str, str]:
params = {}
pattern_parts = _get_pattern_parts(pattern)
if pattern_parts is None:
return params
path_parts = path.strip("/").split("/")
last_pattern = pattern_parts[-1]
is_wildcard = _is_wildcard_param(last_pattern)
use_wildcard = is_wildcard and len(path_parts) > len(pattern_parts)
if use_wildcard:
parts_to_process = pattern_parts[:-1]
else:
parts_to_process = pattern_parts
for i, p in enumerate(parts_to_process):
if i < len(path_parts) and p.startswith(":"):
param_name = p[1:]
params[param_name] = path_parts[i]
if use_wildcard:
param_name = last_pattern[1:]
remaining = "/".join(path_parts[len(pattern_parts) - 1:])
params[param_name] = remaining
return params
class BaseRouter:
def __init__(self):
self.routes: list[BaseRoute] = []
def add(self, method: str, path: str, handler: Callable):
self.routes.append(BaseRoute(method, path, handler))
def get(self, path: str, handler: Callable):
self.add("GET", path, handler)
def post(self, path: str, handler: Callable):
self.add("POST", path, handler)
def put(self, path: str, handler: Callable):
self.add("PUT", path, handler)
def delete(self, path: str, handler: Callable):
self.add("DELETE", path, handler)
def match(self, method: str, path: str):
for route in self.routes:
if route.method == method and match_path(route.path, path):
params = extract_path_params(route.path, path)
return route, params
return None