ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

读Open Terminal源码:FastAPI+PTY如何把一台电脑变成REST API

读Open Terminal源码:FastAPI+PTY如何把一台电脑变成REST API 读Open Terminal源码:FastAPIPTY如何把一台电脑变成REST API【免费下载链接】open-terminalA computer you can curl ⚡项目地址: https://gitcode.com/gh_mirrors/ope/open-terminalOpen Terminal 是一个轻量级的自托管终端 API它用 FastAPI 做 HTTP 服务层用 PTY伪终端做命令执行层把一台 Linux/macOS 电脑变成可以通过 REST API 调用的远程计算机——运行命令、读写文件、搜索代码、甚至开一个交互式 Shell全部通过curl即可完成 ⚡。本文带你从源码角度看懂这两块核心技术如何拼在一起。一句话架构HTTP 接口 子进程 文件操作Open Terminal 的核心代码只有一个包open_terminal/总共约 5000 行 Python。整个系统可以拆成三层层负责什么关键文件API 层接收 HTTP 请求、鉴权、路由open_terminal/main.py执行层启动子进程、接管 PTY 输出open_terminal/utils/runner.py启动层CLI 参数解析、配置加载open_terminal/cli.pyFastAPI 应用实例在 main.py 第 209 行 创建所有接口共用一个 Bearer Token 鉴权依赖verify_api_key未带正确 API Key 的请求统一返回 401。第一步用 FastAPI 把命令执行变成 POST 请求最有代表性的接口是POST /execute。你发一个 JSON{command: ls -la}它做了四件事创建 Runner调用 create_runner 工厂函数根据平台选择 PTY / WinPTY / 管道三种后端之一登记进程生成时间戳随机数的进程 ID把进程放进内存字典_processes同时启动一个后台任务把输出实时写入 JSONL 日志文件可选等待支持wait参数在超时前持续收集输出见 main.py 第 1726 行返回结果输出按条目存储后续用GET /execute/{id}/status?offsetN增量轮询——这个offset 增量读取设计让 AI 客户端可以反复拉取新输出而不重复消费。除了执行命令FastAPI 层还暴露了一整套文件工具接口/files/list、/files/read、/files/write、/files/replace带行号范围限制的精确查找替换、/files/grep正则搜索优先调用系统里的rg否则回退到纯 Python 实现见 main.py 第 1183 行、/files/matches按文件名和内容综合排序的搜索。读文件接口还有一个巧思遇到 PDF、Office 文档时自动抽取文本返回遇到图片则直接返回二进制——因为它的目标用户是 LLM而不是浏览器 。文件操作统一走UserFS这个封装类open_terminal/utils/fs.py单用户模式下用标准库直接 I/O多用户模式下自动改走sudo -u让每个用户只能碰自己的家目录。核心魔法PTY 让命令以为自己运行在真终端里这是本文的重点。普通subprocess只能拿到管道输出而很多程序vim、pip进度条、带颜色的 CLI会检测到不是终端就改变行为甚至拒绝运行。解决方案就是PTY伪终端内核提供一对文件描述符slave 端交给子进程当 stdin/stdout/stderr 用master 端由服务端读取——子进程以为自己连着真实终端一切 ANSI 转义序列照常工作。看 runner.py 中的 PtyRunner关键就三步pty.openpty()打开伪终端对用ioctl(TIOCSWINSZ)设置 24×80 的默认窗口尺寸subprocess.Popen启动 shell三个标准流全部指向 slave fd并设置start_new_sessionTrue让子进程拥有独立进程组——这样杀命令时可以对整个进程组发SIGTERM连sleep 999 这种后台任务一起收走不留孤儿进程。读取输出时read_output 方法代码把阻塞的os.read(master_fd)丢进线程池执行每读到一块数据就追加时间戳写成 JSON 行实现异步友好的实时日志流。跨平台与降级策略create_runner 工厂 体现了优雅的降级链Linux / macOS→PtyRunner原生 PTYWindows→WinPtyRunner通过 pywinpty 的 ConPTY都没有→PipeRunner普通管道功能可用但失去终端特性交互式终端接口POST /api/terminals同理main.py 第 2008 行 先探测 PTY 是否可用不可用再尝试 WinPTY都失败则返回 503 并提示安装依赖。每个会话还受MAX_TERMINAL_SESSIONS上限保护PTY 设备耗尽时返回 503 而不是崩溃。WebSocket 层把键盘按键和屏幕输出双向打通对于需要真正交互式 Shell的场景比如 AI Agent 想在python解释器里连续敲代码REST 轮询太慢了。Open Terminal 在 main.py 第 2283 行 提供了一个 WebSocket 端点/api/terminals/{session_id}协议设计得很克制首帧鉴权连接后必须先在 10 秒内发送{type: auth, token: key}失败即断开二进制帧 数据客户端发按键、服务端回 PTY 输出全程走 bytes零序列化开销文本帧 控制信令发送{type: resize, cols: 120, rows: 40}就能让服务端调用ioctl调整终端窗口vim的布局会实时跟着变。服务端用一个_pty_reader任务把 PTY 输出持续转发到 WebSocket并维护一个 64KB 的环形输出缓冲第 2397 行供 REST 接口随时回读最近内容。断连时清理逻辑会先SIGTERM、等 3 秒、再SIGKILL整个进程组确保资源不泄漏见 _cleanup_session。其余亮点这些细节让 AI 用得更顺手进程自动清理结束 5 分钟后的进程从内存移除日志文件超过保留期自动删除_cleanup_expired会话级工作目录用X-Session-Id请求头追踪每个会话的 cwd替代了不安全的进程级os.chdir并发会话互不串扰转义序列容错POST /execute/{id}/input会把字面量\n、\x03Ctrl-C转成真实控制字符——因为 LLM 经常字面地输出这些转义符第 1828 行端口检测 反向代理GET /ports列出本机监听端口/proxy/{port}/...直接代理请求AI 启动一个 Web 服务后无需暴露端口就能访问LLM 系统提示GET /system返回一段描述当前操作系统、Shell、Python 版本的提示词模板帮助 LLM 快速了解这台机器。如何安装与启动 Open Terminal两种部署方式任选其一# Docker推荐自带完整开发工具链的沙箱 docker run -d --name open-terminal -p 8000:8000 \ -v open-terminal:/home/user \ -e OPEN_TERMINAL_API_KEYyour-secret-key \ ghcr.io/open-webui/open-terminal# 裸机运行标准 Python 包pip 即可装 pip install open-terminal open-terminal run --host 0.0.0.0 --port 8000 --api-key your-secret-key启动入口是 cli.py 中的 run 命令用 Click 解析参数、加载 TOML 配置优先级为 CLI 参数 环境变量 用户配置 系统配置 默认值见 config.py最后交给 uvicorn 跑起 FastAPI。不设置 API Key 时会自动生成一个并打印在启动日志里。服务起来后访问http://localhost:8000/docs即可看到自动生成的交互式 API 文档——这就是 FastAPI 白送的福利。⚠️ 裸机模式下命令以你当前用户的权限直接执行想要隔离环境请用 Docker。总结Open Terminal 用不到 5000 行代码演示了一套非常干净的把系统能力 API 化的工程范式FastAPI 负责接口长什么样——声明式路由、自动 OpenAPI 文档、依赖注入式鉴权PTY 负责命令怎么跑——伪终端保证任意 CLI 程序行为一致独立进程组保证可彻底清理异步 I/O 负责并发怎么扛——阻塞的系统调用一律丢进线程池WebSocket 与 REST 双通道满足不同场景。如果你想给自己的 AI Agent 配一台随叫随到的云端小电脑这套源码值得逐行读一遍它证明了把一台电脑变成 REST API核心代码其实并不多。【免费下载链接】open-terminalA computer you can curl ⚡项目地址: https://gitcode.com/gh_mirrors/ope/open-terminal创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表