Files
desktop-plugin/lib/utils/command_runner.dart
dzc 689a07ca44 feat: 饭卡打印助手 Flutter 版(Phase 1/2:协议服务器 + macOS CUPS 真机打印)
- 协议与 C# 版 card-printer-agent 逐字段对齐(38200-38202 顺延、CORS *、串行任务队列、30 分钟保留)
- macOS CUPS 后端:lpoptions 队列发现 + lp 参数列表提交(LC_ALL=C 防本地化粘连坑)
- --mock 模拟模式 + bin/agent.dart headless 入口 + 测试卡生成工具
- 真机验收:HiTi CS-200e status 就绪 + 真实出卡;macOS 通用二进制构建通过
- App Sandbox 已关闭(服务需绑回环端口并调用 lp 子进程);zaxprint URL scheme 已注册
2026-09-21 12:03:27 +08:00

55 lines
1.6 KiB
Dart
Raw Permalink 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 'dart:convert';
import 'dart:io';
/// 外部命令执行失败(非零退出/超时/无法启动)。
class CommandException implements Exception {
CommandException(this.message);
final String message;
@override
String toString() => message;
}
/// 运行外部命令(lp/lpoptions/lpstat)并返回标准输出。
///
/// 一律用参数列表传参不经过 shell,杜绝命令注入;
/// 强制 LC_ALL=C 英文输出(macOS 会把 lpstat/lp 本地化,中文系统队列名与状态词粘连无法按空格解析)。
Future<String> runCommand(
String executable,
List<String> arguments, {
int timeoutMs = 15000,
bool tolerateExit = false,
}) async {
final Process process;
try {
process = await Process.start(
executable,
arguments,
environment: const {'LC_ALL': 'C', 'LANG': 'C'},
);
} on ProcessException catch (e) {
throw CommandException('无法启动 $executable:${e.message}');
}
// stdout/stderr 立即挂上消费 Future,避免管道缓冲区写满导致死锁
final stdoutFuture = process.stdout.transform(utf8.decoder).join();
final stderrFuture = process.stderr.transform(utf8.decoder).join();
final int exitCode;
try {
exitCode = await process.exitCode.timeout(Duration(milliseconds: timeoutMs));
} on TimeoutException {
process.kill();
throw CommandException('$executable 执行超时');
}
final out = await stdoutFuture;
if (exitCode != 0 && !tolerateExit) {
final err = await stderrFuture;
throw CommandException('$executable 返回 $exitCode:${err.trim()}');
}
return out;
}