Documentation
¶
Overview ¶
attachment.go —— 一次订阅的对外形态。
职责:定义调用方(agentd 的 pty_ws.go)看得见的四个字段与三个方法。
边界:它自己什么都不做——三个方法逐字转交注入进来的 ops。
为什么是「壳 + 注入」而不是接口:pty_ws.go 的 pumpPtyUplink 签名写死了 *ptyhost.Attachment。壳保住具体类型,让进程内引擎与 socket 客户端各自注入行为。
client.go —— agentd 侧的 Host:与进程内引擎逐字同签名,内部改为连 ptyhost socket。
职责:
- Open:建会话目录、写 spec、拉起 detached 的 _ptyhost、等待 socket
- List / Get:短连接查询 stat,拿到静态事实与活事实
- Write / Attach:复用订阅长连接传输 PTY 字节
- Close:显式发送 kill 帧;Adopt:登记启动扫描发现的活会话
边界:
- 不认识 PTY:不开伪终端、不解析转义序列,真正的引擎在 ptyhost 进程里
- 不做启动扫描:扫描由 agentd 调用 sessdir.Scan 后交给 Adopt
- 不删还活着的会话目录;目录收摊由 ptyhost 进程负责
为什么方法签名一个都不改:pty_api.go 与 pty_ws.go 只跟这六个方法打交道,保持 这些边界不变,agentd 的 HTTP 与 WebSocket 层就不需要知道进程已经移到外面。
client_process_unix.go —— Unix 上 ptyhost detached 进程的最小系统调用适配。
职责:让 ptyhost 脱离 agentd 的会话/进程组,并在 Open 失败时按组回收。 边界:不决定何时启动或回收,不读 spec,不写日志;业务语义在 client.go。
closeall.go —— 显式停止路径的批量收口。
职责:不依赖 agentd,直接扫会话根目录并逐个 kill。
边界:
- **只服务显式停止**(handoff service stop)。信号关停、升级换版、崩溃都 不该调它——那几条路必须让会话跨 agentd 生命周期活下来,那正是把 PTY 搬出 agentd 进程的全部意义
- 不删还活着的会话目录:目录收摊由 ptyhost 进程自己做,这里只发 kill
- 不改 agentd 的登记:调它的时候 agentd 可能已经不在了
为什么走目录扫描而不是让 agentd 代劳:显式停止的语义是「让这台机器上的 handoff 全停下来」,而它可能在 agentd 已经停掉之后才被执行(先 stop 服务 再想起来收口,或者 agentd 本来就崩着)。经 agentd 转一手就会在最需要它的 那种情形下失效。
会话级环境变量转发:把 SSH_AUTH_SOCK 这类「由会话注入、不来自 dotfile」的 变量解析出来,注入单个终端会话的环境。
职责:
- 按三级顺序解析每个变量:继承 → 平台查询 → 探不到
- 逐个变量记录三态结论,让「终端里 git push 失败」变成一行可搜的日志
边界:
- 只产出**这个会话的** cmd.Env,**绝不写回 agentd 自身环境**。这与 internal/pathenv 相反:PATH 是进程级恒定事实,socket 路径是会话级易变 事实,写回会让后续所有 fork 拿到一个可能已经失效的路径。
- 探不到就是探不到,不编造默认值(spec §4.2)
- 解析失败一律降级为 unavailable,不阻断会话创建
supported_unix.go —— ptyhost 公共包的 Unix PTY 能力常量。
职责:为 Supported 提供编译期能力结论。 边界:不启动 PTY、不连接引擎;引擎自己的同名常量留在 engine 包,避免包依赖环。
types.go —— agentd 与 ptyhost 引擎共用的会话数据形态。
职责:定义会话快照、开会话参数,以及平台 PTY 能力查询。
边界:不持有会话、不启动 shell、不连接 socket;生命周期与实现分别由 engine 和 client 负责。这里的结构只描述跨实现边界所需的数据。
Index ¶
- Variables
- func CloseAll(root string, log *slog.Logger, budget time.Duration) (int, error)
- func DefaultEnvForward() []string
- func ResolveEnvForward(names []string, base []string, log *slog.Logger) []string
- func Supported() bool
- type AttachOps
- type Attachment
- type Host
- func (h *Host) Adopt(entries []sessdir.Entry)
- func (h *Host) Attach(id string, since uint64) (*Attachment, error)
- func (h *Host) Close(id string) error
- func (h *Host) Get(id string) (Session, bool)
- func (h *Host) List() []Session
- func (h *Host) Open(opt OpenOptions) (Session, error)
- func (h *Host) Supported() bool
- func (h *Host) Write(id string, p []byte) error
- type OpenOptions
- type Session
Constants ¶
This section is empty.
Variables ¶
var ErrNoSession = errors.New("终端会话不存在")
ErrNoSession 表示会话 id 不存在(或已被显式关闭)。
var ErrNotSupported = errors.New("当前平台不支持 PTY 终端")
ErrNotSupported 表示当前平台没有 PTY 实现(Windows:ConPTY 是另一套 API, 本轮如实降级而不假装支持,见 spec §10)。
这个变量刻意放在**无构建标签**的文件里:两套 platform_*.go 都要引用它, 放进任一带标签的文件都会让另一套编译不过。
var ErrProtoMismatch = errors.New("会话由不兼容的版本托管")
ErrProtoMismatch 表示会话由当前客户端不认识的协议版本托管。
var ErrSessionExited = errors.New("终端会话已退出")
ErrSessionExited 表示 shell 已经退出,只能读历史不能再写。
var ErrTooManySubscribers = errors.New("终端会话的连接数已达上限")
ErrTooManySubscribers 表示该会话的订阅者已达上限。
Functions ¶
func CloseAll ¶ added in v0.3.5
CloseAll 扫描 root 下全部会话并 kill 掉还活着的那些。
参数:
- root: 会话根目录,通常是 <DataDir>/ptys。**不存在不算错**——这台机器 可能从没开过终端
- log: 日志入口,不能为 nil
- budget: 总时间预算;到点就返回,不阻塞调用方
返回:成功发出 kill 并等到收摊的会话数,以及扫描失败时的错误。 单个会话关不掉只记 Warn 不算整体失败——它可能刚好自己退了。
注意:dead 与 broken 状态的目录一概不碰。dead 的由 agentd 下次启动时清; broken 的意味着「有个进程活着而我们不知道它是什么」,杀它不安全。
func DefaultEnvForward ¶
func DefaultEnvForward() []string
DefaultEnvForward 返回内置默认清单的副本。
返回副本而不是切片本身:调用方(config 解析、测试)拿到后可能就地排序或改写, 那会污染进程内所有后续会话。
func ResolveEnvForward ¶
ResolveEnvForward 把 names 里每个变量按三级顺序解析后追加到 base,返回新环境。
参数:
- names: 要转发的变量名清单(调用方已按 nil→默认清单 归一化)
- base: 会话的基础环境(PATH / TERM 等),原样保留
- log: 逐个变量记录三态结论,不得为 nil
返回:base + 解析成功的 `NAME=VALUE`。探不到的变量**不出现**在结果里。
注意:日志只记变量名与结论来源,**不记变量值**——今天转发的是 socket 路径, 但这份清单是用户可配的,明天可能就有人往里加一个带凭据的变量。
Types ¶
type AttachOps ¶ added in v0.3.5
AttachOps 是一次订阅的三个行为,由构造它的一方提供。
导出它是因为 internal/ptyhost/engine 要在包外实现它;本包之外没有别的合法实现者。
type Attachment ¶
type Attachment struct {
Backlog []byte
Since uint64
Truncated bool
Out <-chan []byte
// contains filtered or unexported fields
}
Attachment 是一次订阅。Backlog 是建连瞬间的历史回放,Out 是后续实时输出; Out 被关闭意味着会话结束(不是网络抖动),客户端应停止重连。
注意:Backlog 与 Out 必须按构造方的协议语义消费;Detach 只退订,不杀会话。
func NewAttachment ¶ added in v0.3.5
func NewAttachment(backlog []byte, since uint64, truncated bool, out <-chan []byte, ops AttachOps) *Attachment
NewAttachment 组装一个订阅壳。
参数:backlog/since/truncated/out 是订阅结果;ops 提供 Detach、ExitCode、Resize 行为。 返回:可交给 pty_ws.go 的具体 Attachment。 注意:ops 不应为 nil;调用三个方法前必须由构造者注入有效行为。
func (*Attachment) ExitCode ¶
func (a *Attachment) ExitCode() *int
ExitCode 返回 shell 的退出码;nil 表示还活着,或对端没给出退出码。
func (*Attachment) Resize ¶
func (a *Attachment) Resize(cols, rows int) error
Resize 上报本订阅者的尺寸;实际尺寸由所有订阅者取最小值协商而来。
type Host ¶
type Host struct {
// contains filtered or unexported fields
}
Host 是 agentd 侧的 ptyhost 客户端。零值不可用,请用 New。
func New ¶
New 创建一个 ptyhost 客户端。
参数:root 是 <DataDir>/ptys 会话根目录;selfExe 是当前 handoff 可执行文件的绝对路径; log 是 agentd 日志入口,不能为 nil。 返回:一个尚未登记会话的 Host。 注意:New 不扫描 root,也不连接任何 socket;启动时认领由 Adopt 完成。
func (*Host) Adopt ¶ added in v0.3.5
Adopt 登记启动扫描发现的活会话。
参数:entries 是 sessdir.Scan 的结果;只有 StateLive 会被登记,broken 与 dead 由调用方处理。 返回:无。已有同 id 登记会被新的静态元数据覆盖。 注意:Adopt 不连接 socket、不验证协议、不删除目录;它是启动路径的纯登记动作。
func (*Host) Attach ¶
func (h *Host) Attach(id string, since uint64) (*Attachment, error)
Attach 建立一条长期订阅连接。
参数:id 是会话 id;since 是环形缓冲的输出水位。 返回:带历史回放与实时输出通道的 Attachment。 注意:协议版本先从 meta.json 检查;Backlog 在返回前已从 attached 后的第一数据帧取出。
func (*Host) Close ¶
Close 显式杀掉一个会话,并从本地登记中摘除它。
参数:id 是会话 id。 返回:kill 帧发送或等待 ptyhost 收摊失败时报错。 注意:这条路径才发送 kill;Attach 的 Detach 永远只关闭订阅 socket。
func (*Host) Get ¶
Get 取一个已登记会话的最新快照。
返回:第二个返回值 false 表示客户端没有登记该 id;stat 失败时仍返回静态快照与 true。 注意:活事实不从旧缓存猜,查询失败的字段保持其零值。
func (*Host) List ¶
List 返回已登记的全部会话。
返回:每条会话都保留;stat 失败时返回静态元数据与活事实零值,并记 Debug。 注意:查询并发进行,每条连接最多等待 statWait,避免 N 个会话串行拖慢恢复。
func (*Host) Open ¶
func (h *Host) Open(opt OpenOptions) (Session, error)
Open 创建会话并拉起一个脱离 agentd 生命周期的 ptyhost 进程。
参数:opt 是 shell、cwd、环境与初始尺寸。 返回:成功时返回会话快照;失败时保证不会留下本次创建的会话目录。 注意:ptyhost 由自身进程负责收尸,agentd 不等待它退出。
type OpenOptions ¶
type OpenOptions struct {
BasePath string
BaseKind string
Shell string
Env []string
Cols int
Rows int
}
OpenOptions 是开会话的入参。
参数:Env 是完整环境,不会再自动追加 os.Environ;Cols/Rows <= 0 时实现使用默认尺寸。 返回:由 Open 消费,不保留调用方切片的生命周期承诺。 注意:Shell 与 BasePath 必须是目标机器上可执行且可访问的值。
type Session ¶
type Session struct {
ID string
BasePath string
BaseKind string
Shell string
CreatedAt time.Time
Cols int
Rows int
Attached int
PID int
ExitCode *int
// Incompatible 表示该会话由当前客户端不认识的协议版本托管;进程仍活着,
// 但本版不能 Attach,只能在界面走「重开一个终端」出口。
Incompatible bool
// Foreground 表示会话里当前有一个跑在前台的命令。
Foreground bool
BytesOut uint64
}
Session 是一个会话的快照,跨出实现内部的锁之后可以自由持有。
参数:无;字段由引擎或客户端填充。 返回:作为值传递的静态事实与活事实快照。 注意:ExitCode 为 nil 表示还活着;Foreground 与 BytesOut 来自 stat,不能用旧元数据猜。
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package engine 托管伪终端(PTY)会话:开 shell、持有会话表、维护回放缓冲、 向多个订阅者广播输出、按进程组终止。
|
Package engine 托管伪终端(PTY)会话:开 shell、持有会话表、维护回放缓冲、 向多个订阅者广播输出、按进程组终止。 |
|
Package hostproc 是 ptyhost 进程的主体:一个进程托管一个 PTY 会话。
|
Package hostproc 是 ptyhost 进程的主体:一个进程托管一个 PTY 会话。 |
|
Package sessdir 是 PTY 会话在磁盘上的落点:目录布局、元数据、以及跨 agentd 重启的三态扫描。
|
Package sessdir 是 PTY 会话在磁盘上的落点:目录布局、元数据、以及跨 agentd 重启的三态扫描。 |
|
Package wire 是 agentd 与 ptyhost 进程之间的帧格式。
|
Package wire 是 agentd 与 ptyhost 进程之间的帧格式。 |