Files
desktop-plugin/lib/agent.dart
T
dzc bee734fd5b feat: 后台托盘 + 资安信品牌化 + 修复布局断言(Phase 4 部分)
- 后台托盘(mac/Windows):window_manager 拦截关窗改隐藏,服务持续运行;
  托盘单击恢复窗口、右键菜单(显示主界面/退出),退出入口仅放托盘菜单
- 品牌:App 更名"资安信插件助手"(mac PRODUCT_NAME/xib、win main.cpp+Runner.rc(code_page 65001)、
  MaterialApp/侧栏/托盘 tooltip/日志);图标全家桶换资安信盾牌 logo
  (tool/gen_app_icons.dart 生成 mac AppIcon 7 尺寸/win ICO 7 尺寸/托盘白底圆盘版/assets logo)
- 修复启动布局断言:SliverList 内 Row(stretch) 需 IntrinsicHeight 包裹,
  否则子项收到 h=Infinity 约束(用户实测报错,test/ui_smoke_test.dart 守护复现)
- Agent.stop 幂等(托盘退出与窗口销毁竞态安全)
- 测试修复:smoke 测试改 tester.runAsync 包真实 socket I/O(fake async zone 里会永久挂起)、
  显式 pump 替代 pumpAndSettle;13 个测试全过,analyze 零问题,release 构建实测通过
2026-09-21 13:16:23 +08:00

93 lines
2.7 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.
import 'dart:async';
import 'print/backend.dart';
import 'print/mock_backend.dart';
import 'server/http_server.dart';
import 'server/print_queue.dart';
/// 启动参数:--mock 模拟打印;--port=NNN / --port NNN 指定监听端口(默认 38200-38202 顺延)。
class AgentOptions {
AgentOptions({this.mock = false, this.port});
final bool mock;
final int? port;
factory AgentOptions.parse(List<String> args) {
var mock = false;
int? port;
for (var i = 0; i < args.length; i++) {
final arg = args[i];
if (arg == '--mock') {
mock = true;
} else if (arg.startsWith('--port=')) {
port = int.tryParse(arg.substring('--port='.length));
} else if ((arg == '--port' || arg == '-p') && i + 1 < args.length) {
port = int.tryParse(args[++i]);
}
}
return AgentOptions(mock: mock, port: port);
}
}
/// 运行日志环形缓冲(GUI 展示用),同时打到 stdout。
class AgentLog {
final lines = <String>[];
final _controller = StreamController<String>.broadcast();
Stream<String> get stream => _controller.stream;
void write(String line) {
final stamped = '${DateTime.now().toIso8601String().substring(11, 19)} $line';
lines.add(stamped);
if (lines.length > 500) {
lines.removeRange(0, lines.length - 500);
}
// ignore: avoid_print
print(stamped);
_controller.add(stamped);
}
void dispose() => _controller.close();
}
/// 助手核心:组合打印后端、任务队列与 HTTP 服务(Flutter 窗口与 headless 入口共用)。
class Agent {
Agent(this.options) : log = AgentLog();
final AgentOptions options;
final AgentLog log;
late final PrintQueue queue;
late final PrintBackend backend;
late final AgentHttpServer server;
int? port;
Future<int> start() async {
final backendName = osBackendName();
backend = options.mock ? MockBackend(onLog: log.write) : createOsBackend(onLog: log.write);
queue = PrintQueue(backend, onLog: log.write);
server = AgentHttpServer(
queue: queue,
backend: backend,
mock: options.mock,
manifestBackendName: backendName,
);
final ports = options.port == null ? const [38200, 38201, 38202] : <int>[options.port!];
port = await server.start(candidatePorts: ports);
log.write('资安信插件助手已启动 http://127.0.0.1:$port'
'(后端=$backendName,mock=${options.mock},agent=desktop-plugin)');
return port!;
}
bool _stopped = false;
/// 幂等停止:托盘退出与窗口销毁可能先后各调一次。
Future<void> stop() async {
if (_stopped) return;
_stopped = true;
await server.stop();
queue.dispose();
log.dispose();
}
}