Commit Graph
6 Commits
Author SHA1 Message Date
liuzhuohua 2859705cee fix(webshell): 修复终端满员自锁 + 去掉滚动条并加清屏按钮
一、修 PTY 不可用(Web 终端报「创建终端失败:out of pty devices」)
   根因是目标机上 /dev/ptmx 这个符号链接丢了(devpts 里 /dev/pts/ptmx
   还在,但入口没了),于是 pty.openpty() 抛出误导性的「out of pty devices」。
   - 新增 ensure_ptmx():探测 -> ln -sf pts/ptmx /dev/ptmx -> mknod 兜底
   - 新增 _open_pty():首次失败先自愈再重试一次,仍失败就把真实原因
     (_pty_diagnose() 的结论)包进异常,不再只留一句天书
   - 服务启动时也自愈一次,开机即修,不等用户踩坑
   - 前端识别 PTY_FAIL 并给出可照抄的修复命令

二、修会话满员时的死锁(连到第 9 个会话整个终端服务冻死)
   connect 需要「看是否满员 -> 满了就回收 -> 再看一次」,这个序列必然
   在持锁时调到内部也要拿锁的 _reap_idle()。而 _lock 是普通 Lock,
   同线程二次 acquire 永久阻塞 —— 不报错、不超时,直接锁死;而且锁
   一直不放,其他会话的 read/write 也一起堵住,整个 Web 终端报废。
   - _lock 改为 RLock
   - connect 不再把 _reap_idle() 放在 with _lock 里面
   - _reap_idle() 锁内只做登记摘除,close() 移到锁外:
     close() 要等子进程退出(SIGHUP 后最多轮询 3 秒),持锁做同样会
     把并发请求堵死

三、终端外观(按需求)
   - 去掉右侧滚动条(scrollbar-width:none + ::-webkit-scrollbar),
     但保留滚动能力 —— 直接关掉 overflow 会让人再也翻不了历史
   - 高度改为 clamp(260px,54vh,560px) 随视口自适应;内容多了自动跟随
     最新输出。刻意不做「高度随内容增长」:wsMeasure() 用 box.h 算行数,
     内容撑高容器会反过来改变 PTY 行数,形成反馈环
   - 标题栏加「清屏」小按钮;滚上去离开底部时另出现「↓ 最新」——
     滚动条没了,总得留个回到底部的入口
   - 跟随阈值收敛成唯一的 WS_TAIL_GAP:wsAutoScroll 与 wsSyncTailBtn
     各写一份会出现「按钮没出现、输出也不跟着滚了」的死角

四、顺带清理
   - 删掉 app.css 里整套失效的旧终端样式(.tdot/.tt/.term-in/.tk-*,
     app.js 中 0 引用),它们已被新结构完全覆盖,留着只会让人改错地方
   - 合并 .term-wrap / .term-body 各自重复的第二条声明

测试:
   _dev/t-pty.py 扩到 37 项,含「不得自锁」的结构检查 + _reap_idle
   行为验证(摘除/关闭/返回条数);_dev/t-webshell.py 加 16 项外观契约。
   两者都挂进 devtools/sync.sh 预检链。
   新增 devtools/preview-webshell.py:用真实 app.css + 从 viewWebShell()
   抠出的 DOM 生成离线预览页,不手抄样式以免预览与线上不一致。

真机验收(192.168.7.3):
   8 个会话满员后第 9 个 0.01s 干净返回 BUSY(修复前是永久卡死);
   8 个会话 0.87s 全部断开、残留 0(修复前残留 8 个且后续全卡);
   /dev/pts 与 pty/nr 回落到 0,无 fd 泄漏;root shell 正常执行命令。
2026-10-01 01:29:09 +08:00
liuzhuohua 9b4ffce9a5 feat(devtools): 生成截图图床外链清单(Markdown / BBCode / HTML 三格式)
用户问「能不能当图床、转成论坛可用的格式」。

实测结论:可以。四种直链形式全部 200,且
- Content-Type 正确(image/jpeg)
- Access-Control-Allow-Origin: *(CORS 全开,网页引用无阻)
- 无防盗链:带外部 Referer、无 UA 均正常返回

新增 devtools/gen-image-urls.py,一次性产出三种论坛格式:
  ① Markdown  ![alt](url)     GitHub / 语雀 / Discourse / Obsidian
  ② BBCode    [img]url[/img]  Discuz / phpBB / NGA / 恩山 / Chiphell / v2ex
  ③ HTML      <img src="url"> 博客 / 自建站 / 富文本编辑器

域名默认用 cdn.jsdelivr.net/gh —— 国内可达性明显好于
raw.githubusercontent.com,且缓存 7 天(raw 只有 5 分钟)。
文档里附了换域名对照表(gcore 备用节点 / statically / raw)。

同时支持 @<commit-sha> 冻结写法,把内容锁定在某个提交上,
避免后续提交把已发出去的帖子里的图改掉。

产物同时落在 docs/图床链接清单.md(进仓库)和桌面(方便直接用)。

顺带记录一个失败:想生成「纯格式版」和「带文件名版」两份,
判断逻辑写错导致两份内容相同;改用一次生成、分节呈现,
反而更适合「整段复制」的用法。别为了参数化而增加无意义的重复产物。
2026-09-30 23:14:19 +08:00
liuzhuohua 3f5f31701e feat(devtools): 新增截图覆盖度检查,README 标明待补页面
核对用户打包发来的 78 张截图,与仓库已入库的 78 张 md5 集合完全一致
(互相零差异),确认上一轮提交已是完整状态,本次不需改动任何图片。

本次补充的是「防漂移」能力:

1. 新增 devtools/check-shots.py —— 功能页 ↔ 截图 ↔ README 引用 三方对账
   - 43 个功能页逐个报告有无截图(当前 40 有 / 3 缺)
   - 映射表登记的截图 vs docs/screenshots/ 实际文件,双向查差异
   - README 引用的 vs 实际存在的,双向查差异
   为什么不用中文页名做子串匹配:「防火墙 IPv4」会命中「防火墙 IPv6」的
   规则说明,误判是静默的假绿。宁可手工维护一张映射表。

2. sync.sh 里原来那段内联的截图清单校验,替换为调用 check-shots.py
   (功能被完整覆盖,且现在多了功能页覆盖度这一维)。

3. sync.sh 的 CRLF 检查改为只扫 git 已追踪的文件。
   原来用 glob('**/*.html') 会扫到未追踪的本地临时预览页
   (_preview-shots.html),它既不会进仓库也不会被 deploy.sh 上传,
   为它报错是纯噪音。

4. README 截图章节新增「还没截图的 3 个页面」折叠块:
   新手向导 / 主题之家 / 升级与保护,附补图流程。
   项目结构章节补充两个新工具。

验证:check-md-links 98 个引用 0 死链;check-shots 三方一致;
      t-audit / t-packaging 全部通过。
2026-09-30 23:05:51 +08:00
liuzhuohua a8659dfb98 docs(readme): 用 78 张真实界面截图替换 SVG 占位图
原文里 docs/screenshots/ 放的是 6 张同尺寸 SVG 占位图,只为让 README
在仓库刚建好时能完整渲染。现在换成 78 张真实运行截图(1272x900,
取自一台 2 核 4G 的 Debian 13 虚拟机)。

改动:
- 新增 docs/screenshots/ 78 张 jpg,按 9 个功能分组编号命名
  (01-login / 02-overview… / 09-settings-4),覆盖全部 43 个功能页
- 删除 6 张 SVG 占位图与 devtools/make-placeholder-shots.py
- README「截图」章节重写:首屏放 8 张精选大图,其余 70 张按功能分
  组放进 9 个 <details> 折叠块,每组内用两列表格 + 图注
- README 项目结构补充 docs/screenshots 与 devtools/shots-map.py
- dist/RELEASE_NOTES.md 同步「截图已全部为真图」

为什么文件名必须 ASCII:
  GitHub Releases 资产名已被实测证明会静默剥离非 ASCII 字符
  (DOCKER-使用说明.md → DOCKER-.md);且原始文件名含 &(如
  AC&AP管理中心.jpg、UPnp&NAT-PMP.jpg)在 shell / CI 里都要额外转义。
  devtools/shots-map.py 负责「中文名 → ASCII 名」的映射与复制,
  并做完整性校验(漏拷/多余/重名都会中止)。

新增两项预检,挂进 devtools/sync.sh:
- devtools/check-md-links.py:所有 md 的本地引用逐条查存在性
- 截图清单双向校验:README 引用的 78 张与目录里的 78 个文件必须一一对应

验证:check-md-links 扫 10 个 md / 98 个本地引用,0 死链;
      78 张图与源目录 md5 集合完全一致;
      t-packaging / t-audit / t-deps / t-cachebust 全部通过。
2026-09-30 22:46:43 +08:00
liuzhuohua 5150f4c2e6 feat(docker): 补 compose 编排与使用说明,修正镜像标签与 license
新增
  · packaging/docker/docker-compose.yml   现成编排,含健康检查与命名卷
  · packaging/docker/DOCKER-使用说明.md    完整使用文档(含常见问题)
  · devtools/retag-docker-image.py        镜像重打标签工具

修正三个真实缺陷
1. 镜像标签
   原本是 buildah 留下的 `localhost/drouter:1.0.0`。`localhost/` 是 Podman
   的本地镜像约定,Docker 用户拿到会很困惑(像某个私服地址)。
   改为 `drouter:1.0.0` + 别名 `liuzhuohua/drouter:1.0.0`。

2. license 标签写错
   镜像 LABEL 里 `org.opencontainers.image.licenses` 是 **GPL-3.0**,
   但项目实际是 **MIT**(Dockerfile 与镜像 config 都已改)。

3. 缺 HEALTHCHECK
   没有它,compose 里 `depends_on: condition: service_healthy` 无从等起,
   `docker ps` 也看不出容器是否真的活着。
   补上探活 /api/health —— 注意面板走 HTTPS + 自签证书,curl 必须 -k,
   否则永远 unhealthy。

compose 要点
  · network_mode: host 是硬要求(bridge 下看不到真实网卡、管不了宿主 NAT)
  · cap_add 只给 NET_ADMIN + NET_RAW,不用 privileged
  · host 模式下 ports 会被忽略,端口由 /etc/drouter/web-port 决定,
    故用 expose 表达意图而非 ports
  · 四个命名卷必须挂:配置 / 数据 / 快照 / 日志

重打标签采用流式重写 tar(只替换 manifest.json、repositories 与 config
三个小文件,layer.tar 原样透传),已逐层校验 3 个 layer 的 sha256 与
原包完全一致。
2026-09-30 21:25:28 +08:00
liuzhuohua 64df3cf331 feat: Drouter 1.0.0 —— Debian 13 软路由管理系统
一套跑在 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
2026-09-30 19:26:24 +08:00