4.0 KiB
Raw Blame History

name description tags
bricks-terminal-and-popup Use when Wterm/.xterm terminal or PopupWindow resize breaks.
bricks
wterm
xterm
terminal
popup
resize
sage
pipeline

Bricks 终端后端 + 弹窗 resize 踩坑

.xterm 终端后端(Wterm 控件 → SSH 远程命令/vi 编辑)

机制

  • .xterm 文件是 Python 脚本(同 .dspy 语法),经 XtermProcessor 执行,返回 DictObject:{host, username, password/client_keys, cmdargs, noinput}。
  • Wterm 前端 new WebSocket(ws_url);ws_url 用 entire_url('/wss/<module>/xxx.xterm')(浏览器 WebSocket 构造函数自动把 https→wss,无需 websocket_url)。
  • nginx location /wss/ 做 WebSocket 升级 + proxy 到 app 端口(proxy_set_header X-Forwarded-Path 'wss')。
  • 后端 XtermProcessor → SSHServer → asyncssh create_process(cmdargs) 跑命令(如 vi <文件>)。

asyncssh create_process 单 command bug(CRITICAL)

新版 asyncssh 的 create_process(command, *, ...) 只接受单个 command 位置参数,内部 create_session(session_factory, command, *, ...) 只有 2 个位置参数。 xtermProcessor.py 用 create_process(*login_info.cmdargs, ...) 展开列表,cmdargs=['vi', path] 两个元素 → TypeError: SSHClientConnection.create_session() takes from 2 to 3 positional arguments but 4 ...。 修复:.xterm 里 cmdargs 改成单个字符串:r.cmdargs = ['vi ' + shlex.quote(full_path)](不要 ['vi', path])。单命令无参(如 ['~/bin/sagelog'])不受影响。

config.json processors

website.processors 必须含 [".xterm","xterm"] 和 [".ws","ws"](及 .wss),否则 .xterm 端点在新环境 404 或当静态文件处理。提交进仓库 config.json 模板,不要手改生产机。

本地 SSH 编辑

.xterm 返回 host='localhost', username=<app 用户>, cmdargs=['vi <abs_path>'],依赖服务器 ~/.ssh 免密(authorized_keys)。验证:ssh localhost 'which vi'。

PopupWindow 右下角 resize 两个 bug

PopupWindow 构造器已强制 opts.resizable = true(popup.js),无需在 .dspy 显式设置。拖拽失效是另外两个 bug:

bug 1: resizing() 的 e.target 检查

resizing(e){
    ele = this.resizable_w.dom_element;
    if (ele != e.target && !ele.contains(e.target)){  // ❌ mousemove 的 e.target 随鼠标移动变化,拖出 30x30 resizebox 就 stop
        this.stop_resizing(); return;
    }
    ...
}

修复:删掉这段检查。resize_start_pos(mousedown)已用 contains(e.target) 保证起点在 resizebox 上,mousemove 期间不应再检查 e.target。

bug 2: resizebox z-index 被内容覆盖

.resizebox 默认 z-index: auto,而 Wterm/xterm 的 canvas/cursor-layer 在 DOM 靠后覆盖它 → mousedown 点不到 resizebox(document.elementFromPoint 命中 xterm-cursor-layer)。 修复:bricks.css .resizebox 加 z-index: 9999。

Wterm 光标

xterm.js cursorBlink 默认 false(光标静态 block 不闪烁,视觉上不明显)。Wterm 的 term_options 加 "cursorBlink": true 让光标闪烁可见。xterm 用 canvas renderer(rendererType:"canvas"),光标画在 canvas 上而非 .xterm-cursor DOM 元素——.xterm-cursor 为空是正常的。

DSPY 返回文件(下载/媒体流)

web.FileResponse 是 StreamResponse 子类,DSPY 的 handle() 里 isinstance(content, StreamResponse) 会直接返回它。所以 .dspy 可 return FileResponse(path, headers={'Content-Disposition': 'attachment; filename="..."'}) 直接提供文件下载/媒体流,无需 register function(如 idfile)。

验证方法

  • resize:CDP Input.dispatchMouseEvent 模拟 mousedown→mousemove→mouseup,对比 popup getBoundingClientRect 尺寸变化。
  • 命中元素:document.elementFromPoint(x,y) 确认点击点命中的是 resizebox 还是被内容覆盖。
  • 终端连接:浏览器 console 看 ws msg= 数据流 + vi 的 VIM 控制序列(\u001b[2;2R 光标定位、\u001b[>0;276;0c 设备属性、\u001b]10;... 颜色查询)。