- SessionMachine 加 mosh 三相(moshActive/moshParked/moshResuming)+看门狗兜底, mosh 接管即拆 SSH、后台冻结不重建、前台唤醒脉冲等 SSP 续(+5 单测) - bridge.go: Node.WakeUp()(tsnet InjectEvent+MagicSock.Rebind/ReSTUN) + MoshRelay.Rebind()(同端口重开 loopback、泵按 socket 生成容错) - iosclient.cc: g_mosh_last_heard 探针(导出 mosh_last_heard_ms) + SIGCONT 全屏重绘 - MoshSession: nudge()(SIGCONT) + lastHeardMs();SSHTerminalModel 前台脉冲三连 + healthy 轮询 + beginBackgroundTask;URL scheme 供无头前台唤醒 - 验证(vohive-vm over tsnet):15s 冻结→前台 wake pulse→1.3s recovered,<3s Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
98 lines
4.1 KiB
Objective-C
98 lines
4.1 KiB
Objective-C
// Objective-C API for talking to terminalx/tsnetbridge/tsnetbridge Go package.
|
||
// gobind -lang=objc terminalx/tsnetbridge/tsnetbridge
|
||
//
|
||
// File is generated by gobind. Do not edit.
|
||
|
||
#ifndef __Tsnetbridge_H__
|
||
#define __Tsnetbridge_H__
|
||
|
||
@import Foundation;
|
||
#include "ref.h"
|
||
#include "Universe.objc.h"
|
||
|
||
|
||
@class TsnetbridgeMoshRelay;
|
||
@class TsnetbridgeNode;
|
||
|
||
/**
|
||
* MoshRelay 是一条 mosh-over-tsnet 的 UDP 中继:
|
||
mosh-client 在本地把 UDP 包发到 127.0.0.1:<LocalPort>,本中继逐包经 tsnet 转发到
|
||
tailnet 内 host:moshPort,回包再转回"最近一次上行的 client 源地址"(吸收 mosh 的 roaming/端口跳变)。
|
||
与 DialTCPFD 的差异:mosh 内部自建 UDP socket 并 connect(),无法注入外部 fd,故用 loopback relay。
|
||
*/
|
||
@interface TsnetbridgeMoshRelay : NSObject <goSeqRefInterface> {
|
||
}
|
||
@property(strong, readonly) _Nonnull id _ref;
|
||
|
||
- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
|
||
- (nonnull instancetype)init;
|
||
/**
|
||
* Close 关闭中继(两条泵随 conn 关闭而退出)。
|
||
*/
|
||
- (BOOL)close:(NSError* _Nullable* _Nullable)error;
|
||
/**
|
||
* LocalPort 返回固定的 loopback relay 端口(mosh_main 的 port 参数,跨 Rebind 不变)。
|
||
*/
|
||
- (long)localPort;
|
||
/**
|
||
* Rebind 在同端口重开 loopback socket(iOS 前台恢复用:挂起后旧 socket 可能被系统回收为 defunct)。
|
||
关旧 socket → 旧上行泵退出 → 新泵接管;下行泵绑定稳定 tsConn 无需重启。端口被占等返回 error(由上层升级为全量重建)。
|
||
*/
|
||
- (BOOL)rebind:(NSError* _Nullable* _Nullable)error;
|
||
@end
|
||
|
||
/**
|
||
* Node 包装一个嵌入式 tsnet 节点。gomobile 导出为引用型对象。
|
||
*/
|
||
@interface TsnetbridgeNode : NSObject <goSeqRefInterface> {
|
||
}
|
||
@property(strong, readonly) _Nonnull id _ref;
|
||
|
||
- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
|
||
/**
|
||
* NewNode 创建(不启动)一个 tsnet 节点。stateDir 唯一、hostname 展示在管理台。
|
||
*/
|
||
- (nullable instancetype)init:(NSString* _Nullable)stateDir hostname:(NSString* _Nullable)hostname;
|
||
/**
|
||
* Close 释放节点。
|
||
*/
|
||
- (BOOL)close:(NSError* _Nullable* _Nullable)error;
|
||
/**
|
||
* DialTCPFD 经 tsnet 连接 tailnet 内 host:port,返回一个已连接的 socket fd 供 libssh2 使用。
|
||
实现:tsnet.Dial 得到 net.Conn(netstack 虚拟连接,无真实 fd)→ socketpair(AF_UNIX) →
|
||
两条 goroutine 双向 io.Copy 泵 → 把 socketpair 的另一端 fd 返回给 Swift。
|
||
Swift 侧 close(fd) 会触发泵结束并关闭 tsConn。返回 -1 + error 表示失败。
|
||
*/
|
||
- (BOOL)dialTCPFD:(NSString* _Nullable)hostOrIP port:(long)port timeoutMs:(long)timeoutMs ret0_:(int64_t* _Nullable)ret0_ error:(NSError* _Nullable* _Nullable)error;
|
||
/**
|
||
* PeersJSON 返回 tailnet 内其它节点列表(name/ip/online/os)的 JSON,用于选择连接目标。
|
||
*/
|
||
- (NSString* _Nonnull)peersJSON;
|
||
/**
|
||
* SelfIP 返回本节点的 Tailscale IPv4(经 LocalClient().Status() 取;未就绪返回空串)。
|
||
*/
|
||
- (NSString* _Nonnull)selfIP;
|
||
/**
|
||
* StartMoshRelay 建立中继并启动双向泵,返回句柄。Swift 用 LocalPort() 作为 mosh_main 的 port
|
||
参数、ip 传 "127.0.0.1"。失败返回 nil + error。timeoutMs 限制 tsnet UDP Dial 的建连等待。
|
||
*/
|
||
- (TsnetbridgeMoshRelay* _Nullable)startMoshRelay:(NSString* _Nullable)host moshPort:(long)moshPort timeoutMs:(long)timeoutMs error:(NSError* _Nullable* _Nullable)error;
|
||
/**
|
||
* UpWithAuthKey 用 auth key 启动并等待 Running(timeoutMs 到则返回 error)。
|
||
gomobile 友好签名:基本类型入参、error 出参。
|
||
*/
|
||
- (BOOL)upWithAuthKey:(NSString* _Nullable)authKey timeoutMs:(long)timeoutMs error:(NSError* _Nullable* _Nullable)error;
|
||
/**
|
||
* WakeUp 在 iOS 前台恢复时主动唤醒 tsnet 网络层:注入链路变化事件 + Rebind/重新 STUN,
|
||
把"等首次写失败才发现 DERP/路径已死"变成"立刻重建",配合 mosh SSP 实现秒级恢复。
|
||
*/
|
||
- (void)wakeUp;
|
||
@end
|
||
|
||
/**
|
||
* NewNode 创建(不启动)一个 tsnet 节点。stateDir 唯一、hostname 展示在管理台。
|
||
*/
|
||
FOUNDATION_EXPORT TsnetbridgeNode* _Nullable TsnetbridgeNewNode(NSString* _Nullable stateDir, NSString* _Nullable hostname);
|
||
|
||
#endif
|