diff --git a/lib/common/conf/binary_conf.dart b/lib/common/conf/binary_conf.dart index 56c7fd3..96025ed 100644 --- a/lib/common/conf/binary_conf.dart +++ b/lib/common/conf/binary_conf.dart @@ -10,9 +10,10 @@ class BinaryModuleConf { "aria2c": "0", }; - static Future extractModel() async { + static Future extractModule(List modules) async { final workingDir = "${AppConf.applicationSupportDir}\\modules"; for (var m in _modules.entries) { + if (!modules.contains(m.key)) continue; final name = m.key; final version = m.value; final dir = "$workingDir\\$name"; diff --git a/lib/common/io/aria2c.dart b/lib/common/io/aria2c.dart index 259b8f5..874e011 100644 --- a/lib/common/io/aria2c.dart +++ b/lib/common/io/aria2c.dart @@ -5,36 +5,46 @@ import 'package:aria2/aria2.dart'; import 'package:flutter/foundation.dart'; import 'package:starcitizen_doctor/base/ui.dart'; import 'package:starcitizen_doctor/common/conf/app_conf.dart'; +import 'package:starcitizen_doctor/common/conf/binary_conf.dart'; import 'package:starcitizen_doctor/common/helper/system_helper.dart'; class Aria2cManager { - static bool _isDaemonRunning = false; + static int? _daemonPID; static final String _aria2cDir = "${AppConf.applicationSupportDir}\\modules\\aria2c"; static Aria2c? _aria2c; - static Aria2c get aria2c { - if (!_isDaemonRunning) throw Exception("Aria2c Daemon not running!"); - if (_aria2c == null) { - _aria2c = Aria2c( - "ws://127.0.0.1:64664/jsonrpc", "websocket", "ScToolbox_64664"); - _aria2c!.getVersion().then((value) { - dPrint("Aria2cManager.connected! version == ${value.version}"); - }); + static Aria2c getClient() { + if (_aria2c != null) return _aria2c!; + throw "not connect!"; + } + + static bool get isAvailable => _daemonPID != null && _aria2c != null; + + static Future checkLazyLoad() async { + try { + final sessionFile = File("$_aria2cDir\\aria2.session"); + // 有下载任务则第一时间初始化 + if (await sessionFile.exists() && + (await sessionFile.readAsString()).trim().isNotEmpty) { + await launchDaemon(); + } + } catch (e) { + dPrint("Aria2cManager.checkLazyLoad Error:$e"); } - return _aria2c!; } static Future launchDaemon() async { - if (_isDaemonRunning) return; + if (_daemonPID != null) return; + await BinaryModuleConf.extractModule(["aria2c"]); /// skip for debug hot reload if (kDebugMode) { if ((await SystemHelper.getPID("aria2c")).isNotEmpty) { dPrint("[Aria2cManager] debug skip for hot reload"); - _isDaemonRunning = true; + _daemonPID = 0; return; } } @@ -69,21 +79,26 @@ class Aria2cManager { if (event.trim().isEmpty) return; dPrint("[aria2c]: ${event.trim()}"); if (event.contains("IPv4 RPC: listening on TCP port")) { - _isDaemonRunning = true; - aria2c; + _daemonPID = p.pid; + _aria2c = Aria2c( + "ws://127.0.0.1:64664/jsonrpc", "websocket", "ScToolbox_64664"); + _aria2c!.getVersion().then((value) { + dPrint("Aria2cManager.connected! version == ${value.version}"); + }); } }, onDone: () { dPrint("[aria2c] onDone: "); - _isDaemonRunning = false; + _daemonPID = null; }, onError: (e) { dPrint("[aria2c] stdout ERROR: $e"); - _isDaemonRunning = false; + _daemonPID = null; }); + p.pid; p.stderr.transform(utf8.decoder).listen((event) { dPrint("[aria2c] stderr ERROR : $event"); }); while (true) { - if (_isDaemonRunning) return; + if (_daemonPID != null) return; await Future.delayed(const Duration(milliseconds: 100)); } } diff --git a/lib/ui/home/downloads/downloads_ui_model.dart b/lib/ui/home/downloads/downloads_ui_model.dart index 9481af8..388d9d0 100644 --- a/lib/ui/home/downloads/downloads_ui_model.dart +++ b/lib/ui/home/downloads/downloads_ui_model.dart @@ -37,18 +37,22 @@ class DownloadsUIModel extends BaseUIModel { onTapButton(String key) async { switch (key) { case "pause_all": - await Aria2cManager.aria2c.pauseAll(); + if (!Aria2cManager.isAvailable) return; + await Aria2cManager.getClient().pauseAll(); return; case "resume_all": - await Aria2cManager.aria2c.unpauseAll(); + if (!Aria2cManager.isAvailable) return; + + await Aria2cManager.getClient().unpauseAll(); return; case "cancel_all": final userOK = await showConfirmDialogs( context!, "确认取消全部任务?", const Text("如果文件不再需要,你可能需要手动删除下载文件。")); if (userOK == true) { + if (!Aria2cManager.isAvailable) return; try { for (var value in [...tasks, ...waitingTasks]) { - await Aria2cManager.aria2c.remove(value.gid!); + await Aria2cManager.getClient().remove(value.gid!); } } catch (e) { dPrint("DownloadsUIModel cancel_all Error: $e"); @@ -65,12 +69,15 @@ class DownloadsUIModel extends BaseUIModel { try { while (true) { if (!mounted) return; - tasks.clear(); - tasks = await Aria2cManager.aria2c.tellActive(); - waitingTasks = await Aria2cManager.aria2c.tellWaiting(0, 1000000); - stoppedTasks = await Aria2cManager.aria2c.tellStopped(0, 1000000); - globalStat = await Aria2cManager.aria2c.getGlobalStat(); - notifyListeners(); + if (Aria2cManager.isAvailable) { + final aria2c = Aria2cManager.getClient(); + tasks.clear(); + tasks = await aria2c.tellActive(); + waitingTasks = await aria2c.tellWaiting(0, 1000000); + stoppedTasks = await aria2c.tellStopped(0, 1000000); + globalStat = await aria2c.getGlobalStat(); + notifyListeners(); + } await Future.delayed(const Duration(seconds: 1)); } } catch (e) { @@ -136,14 +143,17 @@ class DownloadsUIModel extends BaseUIModel { } Future resumeTask(String? gid) async { + final aria2c = Aria2cManager.getClient(); if (gid != null) { - await Aria2cManager.aria2c.unpause(gid); + await aria2c.unpause(gid); } } Future pauseTask(String? gid) async { + final aria2c = Aria2cManager.getClient(); + if (gid != null) { - await Aria2cManager.aria2c.pause(gid); + await aria2c.pause(gid); } } @@ -153,7 +163,8 @@ class DownloadsUIModel extends BaseUIModel { final ok = await showConfirmDialogs( context!, "确认取消下载?", const Text("如果文件不再需要,你可能需要手动删除下载文件。")); if (ok == true) { - await Aria2cManager.aria2c.remove(gid); + final aria2c = Aria2cManager.getClient(); + await aria2c.remove(gid); } } } @@ -220,12 +231,13 @@ class DownloadsUIModel extends BaseUIModel { ], )); if (ok == true) { + await handleError(() => Aria2cManager.launchDaemon()); + final aria2c = Aria2cManager.getClient(); final upByte = Aria2cManager.textToByte(upCtrl.text.trim()); final downByte = Aria2cManager.textToByte(downCtrl.text.trim()); - final r = await handleError( - () => Aria2cManager.aria2c.changeGlobalOption(Aria2Option() - ..maxOverallUploadLimit = upByte - ..maxOverallDownloadLimit = downByte)); + final r = await handleError(() => aria2c.changeGlobalOption(Aria2Option() + ..maxOverallUploadLimit = upByte + ..maxOverallDownloadLimit = downByte)); if (r != null) { await box.put('downloader_up_limit', upCtrl.text.trim()); await box.put('downloader_down_limit', downCtrl.text.trim()); diff --git a/lib/ui/index_ui_model.dart b/lib/ui/index_ui_model.dart index 34452b6..8d724f0 100644 --- a/lib/ui/index_ui_model.dart +++ b/lib/ui/index_ui_model.dart @@ -108,13 +108,17 @@ class IndexUIModel extends BaseUIModel { void _listenAria2c() async { while (true) { + if (!mounted) return; try { - aria2globalStat = await Aria2cManager.aria2c.getGlobalStat(); - notifyListeners(); + if (Aria2cManager.isAvailable) { + final aria2c = Aria2cManager.getClient(); + aria2globalStat = await aria2c.getGlobalStat(); + notifyListeners(); + } } catch (e) { dPrint("aria2globalStat update error:$e"); } - await Future.delayed(const Duration(seconds: 10)); + await Future.delayed(const Duration(seconds: 5)); } } } diff --git a/lib/ui/splash_ui_model.dart b/lib/ui/splash_ui_model.dart index 7311f0c..5bc6e6f 100644 --- a/lib/ui/splash_ui_model.dart +++ b/lib/ui/splash_ui_model.dart @@ -1,6 +1,5 @@ import 'package:starcitizen_doctor/api/analytics.dart'; import 'package:starcitizen_doctor/base/ui_model.dart'; -import 'package:starcitizen_doctor/common/conf/binary_conf.dart'; import 'package:starcitizen_doctor/common/conf/url_conf.dart'; import 'package:starcitizen_doctor/common/io/aria2c.dart'; import 'package:starcitizen_doctor/ui/index_ui.dart'; @@ -29,8 +28,7 @@ class SplashUIModel extends BaseUIModel { await AppConf.checkUpdate(); step = 2; notifyListeners(); - await handleError(() => BinaryModuleConf.extractModel()); - await handleError(() => Aria2cManager.launchDaemon()); + await Aria2cManager.checkLazyLoad(); Navigator.pushAndRemoveUntil( context!, BaseUIContainer( diff --git a/lib/ui/tools/tools_ui_model.dart b/lib/ui/tools/tools_ui_model.dart index 04c5cce..2201a44 100644 --- a/lib/ui/tools/tools_ui_model.dart +++ b/lib/ui/tools/tools_ui_model.dart @@ -381,13 +381,17 @@ class ToolsUIModel extends BaseUIModel { return; } + /// 启动模块 + await handleError(() => Aria2cManager.launchDaemon()); + final aria2c = Aria2cManager.getClient(); + try { final b64Str = base64Encode(btData.data!); - final gid = await Aria2cManager.aria2c - .addTorrent(b64Str, extraParams: {"dir": savePath}); + final gid = + await aria2c.addTorrent(b64Str, extraParams: {"dir": savePath}); _working = false; dPrint("Aria2cManager.aria2c.addUri resp === $gid"); - await Aria2cManager.aria2c.saveSession(); + await aria2c.saveSession(); BaseUIContainer( uiCreate: () => DownloadsUI(), modelCreate: () => DownloadsUIModel()).push(context!);