Files
windows-application/lib/core/system_info.dart
2026-01-22 15:14:27 +08:00

199 lines
6.5 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:io';
import 'package:logging/logging.dart';
import '../models/client_status.dart';
import '../utils/path_utils.dart';
/// 系统信息获取服务
class SystemInfoService {
static final SystemInfoService _instance = SystemInfoService._internal();
factory SystemInfoService() => _instance;
SystemInfoService._internal();
final Logger _logger = Logger('SystemInfoService');
/// 获取机器码(使用硬盘序列号)
Future<String> getMachineCode() async {
try {
if (Platform.isWindows) {
// 延迟执行,避免启动时崩溃
await Future.delayed(const Duration(seconds: 3));
// 使用 wmic 获取硬盘序列号
try {
final result = await Process.run(
'wmic',
['diskdrive', 'get', 'serialnumber'],
runInShell: true,
);
if (result.exitCode == 0) {
final output = result.stdout.toString();
final lines = output.split('\n');
// 查找序列号(跳过标题行)
for (final line in lines) {
final trimmed = line.trim();
if (trimmed.isNotEmpty &&
!trimmed.toLowerCase().contains('serialnumber') &&
trimmed != '') {
// 提取序列号(去除空格)
final serial = trimmed.replaceAll(RegExp(r'\s+'), '');
if (serial.isNotEmpty) {
_logger.info('获取到硬盘序列号: $serial');
return serial;
}
}
}
}
_logger.warning('wmic 命令执行成功但未找到有效序列号');
} catch (e) {
_logger.warning('使用 wmic 获取硬盘序列号失败: $e');
}
// 备用方案:使用环境变量生成标识符
final computerName = Platform.environment['COMPUTERNAME'] ?? 'UNKNOWN';
final userName = Platform.environment['USERNAME'] ?? 'UNKNOWN';
final userProfile = Platform.environment['USERPROFILE'] ?? '';
final identifier = '${computerName}_${userName}_${userProfile.hashCode.abs()}';
_logger.info('使用备用标识符作为机器码: $identifier');
return identifier;
}
// 非 Windows 系统
_logger.warning('无法获取机器码,使用临时标识');
return 'UNKNOWN_${DateTime.now().millisecondsSinceEpoch}';
} catch (e) {
_logger.severe('获取机器码失败: $e');
// 不抛出异常,返回临时标识
return 'ERROR_${DateTime.now().millisecondsSinceEpoch}';
}
}
/// 获取GPU信息仅在启动时调用一次
Future<List<GPUInfo>> getGPUInfo() async {
try {
// 使用 nvidia-smi 获取GPU信息
final result = await Process.run(
'nvidia-smi',
['--query-gpu=index,name,memory.total', '--format=csv,noheader,nounits'],
runInShell: true,
).timeout(
const Duration(seconds: 10),
onTimeout: () {
_logger.warning('nvidia-smi 执行超时');
return ProcessResult(0, -1, '', 'timeout');
},
);
if (result.exitCode != 0) {
_logger.warning('nvidia-smi 执行失败: exitCode=${result.exitCode}, stderr=${result.stderr}');
return [];
}
final output = result.stdout.toString().trim();
if (output.isEmpty) {
_logger.info('nvidia-smi 返回空输出未检测到GPU');
return [];
}
final lines = output.split('\n');
final gpus = <GPUInfo>[];
for (final line in lines) {
if (line.trim().isEmpty) continue;
final parts = line.split(', ');
if (parts.length >= 3) {
try {
final index = int.parse(parts[0].trim());
final model = parts[1].trim();
final memoryStr = parts[2].trim();
final memory = double.tryParse(memoryStr) ?? 0;
gpus.add(GPUInfo(
index: index,
brand: 'NVIDIA',
model: model,
memory: memory,
));
_logger.info('检测到GPU: 索引=$index, 型号=$model, 显存=${memory}MB');
} catch (e) {
_logger.warning('解析GPU信息失败: $line, 错误: $e');
}
}
}
if (gpus.isEmpty) {
_logger.info('未检测到GPU');
} else {
_logger.info('成功获取 ${gpus.length} 个GPU信息');
}
return gpus;
} catch (e) {
_logger.warning('获取GPU信息失败: $e');
// 不抛出异常返回空列表UI会显示"未检测到GPU"
return [];
}
}
/// 读取版本号(从根目录 bin/version 文件)
Future<String> getVersion() async {
try {
final versionPath = PathUtils.binFile('version');
final file = File(versionPath);
if (await file.exists()) {
final content = await file.readAsString();
return content.trim();
} else {
_logger.warning('版本文件不存在: $versionPath');
}
} catch (e) {
_logger.warning('读取版本号失败: $e');
}
return '未知版本';
}
/// 读取身份信息(从根目录 bin/auth 文件)
Future<String> getAuth() async {
try {
final authPath = PathUtils.binFile('auth');
final file = File(authPath);
if (await file.exists()) {
final content = await file.readAsString();
return content.trim();
} else {
_logger.warning('身份文件不存在: $authPath');
}
} catch (e) {
_logger.warning('读取身份信息失败: $e');
}
return '未配置';
}
/// 检查管理员权限Windows
Future<bool> checkAdminPermission() async {
if (!Platform.isWindows) {
return true;
}
try {
// 由于 Process.run 会导致崩溃,这里使用环境变量判断
// 如果存在管理员相关的环境变量,可能具有管理员权限
// 这是一个简化的判断,可能不准确,但不会崩溃
final userProfile = Platform.environment['USERPROFILE'];
if (userProfile != null && userProfile.contains('Administrator')) {
return true;
}
// 默认返回 false表示可能没有管理员权限
_logger.info('无法准确检测管理员权限(避免 Process.run 崩溃),返回 false');
return false;
} catch (e) {
_logger.warning('检查管理员权限失败: $e');
return false;
}
}
}