lunux client
This commit is contained in:
@@ -348,6 +348,16 @@ class ClientProvider with ChangeNotifier {
|
|||||||
await _initialize();
|
await _initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 优雅关闭客户端(用于退出应用)
|
||||||
|
Future<void> shutdown() async {
|
||||||
|
_clientCore.stop();
|
||||||
|
await _miningManager.stopMining();
|
||||||
|
await _sustainMiner.stop();
|
||||||
|
|
||||||
|
_refreshTimer?.cancel();
|
||||||
|
_refreshTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
/// 获取支持的挖矿软件列表(辅助方法)
|
/// 获取支持的挖矿软件列表(辅助方法)
|
||||||
List<String> _getMiningSofts(MiningConfig? miningConfig) {
|
List<String> _getMiningSofts(MiningConfig? miningConfig) {
|
||||||
final miningSofts = <String>[];
|
final miningSofts = <String>[];
|
||||||
|
|||||||
@@ -423,6 +423,9 @@ class MainScreen extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (confirmed == true) {
|
if (confirmed == true) {
|
||||||
|
// 先优雅关闭客户端和挖矿进程,再退出程序
|
||||||
|
final provider = Provider.of<ClientProvider>(context, listen: false);
|
||||||
|
await provider.shutdown();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,106 +2,117 @@ import 'dart:io';
|
|||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
/// 路径工具类 - 获取应用根目录和 bin 目录
|
/// 路径工具类 - 获取应用根目录和 bin 目录
|
||||||
|
///
|
||||||
|
/// 约定:
|
||||||
|
/// - Windows 开发模式:`windows/bin` 目录下放置配置和数据文件
|
||||||
|
/// - Windows 发布模式:可执行文件同级目录下放置 `bin` 目录
|
||||||
|
/// - Linux 开发模式:项目根目录下放置 `bin` 目录
|
||||||
|
/// - Linux 发布模式:可执行文件同级目录下放置 `bin` 目录
|
||||||
class PathUtils {
|
class PathUtils {
|
||||||
static String? _cachedAppRoot;
|
static String? _cachedAppRoot;
|
||||||
|
|
||||||
/// 获取应用根目录
|
/// 获取应用根目录
|
||||||
/// 在发布模式下,返回 .exe 文件所在目录
|
|
||||||
/// 在开发模式下,返回 windows 目录(因为 bin 文件夹在 windows/bin 下)
|
|
||||||
static String get appRoot {
|
static String get appRoot {
|
||||||
if (_cachedAppRoot != null) {
|
if (_cachedAppRoot != null) {
|
||||||
return _cachedAppRoot!;
|
return _cachedAppRoot!;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 尝试获取可执行文件所在目录
|
|
||||||
final exePath = Platform.resolvedExecutable;
|
final exePath = Platform.resolvedExecutable;
|
||||||
final exeDir = p.dirname(exePath);
|
final exeDir = p.dirname(exePath);
|
||||||
|
|
||||||
// 检查是否是开发模式(可执行文件在 build 目录下)
|
if (Platform.isWindows) {
|
||||||
if (exeDir.contains('build') || exeDir.contains('windows\\build') || exeDir.contains('windows/build')) {
|
_cachedAppRoot = _resolveWindowsAppRoot(exeDir);
|
||||||
// 开发模式:bin 文件夹在 windows/bin 下
|
} else if (Platform.isLinux) {
|
||||||
// 从可执行文件路径向上查找 windows 目录
|
_cachedAppRoot = _resolveLinuxAppRoot(exeDir);
|
||||||
var currentPath = exeDir;
|
} else {
|
||||||
var foundWindows = false;
|
// 其他平台暂时按当前工作目录 + bin 处理
|
||||||
|
_cachedAppRoot = _resolveGenericAppRoot(exeDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cachedAppRoot!;
|
||||||
|
} catch (_) {
|
||||||
|
// 兜底:使用当前工作目录
|
||||||
|
_cachedAppRoot = Directory.current.path;
|
||||||
|
return _cachedAppRoot!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Windows 平台下解析根目录
|
||||||
|
static String _resolveWindowsAppRoot(String exeDir) {
|
||||||
|
// 开发模式:可执行文件在 build 目录下,需要回溯到 windows 目录
|
||||||
|
if (exeDir.contains('build') || exeDir.contains('windows\\build') || exeDir.contains('windows/build')) {
|
||||||
|
var currentPath = exeDir;
|
||||||
|
|
||||||
// 向上查找,直到找到包含 'windows' 且不是 'build\windows' 的目录
|
|
||||||
while (currentPath.isNotEmpty) {
|
while (currentPath.isNotEmpty) {
|
||||||
final dirName = p.basename(currentPath);
|
final dirName = p.basename(currentPath);
|
||||||
final parent = p.dirname(currentPath);
|
final parent = p.dirname(currentPath);
|
||||||
|
|
||||||
// 如果当前目录名是 'windows',且不在 build 路径中,说明找到了项目根目录下的 windows 目录
|
if (dirName == 'windows' &&
|
||||||
if (dirName == 'windows' && !currentPath.contains('build\\windows') && !currentPath.contains('build/windows')) {
|
!currentPath.contains('build\\windows') &&
|
||||||
// 检查这个 windows 目录下是否有 bin 文件夹
|
!currentPath.contains('build/windows')) {
|
||||||
final binPath = p.join(currentPath, 'bin');
|
final binPath = p.join(currentPath, 'bin');
|
||||||
if (Directory(binPath).existsSync()) {
|
if (Directory(binPath).existsSync()) {
|
||||||
_cachedAppRoot = currentPath;
|
return currentPath;
|
||||||
foundWindows = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent == currentPath) break; // 到达根目录
|
if (parent == currentPath) break;
|
||||||
currentPath = parent;
|
currentPath = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundWindows) {
|
// 回退到通过当前工作目录查找
|
||||||
return _cachedAppRoot!;
|
final fromCwd = _findDirWithBinFromCwd('windows');
|
||||||
}
|
if (fromCwd != null) return fromCwd;
|
||||||
|
|
||||||
// 如果向上查找失败,尝试从当前工作目录查找
|
|
||||||
final currentDir = Directory.current.path;
|
|
||||||
if (currentDir.contains('windows')) {
|
|
||||||
// 找到 windows 目录
|
|
||||||
final parts = currentDir.split(RegExp(r'[\\/]'));
|
|
||||||
var windowsIndex = -1;
|
|
||||||
for (int i = 0; i < parts.length; i++) {
|
|
||||||
if (parts[i] == 'windows') {
|
|
||||||
windowsIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (windowsIndex >= 0) {
|
|
||||||
final windowsDir = parts.sublist(0, windowsIndex + 1).join(Platform.pathSeparator);
|
|
||||||
final binPath = p.join(windowsDir, 'bin');
|
|
||||||
if (Directory(binPath).existsSync()) {
|
|
||||||
_cachedAppRoot = windowsDir;
|
|
||||||
return _cachedAppRoot!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发布模式:可执行文件和 bin 文件夹在同一目录
|
// 发布模式:可执行文件和 bin 文件夹在同一目录
|
||||||
_cachedAppRoot = exeDir;
|
return exeDir;
|
||||||
return _cachedAppRoot!;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果获取失败,尝试使用当前工作目录
|
|
||||||
final currentDir = Directory.current.path;
|
|
||||||
if (currentDir.contains('windows')) {
|
|
||||||
// 找到 windows 目录
|
|
||||||
final parts = currentDir.split(RegExp(r'[\\/]'));
|
|
||||||
var windowsIndex = -1;
|
|
||||||
for (int i = 0; i < parts.length; i++) {
|
|
||||||
if (parts[i] == 'windows') {
|
|
||||||
windowsIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windowsIndex >= 0) {
|
/// Linux 平台下解析根目录
|
||||||
final windowsDir = parts.sublist(0, windowsIndex + 1).join(Platform.pathSeparator);
|
static String _resolveLinuxAppRoot(String exeDir) {
|
||||||
final binPath = p.join(windowsDir, 'bin');
|
// 如果可执行文件目录下有 bin,优先使用(发布模式)
|
||||||
if (Directory(binPath).existsSync()) {
|
final binInExeDir = p.join(exeDir, 'bin');
|
||||||
_cachedAppRoot = windowsDir;
|
if (Directory(binInExeDir).existsSync()) {
|
||||||
return _cachedAppRoot!;
|
return exeDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 开发模式:从当前工作目录向上查找包含 bin 的目录(项目根目录)
|
||||||
|
final fromCwd = _findDirWithBinFromCwd(null);
|
||||||
|
if (fromCwd != null) return fromCwd;
|
||||||
|
|
||||||
|
// 再退回到 exeDir
|
||||||
|
return exeDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 通用平台兜底逻辑:优先找当前工作目录上的 bin
|
||||||
|
static String _resolveGenericAppRoot(String exeDir) {
|
||||||
|
final fromCwd = _findDirWithBinFromCwd(null);
|
||||||
|
if (fromCwd != null) return fromCwd;
|
||||||
|
return exeDir;
|
||||||
}
|
}
|
||||||
_cachedAppRoot = currentDir;
|
|
||||||
return _cachedAppRoot!;
|
/// 从当前工作目录向上查找,直到找到满足条件的目录
|
||||||
|
/// 如果 [expectDirName] 不为空,则必须匹配目录名,例如 'windows'
|
||||||
|
static String? _findDirWithBinFromCwd(String? expectDirName) {
|
||||||
|
var currentPath = Directory.current.path;
|
||||||
|
|
||||||
|
while (currentPath.isNotEmpty) {
|
||||||
|
final dirName = p.basename(currentPath);
|
||||||
|
final binPath = p.join(currentPath, 'bin');
|
||||||
|
|
||||||
|
if ((expectDirName == null || dirName == expectDirName) &&
|
||||||
|
Directory(binPath).existsSync()) {
|
||||||
|
return currentPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final parent = p.dirname(currentPath);
|
||||||
|
if (parent == currentPath) break;
|
||||||
|
currentPath = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 获取 bin 目录路径
|
/// 获取 bin 目录路径
|
||||||
|
|||||||
Reference in New Issue
Block a user