Files
pangolin/client/lib/bridge/kernel_process.dart
T
wangjia c84b6ea7da 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 分支补全
2026-06-13 14:58:38 +08:00

113 lines
3.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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 实现');
}