merge: maestro/tsk_iP5-_Ztq5THx [桥接 API 面 Channel 契约 + 三端原生骨架] [tsk_rcNKc3GQHBUd]
合并冲突补救:原分支从 merge base 7871512 分叉,仅修改 client/ 目录,
与 main 新增的 server/(apierr/idgen/CONVENTIONS.md) 完全不重叠,
无真实文件冲突,手动应用 feature branch 的全部 client/ 改动。
client 侧新增:
- lib/bridge/vpn_bridge.dart — Dart↔原生通道契约(冻结)
- lib/bridge/vpn_bridge_mock.dart — 假内核,UI 联调用
- lib/bridge/kernel_process.dart — 桌面子进程管理接口
- ios/PacketTunnel/{Info.plist,PacketTunnelProvider.swift} — NEPacketTunnel 骨架
- ios/Runner/VpnManager.swift — NETunnelProviderManager 封装
- android/.../PangolinVpnService.kt — VpnService 骨架
- android/.../VpnEventBus.kt — Application 级状态总线
- test/bridge/vpn_bridge_mock_test.dart — 桥接层单元测试
client 侧修改:
- android/.../MainActivity.kt — 注册三通道(MethodChannel + 2×EventChannel)
- android/.../AndroidManifest.xml — 声明 FOREGROUND_SERVICE + PangolinVpnService
- ios/Runner/AppDelegate.swift — 注册通道 + VpnManager 初始化
- ios/Runner/Info.plist — 新增 NSVPNUsageDescription
- ios/Runner.xcodeproj/project.pbxproj — 添加 PacketTunnel extension target
- lib/widgets/connect_button.dart — VpnStatus 迁移到 bridge/vpn_bridge.dart
- lib/widgets/home_shell.dart — error 状态 UI 分支补全
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
// kernel_process.dart — 桌面端内核子进程管理接口
|
||||
//
|
||||
// 桌面平台(macOS / Windows / Linux)直接将 sing-box 二进制作为
|
||||
// 子进程运行,通过其 Clash 兼容 REST API 进行控制。
|
||||
//
|
||||
// 本文件仅定义接口契约;具体实现由任务 11D(桌面 PoC)完成。
|
||||
//
|
||||
// 进程生命周期:
|
||||
// spawn(configPath) → 子进程启动,REST API 开始监听
|
||||
// kill() → 优雅停止(SIGTERM),超时后 SIGKILL
|
||||
//
|
||||
// Clash API 通信由 [ClashApiClient] 封装,基地址固定为
|
||||
// http://127.0.0.1:9090(可覆盖)。
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
// ── Clash API 客户端 ─────────────────────────────────────────────
|
||||
|
||||
/// sing-box Clash 兼容 REST API 客户端。
|
||||
/// 实现由 11D(桌面 PoC)填充;本骨架仅定义调用约定。
|
||||
class ClashApiClient {
|
||||
ClashApiClient({this.baseUrl = 'http://127.0.0.1:9090'});
|
||||
|
||||
final String baseUrl;
|
||||
|
||||
/// GET /traffic — 流量统计
|
||||
Future<Map<String, dynamic>> getTraffic() {
|
||||
throw UnimplementedError('ClashApiClient.getTraffic — 11D 实现');
|
||||
}
|
||||
|
||||
/// GET /proxies — 节点列表
|
||||
Future<Map<String, dynamic>> getProxies() {
|
||||
throw UnimplementedError('ClashApiClient.getProxies — 11D 实现');
|
||||
}
|
||||
|
||||
/// PUT /proxies/{group} — 切换出口
|
||||
Future<void> selectProxy(String group, String proxy) {
|
||||
throw UnimplementedError('ClashApiClient.selectProxy — 11D 实现');
|
||||
}
|
||||
|
||||
/// GET /connections — 实时连接
|
||||
Future<Map<String, dynamic>> getConnections() {
|
||||
throw UnimplementedError('ClashApiClient.getConnections — 11D 实现');
|
||||
}
|
||||
|
||||
/// DELETE /connections — 关闭所有连接
|
||||
Future<void> closeAllConnections() {
|
||||
throw UnimplementedError('ClashApiClient.closeAllConnections — 11D 实现');
|
||||
}
|
||||
}
|
||||
|
||||
// ── 进程管理接口 ─────────────────────────────────────────────────
|
||||
|
||||
/// 桌面端内核子进程管理接口。
|
||||
///
|
||||
/// 使用方式:
|
||||
/// ```dart
|
||||
/// final kernel = DesktopKernelProcess();
|
||||
/// await kernel.spawn('/path/to/config.json');
|
||||
/// final traffic = await kernel.clashApiClient.getTraffic();
|
||||
/// await kernel.kill();
|
||||
/// ```
|
||||
abstract class KernelProcess {
|
||||
/// 启动内核子进程。
|
||||
///
|
||||
/// [configPath] 为 sing-box JSON 配置文件的绝对路径。
|
||||
/// 返回的 [Future] 在进程就绪(REST API 可用)后 complete。
|
||||
Future<void> spawn(String configPath);
|
||||
|
||||
/// 停止内核子进程。
|
||||
///
|
||||
/// 先发 SIGTERM,[gracePeriod] 内未退出则 SIGKILL。
|
||||
Future<void> kill({
|
||||
Duration gracePeriod = const Duration(seconds: 3),
|
||||
});
|
||||
|
||||
/// 进程是否正在运行。
|
||||
bool get isRunning;
|
||||
|
||||
/// Clash 兼容 REST API 客户端(进程运行时可用)。
|
||||
ClashApiClient get clashApiClient;
|
||||
|
||||
/// 进程标准输出/标准错误日志流(用于调试面板)。
|
||||
Stream<String> get logStream;
|
||||
}
|
||||
|
||||
// ── 占位实现(防 analyze 报错)────────────────────────────────────
|
||||
|
||||
/// 占位实现,抛出 [UnimplementedError]。
|
||||
/// 11D 替换为真实子进程实现时删除本类。
|
||||
class DesktopKernelProcess implements KernelProcess {
|
||||
@override
|
||||
Future<void> spawn(String configPath) {
|
||||
throw UnimplementedError('DesktopKernelProcess.spawn — 11D 实现');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> kill({Duration gracePeriod = const Duration(seconds: 3)}) {
|
||||
throw UnimplementedError('DesktopKernelProcess.kill — 11D 实现');
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isRunning => false;
|
||||
|
||||
@override
|
||||
ClashApiClient get clashApiClient =>
|
||||
throw UnimplementedError('DesktopKernelProcess.clashApiClient — 11D 实现');
|
||||
|
||||
@override
|
||||
Stream<String> get logStream =>
|
||||
throw UnimplementedError('DesktopKernelProcess.logStream — 11D 实现');
|
||||
}
|
||||
Reference in New Issue
Block a user