一套跑在 Debian 13 (trixie) 上的软路由管理系统,提供 43 个功能页面的 Web 管理面板:WAN 接入、PPPoE 多拨、DHCP/DNS、IPv6、防火墙、QoS 限速、 访问控制、DDNS、文件共享、Docker 管理等。 核心设计原则:不重新实现任何协议 PPPoE 交给 ppp,DHCP 交给 dnsmasq,IPv6 RA 交给 radvd,NAT 交给 nftables。 Web 面板只做三件事:渲染原生配置文件 → 语法预检 → 原子写入并 reload。 面板删掉后,系统仍是一台配置完好的 Debian 路由器。 安全默认值 · 安装后不接管网络:不改默认路由、不开 IP 转发、不启动 DHCP 服务 · 所有改网络的动作都需要用户在面板上亲手点「应用」 · 避开 5900 端口,不触碰 VNC / X 会话 · 配置写入前先做语法预检,失败则回滚 架构 · backend/ Python 3 标准库,零第三方依赖(9 个模块) · web/ 原生 JS/CSS,无构建步骤 · 常驻 helper 通过 Unix socket 提供 75 个动作,socket 不可用时回退 subprocess · 鉴权走 X-Token 请求头 打包 · packaging/build-deb.sh → drouter_1.0.0_all.deb(含 6 个 systemd 单元) · scripts/make-offline-deps.sh → 236 个依赖 .deb + 本地仓库索引 · packaging/build-offline-bundle.sh → 自包含离线包,目标机零外网可装 · packaging/build-docker.sh → 容器镜像(体验用) 测试 40 套单元测试 + 3 个前端检查脚本(菜单映射 / 离线渲染 / 手机适配), 全部挂在 devtools/sync.sh 的预检链里。 许可:MIT
61 lines
2.1 KiB
Python
61 lines
2.1 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""统一日志逐源耗时测量(#7)—— 必须在目标机上跑。
|
|
|
|
目的:/api/ulog 是整个面板唯一还超过 1 秒的接口,但它要汇聚 6 个日志源。
|
|
不拆开量就不知道该优化采集、过滤还是传输。
|
|
"""
|
|
import json
|
|
import ssl
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
|
|
BASE = 'https://127.0.0.1:8443'
|
|
CTX = ssl.create_default_context()
|
|
CTX.check_hostname = False
|
|
CTX.verify_mode = ssl.CERT_NONE
|
|
|
|
|
|
def call(path, token, timeout=120):
|
|
req = urllib.request.Request(BASE + path, headers={'X-Token': token}, method='GET')
|
|
t0 = time.time()
|
|
with urllib.request.urlopen(req, context=CTX, timeout=timeout) as r:
|
|
b = r.read()
|
|
return (time.time() - t0) * 1000, len(b), json.loads(b.decode())
|
|
|
|
|
|
def main():
|
|
req = urllib.request.Request(BASE + '/api/login',
|
|
data=json.dumps({'username': 'admin',
|
|
'password': 'admin123'}).encode(),
|
|
headers={'Content-Type': 'application/json'},
|
|
method='POST')
|
|
with urllib.request.urlopen(req, context=CTX, timeout=30) as r:
|
|
j = json.loads(r.read().decode())
|
|
tk = j['data']['token']
|
|
|
|
print('%-12s %9s %10s %8s' % ('日志源', '耗时ms', '响应字节', '命中条数'))
|
|
print('-' * 46)
|
|
for s in ('fw', 'conntrack', 'wan', 'ddns', 'app', 'system'):
|
|
try:
|
|
dt, n, r = call('/api/ulog?sources=%s&limit=500' % s, tk)
|
|
d = r.get('data') or {}
|
|
m = d.get('meta') or {}
|
|
print('%-12s %9.0f %10d %8s' % (s, dt, n, m.get('matched')))
|
|
except Exception as e:
|
|
print('%-12s 失败: %s' % (s, e))
|
|
try:
|
|
dt, n, r = call('/api/ulog?limit=500', tk)
|
|
print('-' * 46)
|
|
print('%-12s %9.0f %10d' % ('全部源', dt, n))
|
|
d = r.get('data') or {}
|
|
print(' meta:', json.dumps(d.get('meta'), ensure_ascii=False))
|
|
except Exception as e:
|
|
print('全部源失败: %s' % e)
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|