mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-01-13 19:50:28 +00:00
feat: use rust rqbit to replace aria2c
This commit is contained in:
parent
c5de9e2252
commit
4315e36cbe
@ -82,7 +82,7 @@ final class AppGlobalModelProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$appGlobalModelHash() => r'9729c3ffb891e5899abbb3dc7d2d25ef13a442e7';
|
String _$appGlobalModelHash() => r'0e46d72594d94e2beb4d2ccb8616eb37facba288';
|
||||||
|
|
||||||
abstract class _$AppGlobalModel extends $Notifier<AppGlobalState> {
|
abstract class _$AppGlobalModel extends $Notifier<AppGlobalState> {
|
||||||
AppGlobalState build();
|
AppGlobalState build();
|
||||||
|
|||||||
@ -6,7 +6,8 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||||
|
|
||||||
class BinaryModuleConf {
|
class BinaryModuleConf {
|
||||||
static const _modules = {"aria2c": "0"};
|
// aria2c has been replaced by rqbit (Rust-based torrent library)
|
||||||
|
static const _modules = <String, String>{};
|
||||||
|
|
||||||
static Future extractModule(List<String> modules, String workingDir) async {
|
static Future extractModule(List<String> modules, String workingDir) async {
|
||||||
for (var m in _modules.entries) {
|
for (var m in _modules.entries) {
|
||||||
|
|||||||
198
lib/common/rust/api/downloader_api.dart
Normal file
198
lib/common/rust/api/downloader_api.dart
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
// This file is automatically generated, so please do not edit it.
|
||||||
|
// @generated by `flutter_rust_bridge`@ 2.11.1.
|
||||||
|
|
||||||
|
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
|
||||||
|
|
||||||
|
import '../frb_generated.dart';
|
||||||
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||||
|
|
||||||
|
// These functions are ignored because they are not marked as `pub`: `get_task_status`
|
||||||
|
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `clone`, `fmt`, `fmt`, `fmt`
|
||||||
|
|
||||||
|
/// Initialize the download manager session
|
||||||
|
void downloaderInit({required String downloadDir}) => RustLib.instance.api
|
||||||
|
.crateApiDownloaderApiDownloaderInit(downloadDir: downloadDir);
|
||||||
|
|
||||||
|
/// Check if the downloader is initialized
|
||||||
|
bool downloaderIsInitialized() =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderIsInitialized();
|
||||||
|
|
||||||
|
/// Add a torrent from bytes (e.g., .torrent file content)
|
||||||
|
Future<BigInt> downloaderAddTorrent({
|
||||||
|
required List<int> torrentBytes,
|
||||||
|
String? outputFolder,
|
||||||
|
List<String>? trackers,
|
||||||
|
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderAddTorrent(
|
||||||
|
torrentBytes: torrentBytes,
|
||||||
|
outputFolder: outputFolder,
|
||||||
|
trackers: trackers,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Add a torrent from a magnet link
|
||||||
|
Future<BigInt> downloaderAddMagnet({
|
||||||
|
required String magnetLink,
|
||||||
|
String? outputFolder,
|
||||||
|
List<String>? trackers,
|
||||||
|
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderAddMagnet(
|
||||||
|
magnetLink: magnetLink,
|
||||||
|
outputFolder: outputFolder,
|
||||||
|
trackers: trackers,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Add a torrent from URL (HTTP download not supported, only torrent file URLs)
|
||||||
|
Future<BigInt> downloaderAddUrl({
|
||||||
|
required String url,
|
||||||
|
String? outputFolder,
|
||||||
|
List<String>? trackers,
|
||||||
|
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderAddUrl(
|
||||||
|
url: url,
|
||||||
|
outputFolder: outputFolder,
|
||||||
|
trackers: trackers,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Pause a download task
|
||||||
|
Future<void> downloaderPause({required BigInt taskId}) =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderPause(taskId: taskId);
|
||||||
|
|
||||||
|
/// Resume a download task
|
||||||
|
Future<void> downloaderResume({required BigInt taskId}) =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderResume(taskId: taskId);
|
||||||
|
|
||||||
|
/// Remove a download task
|
||||||
|
Future<void> downloaderRemove({
|
||||||
|
required BigInt taskId,
|
||||||
|
required bool deleteFiles,
|
||||||
|
}) => RustLib.instance.api.crateApiDownloaderApiDownloaderRemove(
|
||||||
|
taskId: taskId,
|
||||||
|
deleteFiles: deleteFiles,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Get information about a specific task
|
||||||
|
Future<DownloadTaskInfo> downloaderGetTaskInfo({required BigInt taskId}) =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderGetTaskInfo(
|
||||||
|
taskId: taskId,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Get all tasks
|
||||||
|
Future<List<DownloadTaskInfo>> downloaderGetAllTasks() =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderGetAllTasks();
|
||||||
|
|
||||||
|
/// Get global statistics
|
||||||
|
Future<DownloadGlobalStat> downloaderGetGlobalStats() =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderGetGlobalStats();
|
||||||
|
|
||||||
|
/// Check if a task with given name exists
|
||||||
|
Future<bool> downloaderIsNameInTask({required String name}) => RustLib
|
||||||
|
.instance
|
||||||
|
.api
|
||||||
|
.crateApiDownloaderApiDownloaderIsNameInTask(name: name);
|
||||||
|
|
||||||
|
/// Pause all tasks
|
||||||
|
Future<void> downloaderPauseAll() =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderPauseAll();
|
||||||
|
|
||||||
|
/// Resume all tasks
|
||||||
|
Future<void> downloaderResumeAll() =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderResumeAll();
|
||||||
|
|
||||||
|
/// Stop the downloader session
|
||||||
|
Future<void> downloaderStop() =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderStop();
|
||||||
|
|
||||||
|
/// Global statistics
|
||||||
|
class DownloadGlobalStat {
|
||||||
|
final BigInt downloadSpeed;
|
||||||
|
final BigInt uploadSpeed;
|
||||||
|
final BigInt numActive;
|
||||||
|
final BigInt numWaiting;
|
||||||
|
|
||||||
|
const DownloadGlobalStat({
|
||||||
|
required this.downloadSpeed,
|
||||||
|
required this.uploadSpeed,
|
||||||
|
required this.numActive,
|
||||||
|
required this.numWaiting,
|
||||||
|
});
|
||||||
|
|
||||||
|
static Future<DownloadGlobalStat> default_() =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloadGlobalStatDefault();
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
downloadSpeed.hashCode ^
|
||||||
|
uploadSpeed.hashCode ^
|
||||||
|
numActive.hashCode ^
|
||||||
|
numWaiting.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is DownloadGlobalStat &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
downloadSpeed == other.downloadSpeed &&
|
||||||
|
uploadSpeed == other.uploadSpeed &&
|
||||||
|
numActive == other.numActive &&
|
||||||
|
numWaiting == other.numWaiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Download task information
|
||||||
|
class DownloadTaskInfo {
|
||||||
|
final BigInt id;
|
||||||
|
final String name;
|
||||||
|
final DownloadTaskStatus status;
|
||||||
|
final BigInt totalBytes;
|
||||||
|
final BigInt downloadedBytes;
|
||||||
|
final BigInt uploadedBytes;
|
||||||
|
final BigInt downloadSpeed;
|
||||||
|
final BigInt uploadSpeed;
|
||||||
|
final double progress;
|
||||||
|
final BigInt numPeers;
|
||||||
|
final String outputFolder;
|
||||||
|
|
||||||
|
const DownloadTaskInfo({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.status,
|
||||||
|
required this.totalBytes,
|
||||||
|
required this.downloadedBytes,
|
||||||
|
required this.uploadedBytes,
|
||||||
|
required this.downloadSpeed,
|
||||||
|
required this.uploadSpeed,
|
||||||
|
required this.progress,
|
||||||
|
required this.numPeers,
|
||||||
|
required this.outputFolder,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
id.hashCode ^
|
||||||
|
name.hashCode ^
|
||||||
|
status.hashCode ^
|
||||||
|
totalBytes.hashCode ^
|
||||||
|
downloadedBytes.hashCode ^
|
||||||
|
uploadedBytes.hashCode ^
|
||||||
|
downloadSpeed.hashCode ^
|
||||||
|
uploadSpeed.hashCode ^
|
||||||
|
progress.hashCode ^
|
||||||
|
numPeers.hashCode ^
|
||||||
|
outputFolder.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is DownloadTaskInfo &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
id == other.id &&
|
||||||
|
name == other.name &&
|
||||||
|
status == other.status &&
|
||||||
|
totalBytes == other.totalBytes &&
|
||||||
|
downloadedBytes == other.downloadedBytes &&
|
||||||
|
uploadedBytes == other.uploadedBytes &&
|
||||||
|
downloadSpeed == other.downloadSpeed &&
|
||||||
|
uploadSpeed == other.uploadSpeed &&
|
||||||
|
progress == other.progress &&
|
||||||
|
numPeers == other.numPeers &&
|
||||||
|
outputFolder == other.outputFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Download task status
|
||||||
|
enum DownloadTaskStatus { initializing, live, paused, error, finished }
|
||||||
@ -6,7 +6,6 @@
|
|||||||
import '../frb_generated.dart';
|
import '../frb_generated.dart';
|
||||||
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
||||||
|
|
||||||
// These functions are ignored because they are not marked as `pub`: `get_process_path`
|
|
||||||
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `fmt`, `fmt`
|
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `fmt`, `fmt`
|
||||||
|
|
||||||
Future<void> sendNotify({
|
Future<void> sendNotify({
|
||||||
@ -21,27 +20,21 @@ Future<void> sendNotify({
|
|||||||
appId: appId,
|
appId: appId,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Get system memory size in GB
|
|
||||||
Future<BigInt> getSystemMemorySizeGb() =>
|
Future<BigInt> getSystemMemorySizeGb() =>
|
||||||
RustLib.instance.api.crateApiWin32ApiGetSystemMemorySizeGb();
|
RustLib.instance.api.crateApiWin32ApiGetSystemMemorySizeGb();
|
||||||
|
|
||||||
/// Get number of logical processors
|
|
||||||
Future<int> getNumberOfLogicalProcessors() =>
|
Future<int> getNumberOfLogicalProcessors() =>
|
||||||
RustLib.instance.api.crateApiWin32ApiGetNumberOfLogicalProcessors();
|
RustLib.instance.api.crateApiWin32ApiGetNumberOfLogicalProcessors();
|
||||||
|
|
||||||
/// Get all system information at once
|
|
||||||
Future<SystemInfo> getSystemInfo() =>
|
Future<SystemInfo> getSystemInfo() =>
|
||||||
RustLib.instance.api.crateApiWin32ApiGetSystemInfo();
|
RustLib.instance.api.crateApiWin32ApiGetSystemInfo();
|
||||||
|
|
||||||
/// Get GPU info from registry (more accurate VRAM)
|
|
||||||
Future<String> getGpuInfoFromRegistry() =>
|
Future<String> getGpuInfoFromRegistry() =>
|
||||||
RustLib.instance.api.crateApiWin32ApiGetGpuInfoFromRegistry();
|
RustLib.instance.api.crateApiWin32ApiGetGpuInfoFromRegistry();
|
||||||
|
|
||||||
/// Resolve shortcut (.lnk) file to get target path
|
|
||||||
Future<String> resolveShortcut({required String lnkPath}) =>
|
Future<String> resolveShortcut({required String lnkPath}) =>
|
||||||
RustLib.instance.api.crateApiWin32ApiResolveShortcut(lnkPath: lnkPath);
|
RustLib.instance.api.crateApiWin32ApiResolveShortcut(lnkPath: lnkPath);
|
||||||
|
|
||||||
/// Open file explorer and select file/folder
|
|
||||||
Future<void> openDirWithExplorer({
|
Future<void> openDirWithExplorer({
|
||||||
required String path,
|
required String path,
|
||||||
required bool isFile,
|
required bool isFile,
|
||||||
@ -65,19 +58,16 @@ Future<List<ProcessInfo>> getProcessListByName({required String processName}) =>
|
|||||||
processName: processName,
|
processName: processName,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Kill processes by name
|
|
||||||
Future<int> killProcessByName({required String processName}) => RustLib
|
Future<int> killProcessByName({required String processName}) => RustLib
|
||||||
.instance
|
.instance
|
||||||
.api
|
.api
|
||||||
.crateApiWin32ApiKillProcessByName(processName: processName);
|
.crateApiWin32ApiKillProcessByName(processName: processName);
|
||||||
|
|
||||||
/// Get disk physical sector size for performance
|
|
||||||
Future<int> getDiskPhysicalSectorSize({required String driveLetter}) => RustLib
|
Future<int> getDiskPhysicalSectorSize({required String driveLetter}) => RustLib
|
||||||
.instance
|
.instance
|
||||||
.api
|
.api
|
||||||
.crateApiWin32ApiGetDiskPhysicalSectorSize(driveLetter: driveLetter);
|
.crateApiWin32ApiGetDiskPhysicalSectorSize(driveLetter: driveLetter);
|
||||||
|
|
||||||
/// Create a desktop shortcut
|
|
||||||
Future<void> createDesktopShortcut({
|
Future<void> createDesktopShortcut({
|
||||||
required String targetPath,
|
required String targetPath,
|
||||||
required String shortcutName,
|
required String shortcutName,
|
||||||
@ -86,14 +76,12 @@ Future<void> createDesktopShortcut({
|
|||||||
shortcutName: shortcutName,
|
shortcutName: shortcutName,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Run a program with admin privileges (UAC)
|
|
||||||
Future<void> runAsAdmin({required String program, required String args}) =>
|
Future<void> runAsAdmin({required String program, required String args}) =>
|
||||||
RustLib.instance.api.crateApiWin32ApiRunAsAdmin(
|
RustLib.instance.api.crateApiWin32ApiRunAsAdmin(
|
||||||
program: program,
|
program: program,
|
||||||
args: args,
|
args: args,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Start a program (without waiting)
|
|
||||||
Future<void> startProcess({
|
Future<void> startProcess({
|
||||||
required String program,
|
required String program,
|
||||||
required List<String> args,
|
required List<String> args,
|
||||||
@ -102,15 +90,12 @@ Future<void> startProcess({
|
|||||||
args: args,
|
args: args,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Check if NVME patch is applied
|
|
||||||
Future<bool> checkNvmePatchStatus() =>
|
Future<bool> checkNvmePatchStatus() =>
|
||||||
RustLib.instance.api.crateApiWin32ApiCheckNvmePatchStatus();
|
RustLib.instance.api.crateApiWin32ApiCheckNvmePatchStatus();
|
||||||
|
|
||||||
/// Add NVME patch to registry
|
|
||||||
Future<void> addNvmePatch() =>
|
Future<void> addNvmePatch() =>
|
||||||
RustLib.instance.api.crateApiWin32ApiAddNvmePatch();
|
RustLib.instance.api.crateApiWin32ApiAddNvmePatch();
|
||||||
|
|
||||||
/// Remove NVME patch from registry
|
|
||||||
Future<void> removeNvmePatch() =>
|
Future<void> removeNvmePatch() =>
|
||||||
RustLib.instance.api.crateApiWin32ApiRemoveNvmePatch();
|
RustLib.instance.api.crateApiWin32ApiRemoveNvmePatch();
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
||||||
|
|
||||||
import 'api/asar_api.dart';
|
import 'api/asar_api.dart';
|
||||||
|
import 'api/downloader_api.dart';
|
||||||
import 'api/http_api.dart';
|
import 'api/http_api.dart';
|
||||||
import 'api/ort_api.dart';
|
import 'api/ort_api.dart';
|
||||||
import 'api/rs_process.dart';
|
import 'api/rs_process.dart';
|
||||||
@ -71,7 +72,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
|||||||
String get codegenVersion => '2.11.1';
|
String get codegenVersion => '2.11.1';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get rustContentHash => 1161621087;
|
int get rustContentHash => -1465039096;
|
||||||
|
|
||||||
static const kDefaultExternalLibraryLoaderConfig =
|
static const kDefaultExternalLibraryLoaderConfig =
|
||||||
ExternalLibraryLoaderConfig(
|
ExternalLibraryLoaderConfig(
|
||||||
@ -97,6 +98,57 @@ abstract class RustLibApi extends BaseApi {
|
|||||||
|
|
||||||
Future<List<String>> crateApiHttpApiDnsLookupTxt({required String host});
|
Future<List<String>> crateApiHttpApiDnsLookupTxt({required String host});
|
||||||
|
|
||||||
|
Future<DownloadGlobalStat> crateApiDownloaderApiDownloadGlobalStatDefault();
|
||||||
|
|
||||||
|
Future<BigInt> crateApiDownloaderApiDownloaderAddMagnet({
|
||||||
|
required String magnetLink,
|
||||||
|
String? outputFolder,
|
||||||
|
List<String>? trackers,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<BigInt> crateApiDownloaderApiDownloaderAddTorrent({
|
||||||
|
required List<int> torrentBytes,
|
||||||
|
String? outputFolder,
|
||||||
|
List<String>? trackers,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<BigInt> crateApiDownloaderApiDownloaderAddUrl({
|
||||||
|
required String url,
|
||||||
|
String? outputFolder,
|
||||||
|
List<String>? trackers,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<DownloadTaskInfo>> crateApiDownloaderApiDownloaderGetAllTasks();
|
||||||
|
|
||||||
|
Future<DownloadGlobalStat> crateApiDownloaderApiDownloaderGetGlobalStats();
|
||||||
|
|
||||||
|
Future<DownloadTaskInfo> crateApiDownloaderApiDownloaderGetTaskInfo({
|
||||||
|
required BigInt taskId,
|
||||||
|
});
|
||||||
|
|
||||||
|
void crateApiDownloaderApiDownloaderInit({required String downloadDir});
|
||||||
|
|
||||||
|
bool crateApiDownloaderApiDownloaderIsInitialized();
|
||||||
|
|
||||||
|
Future<bool> crateApiDownloaderApiDownloaderIsNameInTask({
|
||||||
|
required String name,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderPause({required BigInt taskId});
|
||||||
|
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderPauseAll();
|
||||||
|
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderRemove({
|
||||||
|
required BigInt taskId,
|
||||||
|
required bool deleteFiles,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderResume({required BigInt taskId});
|
||||||
|
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderResumeAll();
|
||||||
|
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderStop();
|
||||||
|
|
||||||
Future<RustHttpResponse> crateApiHttpApiFetch({
|
Future<RustHttpResponse> crateApiHttpApiFetch({
|
||||||
required MyMethod method,
|
required MyMethod method,
|
||||||
required String url,
|
required String url,
|
||||||
@ -430,6 +482,451 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
TaskConstMeta get kCrateApiHttpApiDnsLookupTxtConstMeta =>
|
TaskConstMeta get kCrateApiHttpApiDnsLookupTxtConstMeta =>
|
||||||
const TaskConstMeta(debugName: "dns_lookup_txt", argNames: ["host"]);
|
const TaskConstMeta(debugName: "dns_lookup_txt", argNames: ["host"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DownloadGlobalStat> crateApiDownloaderApiDownloadGlobalStatDefault() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__downloader_api__download_global_stat_default(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_download_global_stat,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloadGlobalStatDefaultConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloadGlobalStatDefaultConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "download_global_stat_default",
|
||||||
|
argNames: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<BigInt> crateApiDownloaderApiDownloaderAddMagnet({
|
||||||
|
required String magnetLink,
|
||||||
|
String? outputFolder,
|
||||||
|
List<String>? trackers,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 = cst_encode_String(magnetLink);
|
||||||
|
var arg1 = cst_encode_opt_String(outputFolder);
|
||||||
|
var arg2 = cst_encode_opt_list_String(trackers);
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_add_magnet(
|
||||||
|
port_,
|
||||||
|
arg0,
|
||||||
|
arg1,
|
||||||
|
arg2,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_usize,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderAddMagnetConstMeta,
|
||||||
|
argValues: [magnetLink, outputFolder, trackers],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderAddMagnetConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_add_magnet",
|
||||||
|
argNames: ["magnetLink", "outputFolder", "trackers"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<BigInt> crateApiDownloaderApiDownloaderAddTorrent({
|
||||||
|
required List<int> torrentBytes,
|
||||||
|
String? outputFolder,
|
||||||
|
List<String>? trackers,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 = cst_encode_list_prim_u_8_loose(torrentBytes);
|
||||||
|
var arg1 = cst_encode_opt_String(outputFolder);
|
||||||
|
var arg2 = cst_encode_opt_list_String(trackers);
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_add_torrent(
|
||||||
|
port_,
|
||||||
|
arg0,
|
||||||
|
arg1,
|
||||||
|
arg2,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_usize,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderAddTorrentConstMeta,
|
||||||
|
argValues: [torrentBytes, outputFolder, trackers],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderAddTorrentConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_add_torrent",
|
||||||
|
argNames: ["torrentBytes", "outputFolder", "trackers"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<BigInt> crateApiDownloaderApiDownloaderAddUrl({
|
||||||
|
required String url,
|
||||||
|
String? outputFolder,
|
||||||
|
List<String>? trackers,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 = cst_encode_String(url);
|
||||||
|
var arg1 = cst_encode_opt_String(outputFolder);
|
||||||
|
var arg2 = cst_encode_opt_list_String(trackers);
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_add_url(
|
||||||
|
port_,
|
||||||
|
arg0,
|
||||||
|
arg1,
|
||||||
|
arg2,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_usize,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderAddUrlConstMeta,
|
||||||
|
argValues: [url, outputFolder, trackers],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderAddUrlConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_add_url",
|
||||||
|
argNames: ["url", "outputFolder", "trackers"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<DownloadTaskInfo>> crateApiDownloaderApiDownloaderGetAllTasks() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__downloader_api__downloader_get_all_tasks(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_list_download_task_info,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderGetAllTasksConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderGetAllTasksConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "downloader_get_all_tasks", argNames: []);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DownloadGlobalStat> crateApiDownloaderApiDownloaderGetGlobalStats() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__downloader_api__downloader_get_global_stats(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_download_global_stat,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderGetGlobalStatsConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderGetGlobalStatsConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_get_global_stats",
|
||||||
|
argNames: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DownloadTaskInfo> crateApiDownloaderApiDownloaderGetTaskInfo({
|
||||||
|
required BigInt taskId,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 = cst_encode_usize(taskId);
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__downloader_api__downloader_get_task_info(
|
||||||
|
port_,
|
||||||
|
arg0,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_download_task_info,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderGetTaskInfoConstMeta,
|
||||||
|
argValues: [taskId],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderGetTaskInfoConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_get_task_info",
|
||||||
|
argNames: ["taskId"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiDownloaderApiDownloaderInit({required String downloadDir}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(downloadDir);
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_init(arg0);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderInitConstMeta,
|
||||||
|
argValues: [downloadDir],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderInitConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_init",
|
||||||
|
argNames: ["downloadDir"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool crateApiDownloaderApiDownloaderIsInitialized() {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__downloader_api__downloader_is_initialized();
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_bool,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderIsInitializedConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderIsInitializedConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "downloader_is_initialized", argNames: []);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> crateApiDownloaderApiDownloaderIsNameInTask({
|
||||||
|
required String name,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 = cst_encode_String(name);
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__downloader_api__downloader_is_name_in_task(
|
||||||
|
port_,
|
||||||
|
arg0,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_bool,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderIsNameInTaskConstMeta,
|
||||||
|
argValues: [name],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderIsNameInTaskConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_is_name_in_task",
|
||||||
|
argNames: ["name"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderPause({required BigInt taskId}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 = cst_encode_usize(taskId);
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_pause(
|
||||||
|
port_,
|
||||||
|
arg0,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderPauseConstMeta,
|
||||||
|
argValues: [taskId],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderPauseConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "downloader_pause", argNames: ["taskId"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderPauseAll() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_pause_all(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderPauseAllConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderPauseAllConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "downloader_pause_all", argNames: []);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderRemove({
|
||||||
|
required BigInt taskId,
|
||||||
|
required bool deleteFiles,
|
||||||
|
}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 = cst_encode_usize(taskId);
|
||||||
|
var arg1 = cst_encode_bool(deleteFiles);
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_remove(
|
||||||
|
port_,
|
||||||
|
arg0,
|
||||||
|
arg1,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderRemoveConstMeta,
|
||||||
|
argValues: [taskId, deleteFiles],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderRemoveConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_remove",
|
||||||
|
argNames: ["taskId", "deleteFiles"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderResume({required BigInt taskId}) {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 = cst_encode_usize(taskId);
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_resume(
|
||||||
|
port_,
|
||||||
|
arg0,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderResumeConstMeta,
|
||||||
|
argValues: [taskId],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderResumeConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "downloader_resume", argNames: ["taskId"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderResumeAll() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_resume_all(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderResumeAllConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderResumeAllConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "downloader_resume_all", argNames: []);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> crateApiDownloaderApiDownloaderStop() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
return wire.wire__crate__api__downloader_api__downloader_stop(port_);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: dco_decode_AnyhowException,
|
||||||
|
),
|
||||||
|
constMeta: kCrateApiDownloaderApiDownloaderStopConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderStopConstMeta =>
|
||||||
|
const TaskConstMeta(debugName: "downloader_stop", argNames: []);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<RustHttpResponse> crateApiHttpApiFetch({
|
Future<RustHttpResponse> crateApiHttpApiFetch({
|
||||||
required MyMethod method,
|
required MyMethod method,
|
||||||
@ -1903,6 +2400,53 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return dco_decode_web_view_configuration(raw);
|
return dco_decode_web_view_configuration(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadGlobalStat dco_decode_download_global_stat(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 4)
|
||||||
|
throw Exception('unexpected arr length: expect 4 but see ${arr.length}');
|
||||||
|
return DownloadGlobalStat(
|
||||||
|
downloadSpeed: dco_decode_u_64(arr[0]),
|
||||||
|
uploadSpeed: dco_decode_u_64(arr[1]),
|
||||||
|
numActive: dco_decode_usize(arr[2]),
|
||||||
|
numWaiting: dco_decode_usize(arr[3]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadTaskInfo dco_decode_download_task_info(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 11)
|
||||||
|
throw Exception('unexpected arr length: expect 11 but see ${arr.length}');
|
||||||
|
return DownloadTaskInfo(
|
||||||
|
id: dco_decode_usize(arr[0]),
|
||||||
|
name: dco_decode_String(arr[1]),
|
||||||
|
status: dco_decode_download_task_status(arr[2]),
|
||||||
|
totalBytes: dco_decode_u_64(arr[3]),
|
||||||
|
downloadedBytes: dco_decode_u_64(arr[4]),
|
||||||
|
uploadedBytes: dco_decode_u_64(arr[5]),
|
||||||
|
downloadSpeed: dco_decode_u_64(arr[6]),
|
||||||
|
uploadSpeed: dco_decode_u_64(arr[7]),
|
||||||
|
progress: dco_decode_f_64(arr[8]),
|
||||||
|
numPeers: dco_decode_usize(arr[9]),
|
||||||
|
outputFolder: dco_decode_String(arr[10]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadTaskStatus dco_decode_download_task_status(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return DownloadTaskStatus.values[raw as int];
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
double dco_decode_f_64(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return raw as double;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int dco_decode_i_32(dynamic raw) {
|
int dco_decode_i_32(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@ -1921,6 +2465,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return (raw as List<dynamic>).map(dco_decode_String).toList();
|
return (raw as List<dynamic>).map(dco_decode_String).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<DownloadTaskInfo> dco_decode_list_download_task_info(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return (raw as List<dynamic>).map(dco_decode_download_task_info).toList();
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<P4kFileItem> dco_decode_list_p_4_k_file_item(dynamic raw) {
|
List<P4kFileItem> dco_decode_list_p_4_k_file_item(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@ -1993,6 +2543,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return raw == null ? null : dco_decode_box_autoadd_u_64(raw);
|
return raw == null ? null : dco_decode_box_autoadd_u_64(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String>? dco_decode_opt_list_String(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return raw == null ? null : dco_decode_list_String(raw);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List? dco_decode_opt_list_prim_u_8_strict(dynamic raw) {
|
Uint8List? dco_decode_opt_list_prim_u_8_strict(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@ -2255,6 +2811,67 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return (sse_decode_web_view_configuration(deserializer));
|
return (sse_decode_web_view_configuration(deserializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadGlobalStat sse_decode_download_global_stat(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var var_downloadSpeed = sse_decode_u_64(deserializer);
|
||||||
|
var var_uploadSpeed = sse_decode_u_64(deserializer);
|
||||||
|
var var_numActive = sse_decode_usize(deserializer);
|
||||||
|
var var_numWaiting = sse_decode_usize(deserializer);
|
||||||
|
return DownloadGlobalStat(
|
||||||
|
downloadSpeed: var_downloadSpeed,
|
||||||
|
uploadSpeed: var_uploadSpeed,
|
||||||
|
numActive: var_numActive,
|
||||||
|
numWaiting: var_numWaiting,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadTaskInfo sse_decode_download_task_info(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var var_id = sse_decode_usize(deserializer);
|
||||||
|
var var_name = sse_decode_String(deserializer);
|
||||||
|
var var_status = sse_decode_download_task_status(deserializer);
|
||||||
|
var var_totalBytes = sse_decode_u_64(deserializer);
|
||||||
|
var var_downloadedBytes = sse_decode_u_64(deserializer);
|
||||||
|
var var_uploadedBytes = sse_decode_u_64(deserializer);
|
||||||
|
var var_downloadSpeed = sse_decode_u_64(deserializer);
|
||||||
|
var var_uploadSpeed = sse_decode_u_64(deserializer);
|
||||||
|
var var_progress = sse_decode_f_64(deserializer);
|
||||||
|
var var_numPeers = sse_decode_usize(deserializer);
|
||||||
|
var var_outputFolder = sse_decode_String(deserializer);
|
||||||
|
return DownloadTaskInfo(
|
||||||
|
id: var_id,
|
||||||
|
name: var_name,
|
||||||
|
status: var_status,
|
||||||
|
totalBytes: var_totalBytes,
|
||||||
|
downloadedBytes: var_downloadedBytes,
|
||||||
|
uploadedBytes: var_uploadedBytes,
|
||||||
|
downloadSpeed: var_downloadSpeed,
|
||||||
|
uploadSpeed: var_uploadSpeed,
|
||||||
|
progress: var_progress,
|
||||||
|
numPeers: var_numPeers,
|
||||||
|
outputFolder: var_outputFolder,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadTaskStatus sse_decode_download_task_status(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var inner = sse_decode_i_32(deserializer);
|
||||||
|
return DownloadTaskStatus.values[inner];
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
double sse_decode_f_64(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return deserializer.buffer.getFloat64();
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int sse_decode_i_32(SseDeserializer deserializer) {
|
int sse_decode_i_32(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@ -2279,6 +2896,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return ans_;
|
return ans_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<DownloadTaskInfo> sse_decode_list_download_task_info(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
||||||
|
var len_ = sse_decode_i_32(deserializer);
|
||||||
|
var ans_ = <DownloadTaskInfo>[];
|
||||||
|
for (var idx_ = 0; idx_ < len_; ++idx_) {
|
||||||
|
ans_.add(sse_decode_download_task_info(deserializer));
|
||||||
|
}
|
||||||
|
return ans_;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<P4kFileItem> sse_decode_list_p_4_k_file_item(
|
List<P4kFileItem> sse_decode_list_p_4_k_file_item(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
@ -2407,6 +3038,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String>? sse_decode_opt_list_String(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
||||||
|
if (sse_decode_bool(deserializer)) {
|
||||||
|
return (sse_decode_list_String(deserializer));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List? sse_decode_opt_list_prim_u_8_strict(SseDeserializer deserializer) {
|
Uint8List? sse_decode_opt_list_prim_u_8_strict(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@ -2640,6 +3282,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int cst_encode_download_task_status(DownloadTaskStatus raw) {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
return cst_encode_i_32(raw.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
double cst_encode_f_64(double raw) {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int cst_encode_i_32(int raw) {
|
int cst_encode_i_32(int raw) {
|
||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
@ -2768,6 +3422,52 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
sse_encode_web_view_configuration(self, serializer);
|
sse_encode_web_view_configuration(self, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_download_global_stat(
|
||||||
|
DownloadGlobalStat self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_u_64(self.downloadSpeed, serializer);
|
||||||
|
sse_encode_u_64(self.uploadSpeed, serializer);
|
||||||
|
sse_encode_usize(self.numActive, serializer);
|
||||||
|
sse_encode_usize(self.numWaiting, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_download_task_info(
|
||||||
|
DownloadTaskInfo self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_usize(self.id, serializer);
|
||||||
|
sse_encode_String(self.name, serializer);
|
||||||
|
sse_encode_download_task_status(self.status, serializer);
|
||||||
|
sse_encode_u_64(self.totalBytes, serializer);
|
||||||
|
sse_encode_u_64(self.downloadedBytes, serializer);
|
||||||
|
sse_encode_u_64(self.uploadedBytes, serializer);
|
||||||
|
sse_encode_u_64(self.downloadSpeed, serializer);
|
||||||
|
sse_encode_u_64(self.uploadSpeed, serializer);
|
||||||
|
sse_encode_f_64(self.progress, serializer);
|
||||||
|
sse_encode_usize(self.numPeers, serializer);
|
||||||
|
sse_encode_String(self.outputFolder, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_download_task_status(
|
||||||
|
DownloadTaskStatus self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_i_32(self.index, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_f_64(double self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
serializer.buffer.putFloat64(self);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_i_32(int self, SseSerializer serializer) {
|
void sse_encode_i_32(int self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@ -2789,6 +3489,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_download_task_info(
|
||||||
|
List<DownloadTaskInfo> self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_i_32(self.length, serializer);
|
||||||
|
for (final item in self) {
|
||||||
|
sse_encode_download_task_info(item, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_list_p_4_k_file_item(
|
void sse_encode_list_p_4_k_file_item(
|
||||||
List<P4kFileItem> self,
|
List<P4kFileItem> self,
|
||||||
@ -2917,6 +3629,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_opt_list_String(
|
||||||
|
List<String>? self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
||||||
|
sse_encode_bool(self != null, serializer);
|
||||||
|
if (self != null) {
|
||||||
|
sse_encode_list_String(self, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_opt_list_prim_u_8_strict(
|
void sse_encode_opt_list_prim_u_8_strict(
|
||||||
Uint8List? self,
|
Uint8List? self,
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
|
||||||
|
|
||||||
import 'api/asar_api.dart';
|
import 'api/asar_api.dart';
|
||||||
|
import 'api/downloader_api.dart';
|
||||||
import 'api/http_api.dart';
|
import 'api/http_api.dart';
|
||||||
import 'api/ort_api.dart';
|
import 'api/ort_api.dart';
|
||||||
import 'api/rs_process.dart';
|
import 'api/rs_process.dart';
|
||||||
@ -57,6 +58,18 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
dynamic raw,
|
dynamic raw,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadGlobalStat dco_decode_download_global_stat(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadTaskInfo dco_decode_download_task_info(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadTaskStatus dco_decode_download_task_status(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
double dco_decode_f_64(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int dco_decode_i_32(dynamic raw);
|
int dco_decode_i_32(dynamic raw);
|
||||||
|
|
||||||
@ -66,6 +79,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
List<String> dco_decode_list_String(dynamic raw);
|
List<String> dco_decode_list_String(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<DownloadTaskInfo> dco_decode_list_download_task_info(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<P4kFileItem> dco_decode_list_p_4_k_file_item(dynamic raw);
|
List<P4kFileItem> dco_decode_list_p_4_k_file_item(dynamic raw);
|
||||||
|
|
||||||
@ -102,6 +118,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
BigInt? dco_decode_opt_box_autoadd_u_64(dynamic raw);
|
BigInt? dco_decode_opt_box_autoadd_u_64(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String>? dco_decode_opt_list_String(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List? dco_decode_opt_list_prim_u_8_strict(dynamic raw);
|
Uint8List? dco_decode_opt_list_prim_u_8_strict(dynamic raw);
|
||||||
|
|
||||||
@ -192,6 +211,22 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadGlobalStat sse_decode_download_global_stat(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadTaskInfo sse_decode_download_task_info(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DownloadTaskStatus sse_decode_download_task_status(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
double sse_decode_f_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int sse_decode_i_32(SseDeserializer deserializer);
|
int sse_decode_i_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
@ -201,6 +236,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
List<String> sse_decode_list_String(SseDeserializer deserializer);
|
List<String> sse_decode_list_String(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<DownloadTaskInfo> sse_decode_list_download_task_info(
|
||||||
|
SseDeserializer deserializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
List<P4kFileItem> sse_decode_list_p_4_k_file_item(
|
List<P4kFileItem> sse_decode_list_p_4_k_file_item(
|
||||||
SseDeserializer deserializer,
|
SseDeserializer deserializer,
|
||||||
@ -245,6 +285,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
BigInt? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer);
|
BigInt? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String>? sse_decode_opt_list_String(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List? sse_decode_opt_list_prim_u_8_strict(SseDeserializer deserializer);
|
Uint8List? sse_decode_opt_list_prim_u_8_strict(SseDeserializer deserializer);
|
||||||
|
|
||||||
@ -396,6 +439,17 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
ffi.Pointer<wire_cst_list_download_task_info>
|
||||||
|
cst_encode_list_download_task_info(List<DownloadTaskInfo> raw) {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
final ans = wire.cst_new_list_download_task_info(raw.length);
|
||||||
|
for (var i = 0; i < raw.length; ++i) {
|
||||||
|
cst_api_fill_to_wire_download_task_info(raw[i], ans.ref.ptr[i]);
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
ffi.Pointer<wire_cst_list_p_4_k_file_item> cst_encode_list_p_4_k_file_item(
|
ffi.Pointer<wire_cst_list_p_4_k_file_item> cst_encode_list_p_4_k_file_item(
|
||||||
List<P4kFileItem> raw,
|
List<P4kFileItem> raw,
|
||||||
@ -490,6 +544,14 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
return raw == null ? ffi.nullptr : cst_encode_box_autoadd_u_64(raw);
|
return raw == null ? ffi.nullptr : cst_encode_box_autoadd_u_64(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
ffi.Pointer<wire_cst_list_String> cst_encode_opt_list_String(
|
||||||
|
List<String>? raw,
|
||||||
|
) {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
return raw == null ? ffi.nullptr : cst_encode_list_String(raw);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
ffi.Pointer<wire_cst_list_prim_u_8_strict>
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>
|
||||||
cst_encode_opt_list_prim_u_8_strict(Uint8List? raw) {
|
cst_encode_opt_list_prim_u_8_strict(Uint8List? raw) {
|
||||||
@ -525,6 +587,35 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
cst_api_fill_to_wire_web_view_configuration(apiObj, wireObj.ref);
|
cst_api_fill_to_wire_web_view_configuration(apiObj, wireObj.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_download_global_stat(
|
||||||
|
DownloadGlobalStat apiObj,
|
||||||
|
wire_cst_download_global_stat wireObj,
|
||||||
|
) {
|
||||||
|
wireObj.download_speed = cst_encode_u_64(apiObj.downloadSpeed);
|
||||||
|
wireObj.upload_speed = cst_encode_u_64(apiObj.uploadSpeed);
|
||||||
|
wireObj.num_active = cst_encode_usize(apiObj.numActive);
|
||||||
|
wireObj.num_waiting = cst_encode_usize(apiObj.numWaiting);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_download_task_info(
|
||||||
|
DownloadTaskInfo apiObj,
|
||||||
|
wire_cst_download_task_info wireObj,
|
||||||
|
) {
|
||||||
|
wireObj.id = cst_encode_usize(apiObj.id);
|
||||||
|
wireObj.name = cst_encode_String(apiObj.name);
|
||||||
|
wireObj.status = cst_encode_download_task_status(apiObj.status);
|
||||||
|
wireObj.total_bytes = cst_encode_u_64(apiObj.totalBytes);
|
||||||
|
wireObj.downloaded_bytes = cst_encode_u_64(apiObj.downloadedBytes);
|
||||||
|
wireObj.uploaded_bytes = cst_encode_u_64(apiObj.uploadedBytes);
|
||||||
|
wireObj.download_speed = cst_encode_u_64(apiObj.downloadSpeed);
|
||||||
|
wireObj.upload_speed = cst_encode_u_64(apiObj.uploadSpeed);
|
||||||
|
wireObj.progress = cst_encode_f_64(apiObj.progress);
|
||||||
|
wireObj.num_peers = cst_encode_usize(apiObj.numPeers);
|
||||||
|
wireObj.output_folder = cst_encode_String(apiObj.outputFolder);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void cst_api_fill_to_wire_p_4_k_file_item(
|
void cst_api_fill_to_wire_p_4_k_file_item(
|
||||||
P4kFileItem apiObj,
|
P4kFileItem apiObj,
|
||||||
@ -675,6 +766,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
bool cst_encode_bool(bool raw);
|
bool cst_encode_bool(bool raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
int cst_encode_download_task_status(DownloadTaskStatus raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
double cst_encode_f_64(double raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
int cst_encode_i_32(int raw);
|
int cst_encode_i_32(int raw);
|
||||||
|
|
||||||
@ -741,6 +838,27 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
SseSerializer serializer,
|
SseSerializer serializer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_download_global_stat(
|
||||||
|
DownloadGlobalStat self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_download_task_info(
|
||||||
|
DownloadTaskInfo self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_download_task_status(
|
||||||
|
DownloadTaskStatus self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_f_64(double self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_i_32(int self, SseSerializer serializer);
|
void sse_encode_i_32(int self, SseSerializer serializer);
|
||||||
|
|
||||||
@ -750,6 +868,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_list_String(List<String> self, SseSerializer serializer);
|
void sse_encode_list_String(List<String> self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_download_task_info(
|
||||||
|
List<DownloadTaskInfo> self,
|
||||||
|
SseSerializer serializer,
|
||||||
|
);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_list_p_4_k_file_item(
|
void sse_encode_list_p_4_k_file_item(
|
||||||
List<P4kFileItem> self,
|
List<P4kFileItem> self,
|
||||||
@ -804,6 +928,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_opt_box_autoadd_u_64(BigInt? self, SseSerializer serializer);
|
void sse_encode_opt_box_autoadd_u_64(BigInt? self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_opt_list_prim_u_8_strict(
|
void sse_encode_opt_list_prim_u_8_strict(
|
||||||
Uint8List? self,
|
Uint8List? self,
|
||||||
@ -1034,6 +1161,334 @@ class RustLibWire implements BaseWire {
|
|||||||
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
|
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
|
||||||
>();
|
>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__download_global_stat_default(
|
||||||
|
int port_,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__download_global_stat_default(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__download_global_stat_defaultPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__download_global_stat_default',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__download_global_stat_default =
|
||||||
|
_wire__crate__api__downloader_api__download_global_stat_defaultPtr
|
||||||
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_add_magnet(
|
||||||
|
int port_,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> magnet_link,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> output_folder,
|
||||||
|
ffi.Pointer<wire_cst_list_String> trackers,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_add_magnet(
|
||||||
|
port_,
|
||||||
|
magnet_link,
|
||||||
|
output_folder,
|
||||||
|
trackers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_add_magnetPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Void Function(
|
||||||
|
ffi.Int64,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_String>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_add_magnet',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_add_magnet =
|
||||||
|
_wire__crate__api__downloader_api__downloader_add_magnetPtr
|
||||||
|
.asFunction<
|
||||||
|
void Function(
|
||||||
|
int,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_String>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_add_torrent(
|
||||||
|
int port_,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_loose> torrent_bytes,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> output_folder,
|
||||||
|
ffi.Pointer<wire_cst_list_String> trackers,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_add_torrent(
|
||||||
|
port_,
|
||||||
|
torrent_bytes,
|
||||||
|
output_folder,
|
||||||
|
trackers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_add_torrentPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Void Function(
|
||||||
|
ffi.Int64,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_loose>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_String>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_add_torrent',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_add_torrent =
|
||||||
|
_wire__crate__api__downloader_api__downloader_add_torrentPtr
|
||||||
|
.asFunction<
|
||||||
|
void Function(
|
||||||
|
int,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_loose>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_String>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_add_url(
|
||||||
|
int port_,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> url,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> output_folder,
|
||||||
|
ffi.Pointer<wire_cst_list_String> trackers,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_add_url(
|
||||||
|
port_,
|
||||||
|
url,
|
||||||
|
output_folder,
|
||||||
|
trackers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_add_urlPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Void Function(
|
||||||
|
ffi.Int64,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_String>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_add_url',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_add_url =
|
||||||
|
_wire__crate__api__downloader_api__downloader_add_urlPtr
|
||||||
|
.asFunction<
|
||||||
|
void Function(
|
||||||
|
int,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
ffi.Pointer<wire_cst_list_String>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_get_all_tasks(int port_) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_get_all_tasks(port_);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_get_all_tasksPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_get_all_tasks',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_get_all_tasks =
|
||||||
|
_wire__crate__api__downloader_api__downloader_get_all_tasksPtr
|
||||||
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_get_global_stats(
|
||||||
|
int port_,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_get_global_stats(
|
||||||
|
port_,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_get_global_statsPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_get_global_stats',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_get_global_stats =
|
||||||
|
_wire__crate__api__downloader_api__downloader_get_global_statsPtr
|
||||||
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_get_task_info(
|
||||||
|
int port_,
|
||||||
|
int task_id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_get_task_info(
|
||||||
|
port_,
|
||||||
|
task_id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_get_task_infoPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64, ffi.UintPtr)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_get_task_info',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_get_task_info =
|
||||||
|
_wire__crate__api__downloader_api__downloader_get_task_infoPtr
|
||||||
|
.asFunction<void Function(int, int)>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco wire__crate__api__downloader_api__downloader_init(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> download_dir,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_init(download_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_initPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_init',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_init =
|
||||||
|
_wire__crate__api__downloader_api__downloader_initPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco
|
||||||
|
wire__crate__api__downloader_api__downloader_is_initialized() {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_is_initialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_is_initializedPtr =
|
||||||
|
_lookup<ffi.NativeFunction<WireSyncRust2DartDco Function()>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_is_initialized',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_is_initialized =
|
||||||
|
_wire__crate__api__downloader_api__downloader_is_initializedPtr
|
||||||
|
.asFunction<WireSyncRust2DartDco Function()>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_is_name_in_task(
|
||||||
|
int port_,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> name,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_is_name_in_task(
|
||||||
|
port_,
|
||||||
|
name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_is_name_in_taskPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Void Function(
|
||||||
|
ffi.Int64,
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_is_name_in_task',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_is_name_in_task =
|
||||||
|
_wire__crate__api__downloader_api__downloader_is_name_in_taskPtr
|
||||||
|
.asFunction<
|
||||||
|
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
|
||||||
|
>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_pause(
|
||||||
|
int port_,
|
||||||
|
int task_id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_pause(port_, task_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_pausePtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64, ffi.UintPtr)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_pause',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_pause =
|
||||||
|
_wire__crate__api__downloader_api__downloader_pausePtr
|
||||||
|
.asFunction<void Function(int, int)>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_pause_all(int port_) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_pause_all(port_);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_pause_allPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_pause_all',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_pause_all =
|
||||||
|
_wire__crate__api__downloader_api__downloader_pause_allPtr
|
||||||
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_remove(
|
||||||
|
int port_,
|
||||||
|
int task_id,
|
||||||
|
bool delete_files,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_remove(
|
||||||
|
port_,
|
||||||
|
task_id,
|
||||||
|
delete_files,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_removePtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<ffi.Void Function(ffi.Int64, ffi.UintPtr, ffi.Bool)>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_remove',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_remove =
|
||||||
|
_wire__crate__api__downloader_api__downloader_removePtr
|
||||||
|
.asFunction<void Function(int, int, bool)>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_resume(
|
||||||
|
int port_,
|
||||||
|
int task_id,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_resume(port_, task_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_resumePtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64, ffi.UintPtr)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_resume',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_resume =
|
||||||
|
_wire__crate__api__downloader_api__downloader_resumePtr
|
||||||
|
.asFunction<void Function(int, int)>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_resume_all(int port_) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_resume_all(port_);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_resume_allPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_resume_all',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_resume_all =
|
||||||
|
_wire__crate__api__downloader_api__downloader_resume_allPtr
|
||||||
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
|
void wire__crate__api__downloader_api__downloader_stop(int port_) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_stop(port_);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_stopPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_stop',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_stop =
|
||||||
|
_wire__crate__api__downloader_api__downloader_stopPtr
|
||||||
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
void wire__crate__api__http_api__fetch(
|
void wire__crate__api__http_api__fetch(
|
||||||
int port_,
|
int port_,
|
||||||
int method,
|
int method,
|
||||||
@ -1506,9 +1961,9 @@ class RustLibWire implements BaseWire {
|
|||||||
|
|
||||||
void wire__crate__api__win32_api__resolve_shortcut(
|
void wire__crate__api__win32_api__resolve_shortcut(
|
||||||
int port_,
|
int port_,
|
||||||
ffi.Pointer<wire_cst_list_prim_u_8_strict> lnk_path,
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> _lnk_path,
|
||||||
) {
|
) {
|
||||||
return _wire__crate__api__win32_api__resolve_shortcut(port_, lnk_path);
|
return _wire__crate__api__win32_api__resolve_shortcut(port_, _lnk_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
late final _wire__crate__api__win32_api__resolve_shortcutPtr =
|
late final _wire__crate__api__win32_api__resolve_shortcutPtr =
|
||||||
@ -2341,6 +2796,24 @@ class RustLibWire implements BaseWire {
|
|||||||
late final _cst_new_list_String = _cst_new_list_StringPtr
|
late final _cst_new_list_String = _cst_new_list_StringPtr
|
||||||
.asFunction<ffi.Pointer<wire_cst_list_String> Function(int)>();
|
.asFunction<ffi.Pointer<wire_cst_list_String> Function(int)>();
|
||||||
|
|
||||||
|
ffi.Pointer<wire_cst_list_download_task_info> cst_new_list_download_task_info(
|
||||||
|
int len,
|
||||||
|
) {
|
||||||
|
return _cst_new_list_download_task_info(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _cst_new_list_download_task_infoPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Pointer<wire_cst_list_download_task_info> Function(ffi.Int32)
|
||||||
|
>
|
||||||
|
>('frbgen_starcitizen_doctor_cst_new_list_download_task_info');
|
||||||
|
late final _cst_new_list_download_task_info =
|
||||||
|
_cst_new_list_download_task_infoPtr
|
||||||
|
.asFunction<
|
||||||
|
ffi.Pointer<wire_cst_list_download_task_info> Function(int)
|
||||||
|
>();
|
||||||
|
|
||||||
ffi.Pointer<wire_cst_list_p_4_k_file_item> cst_new_list_p_4_k_file_item(
|
ffi.Pointer<wire_cst_list_p_4_k_file_item> cst_new_list_p_4_k_file_item(
|
||||||
int len,
|
int len,
|
||||||
) {
|
) {
|
||||||
@ -2459,6 +2932,20 @@ final class wire_cst_list_prim_u_8_strict extends ffi.Struct {
|
|||||||
external int len;
|
external int len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_list_String extends ffi.Struct {
|
||||||
|
external ffi.Pointer<ffi.Pointer<wire_cst_list_prim_u_8_strict>> ptr;
|
||||||
|
|
||||||
|
@ffi.Int32()
|
||||||
|
external int len;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_list_prim_u_8_loose extends ffi.Struct {
|
||||||
|
external ffi.Pointer<ffi.Uint8> ptr;
|
||||||
|
|
||||||
|
@ffi.Int32()
|
||||||
|
external int len;
|
||||||
|
}
|
||||||
|
|
||||||
final class wire_cst_record_string_string extends ffi.Struct {
|
final class wire_cst_record_string_string extends ffi.Struct {
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> field0;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> field0;
|
||||||
|
|
||||||
@ -2472,13 +2959,6 @@ final class wire_cst_list_record_string_string extends ffi.Struct {
|
|||||||
external int len;
|
external int len;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class wire_cst_list_String extends ffi.Struct {
|
|
||||||
external ffi.Pointer<ffi.Pointer<wire_cst_list_prim_u_8_strict>> ptr;
|
|
||||||
|
|
||||||
@ffi.Int32()
|
|
||||||
external int len;
|
|
||||||
}
|
|
||||||
|
|
||||||
final class wire_cst_rsi_launcher_asar_data extends ffi.Struct {
|
final class wire_cst_rsi_launcher_asar_data extends ffi.Struct {
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> asar_path;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> asar_path;
|
||||||
|
|
||||||
@ -2487,13 +2967,6 @@ final class wire_cst_rsi_launcher_asar_data extends ffi.Struct {
|
|||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> main_js_content;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> main_js_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class wire_cst_list_prim_u_8_loose extends ffi.Struct {
|
|
||||||
external ffi.Pointer<ffi.Uint8> ptr;
|
|
||||||
|
|
||||||
@ffi.Int32()
|
|
||||||
external int len;
|
|
||||||
}
|
|
||||||
|
|
||||||
final class wire_cst_web_view_configuration extends ffi.Struct {
|
final class wire_cst_web_view_configuration extends ffi.Struct {
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> title;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> title;
|
||||||
|
|
||||||
@ -2514,6 +2987,46 @@ final class wire_cst_web_view_configuration extends ffi.Struct {
|
|||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> user_agent;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> user_agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_download_task_info extends ffi.Struct {
|
||||||
|
@ffi.UintPtr()
|
||||||
|
external int id;
|
||||||
|
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> name;
|
||||||
|
|
||||||
|
@ffi.Int32()
|
||||||
|
external int status;
|
||||||
|
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int total_bytes;
|
||||||
|
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int downloaded_bytes;
|
||||||
|
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int uploaded_bytes;
|
||||||
|
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int download_speed;
|
||||||
|
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int upload_speed;
|
||||||
|
|
||||||
|
@ffi.Double()
|
||||||
|
external double progress;
|
||||||
|
|
||||||
|
@ffi.UintPtr()
|
||||||
|
external int num_peers;
|
||||||
|
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> output_folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_list_download_task_info extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_download_task_info> ptr;
|
||||||
|
|
||||||
|
@ffi.Int32()
|
||||||
|
external int len;
|
||||||
|
}
|
||||||
|
|
||||||
final class wire_cst_p_4_k_file_item extends ffi.Struct {
|
final class wire_cst_p_4_k_file_item extends ffi.Struct {
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> name;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> name;
|
||||||
|
|
||||||
@ -2599,6 +3112,20 @@ final class wire_cst_list_web_view_event extends ffi.Struct {
|
|||||||
external int len;
|
external int len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_download_global_stat extends ffi.Struct {
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int download_speed;
|
||||||
|
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int upload_speed;
|
||||||
|
|
||||||
|
@ffi.UintPtr()
|
||||||
|
external int num_active;
|
||||||
|
|
||||||
|
@ffi.UintPtr()
|
||||||
|
external int num_waiting;
|
||||||
|
}
|
||||||
|
|
||||||
final class wire_cst_rs_process_stream_data extends ffi.Struct {
|
final class wire_cst_rs_process_stream_data extends ffi.Struct {
|
||||||
@ffi.Int32()
|
@ffi.Int32()
|
||||||
external int data_type;
|
external int data_type;
|
||||||
|
|||||||
@ -1,222 +0,0 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
import 'package:starcitizen_doctor/common/conf/binary_conf.dart';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:math';
|
|
||||||
import 'package:aria2/aria2.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:hive_ce/hive.dart';
|
|
||||||
import 'package:starcitizen_doctor/api/api.dart';
|
|
||||||
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
|
|
||||||
import 'package:starcitizen_doctor/common/rust/api/rs_process.dart' as rs_process;
|
|
||||||
|
|
||||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
|
||||||
import 'package:starcitizen_doctor/common/utils/provider.dart';
|
|
||||||
import 'package:starcitizen_doctor/ui/home/downloader/home_downloader_ui_model.dart';
|
|
||||||
|
|
||||||
part 'aria2c.g.dart';
|
|
||||||
|
|
||||||
part 'aria2c.freezed.dart';
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
abstract class Aria2cModelState with _$Aria2cModelState {
|
|
||||||
const factory Aria2cModelState({required String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat}) =
|
|
||||||
_Aria2cModelState;
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Aria2cModelExt on Aria2cModelState {
|
|
||||||
bool get isRunning => aria2c != null;
|
|
||||||
|
|
||||||
bool get hasDownloadTask => aria2globalStat != null && aria2TotalTaskNum > 0;
|
|
||||||
|
|
||||||
int get aria2TotalTaskNum =>
|
|
||||||
aria2globalStat == null ? 0 : ((aria2globalStat!.numActive ?? 0) + (aria2globalStat!.numWaiting ?? 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
@riverpod
|
|
||||||
class Aria2cModel extends _$Aria2cModel {
|
|
||||||
bool _disposed = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Aria2cModelState build() {
|
|
||||||
if (appGlobalState.applicationBinaryModuleDir == null) {
|
|
||||||
throw Exception("applicationBinaryModuleDir is null");
|
|
||||||
}
|
|
||||||
ref.onDispose(() {
|
|
||||||
_disposed = true;
|
|
||||||
});
|
|
||||||
ref.keepAlive();
|
|
||||||
final aria2cDir = "${appGlobalState.applicationBinaryModuleDir}\\aria2c";
|
|
||||||
// LazyLoad init
|
|
||||||
() async {
|
|
||||||
try {
|
|
||||||
final sessionFile = File("$aria2cDir\\aria2.session");
|
|
||||||
// 有下载任务则第一时间初始化
|
|
||||||
if (await sessionFile.exists ()
|
|
||||||
&& (await sessionFile.readAsString()).trim().isNotEmpty) {
|
|
||||||
dPrint("launch Aria2c daemon");
|
|
||||||
await launchDaemon(appGlobalState.applicationBinaryModuleDir!);
|
|
||||||
} else {
|
|
||||||
dPrint("LazyLoad Aria2c daemon");
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
dPrint("Aria2cManager.checkLazyLoad Error:$e");
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
|
|
||||||
return Aria2cModelState(aria2cDir: aria2cDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future launchDaemon(String applicationBinaryModuleDir) async {
|
|
||||||
if (state.aria2c != null) return;
|
|
||||||
await BinaryModuleConf.extractModule(["aria2c"], applicationBinaryModuleDir);
|
|
||||||
|
|
||||||
/// skip for debug hot reload
|
|
||||||
if (kDebugMode) {
|
|
||||||
if ((await SystemHelper.getPID("aria2c")).isNotEmpty) {
|
|
||||||
dPrint("[Aria2cManager] debug skip for hot reload");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final sessionFile = File("${state.aria2cDir}\\aria2.session");
|
|
||||||
if (!await sessionFile.exists()) {
|
|
||||||
await sessionFile.create(recursive: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
final exePath = "${state.aria2cDir}\\aria2c.exe";
|
|
||||||
final port = await getFreePort();
|
|
||||||
final pwd = generateRandomPassword(16);
|
|
||||||
dPrint("pwd === $pwd");
|
|
||||||
final trackerList = await Api.getTorrentTrackerList();
|
|
||||||
dPrint("trackerList === $trackerList");
|
|
||||||
dPrint("Aria2cManager .----- aria2c start $port------");
|
|
||||||
|
|
||||||
final stream = rs_process.start(
|
|
||||||
executable: exePath,
|
|
||||||
arguments: [
|
|
||||||
"-V",
|
|
||||||
"-c",
|
|
||||||
"-x 16",
|
|
||||||
"--dir=${state.aria2cDir}\\downloads",
|
|
||||||
"--disable-ipv6",
|
|
||||||
"--enable-rpc",
|
|
||||||
"--pause",
|
|
||||||
"--rpc-listen-port=$port",
|
|
||||||
"--rpc-secret=$pwd",
|
|
||||||
"--input-file=${sessionFile.absolute.path.trim()}",
|
|
||||||
"--save-session=${sessionFile.absolute.path.trim()}",
|
|
||||||
"--save-session-interval=60",
|
|
||||||
"--file-allocation=trunc",
|
|
||||||
"--seed-time=0",
|
|
||||||
],
|
|
||||||
workingDirectory: state.aria2cDir,
|
|
||||||
);
|
|
||||||
|
|
||||||
String launchError = "";
|
|
||||||
|
|
||||||
stream.listen((event) {
|
|
||||||
dPrint("Aria2cManager.rs_process event === [${event.rsPid}] ${event.dataType} >> ${event.data}");
|
|
||||||
switch (event.dataType) {
|
|
||||||
case rs_process.RsProcessStreamDataType.output:
|
|
||||||
if (event.data.contains("IPv4 RPC: listening on TCP port")) {
|
|
||||||
_onLaunch(port, pwd, trackerList);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case rs_process.RsProcessStreamDataType.error:
|
|
||||||
launchError = event.data;
|
|
||||||
state = state.copyWith(aria2c: null);
|
|
||||||
break;
|
|
||||||
case rs_process.RsProcessStreamDataType.exit:
|
|
||||||
launchError = event.data;
|
|
||||||
state = state.copyWith(aria2c: null);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (state.aria2c != null) return;
|
|
||||||
if (launchError.isNotEmpty) throw launchError;
|
|
||||||
await Future.delayed(const Duration(milliseconds: 100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int> getFreePort() async {
|
|
||||||
final serverSocket = await ServerSocket.bind("127.0.0.1", 0);
|
|
||||||
final port = serverSocket.port;
|
|
||||||
await serverSocket.close();
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
|
|
||||||
String generateRandomPassword(int length) {
|
|
||||||
const String charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
||||||
Random random = Random();
|
|
||||||
StringBuffer buffer = StringBuffer();
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
int randomIndex = random.nextInt(charset.length);
|
|
||||||
buffer.write(charset[randomIndex]);
|
|
||||||
}
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
int textToByte(String text) {
|
|
||||||
if (text.length == 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (int.tryParse(text) != null) {
|
|
||||||
return int.parse(text);
|
|
||||||
}
|
|
||||||
if (text.endsWith("k")) {
|
|
||||||
return int.parse(text.substring(0, text.length - 1)) * 1024;
|
|
||||||
}
|
|
||||||
if (text.endsWith("m")) {
|
|
||||||
return int.parse(text.substring(0, text.length - 1)) * 1024 * 1024;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onLaunch(int port, String pwd, String trackerList) async {
|
|
||||||
final aria2c = Aria2c("ws://127.0.0.1:$port/jsonrpc", "websocket", pwd);
|
|
||||||
state = state.copyWith(aria2c: aria2c);
|
|
||||||
aria2c.getVersion().then((value) {
|
|
||||||
dPrint("Aria2cManager.connected! version == ${value.version}");
|
|
||||||
_listenState(aria2c);
|
|
||||||
});
|
|
||||||
final box = await Hive.openBox("app_conf");
|
|
||||||
aria2c.changeGlobalOption(
|
|
||||||
Aria2Option()
|
|
||||||
..maxOverallUploadLimit = textToByte(box.get("downloader_up_limit", defaultValue: "0"))
|
|
||||||
..maxOverallDownloadLimit = textToByte(box.get("downloader_down_limit", defaultValue: "0"))
|
|
||||||
..btTracker = trackerList,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _listenState(Aria2c aria2c) async {
|
|
||||||
dPrint("Aria2cModel._listenState start");
|
|
||||||
while (true) {
|
|
||||||
if (_disposed || state.aria2c == null) {
|
|
||||||
dPrint("Aria2cModel._listenState end");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
final aria2globalStat = await aria2c.getGlobalStat();
|
|
||||||
state = state.copyWith(aria2globalStat: aria2globalStat);
|
|
||||||
} catch (e) {
|
|
||||||
dPrint("aria2globalStat update error:$e");
|
|
||||||
}
|
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> isNameInTask(String name) async {
|
|
||||||
final aria2c = state.aria2c;
|
|
||||||
if (aria2c == null) return false;
|
|
||||||
for (var value in [...await aria2c.tellActive(), ...await aria2c.tellWaiting(0, 100000)]) {
|
|
||||||
final t = HomeDownloaderUIModel.getTaskTypeAndName(value);
|
|
||||||
if (t.key == "torrent" && t.value.contains(name)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,289 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// coverage:ignore-file
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
|
||||||
|
|
||||||
part of 'aria2c.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// FreezedGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// dart format off
|
|
||||||
T _$identity<T>(T value) => value;
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$Aria2cModelState implements DiagnosticableTreeMixin {
|
|
||||||
|
|
||||||
String get aria2cDir; Aria2c? get aria2c; Aria2GlobalStat? get aria2globalStat;
|
|
||||||
/// Create a copy of Aria2cModelState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$Aria2cModelStateCopyWith<Aria2cModelState> get copyWith => _$Aria2cModelStateCopyWithImpl<Aria2cModelState>(this as Aria2cModelState, _$identity);
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
||||||
properties
|
|
||||||
..add(DiagnosticsProperty('type', 'Aria2cModelState'))
|
|
||||||
..add(DiagnosticsProperty('aria2cDir', aria2cDir))..add(DiagnosticsProperty('aria2c', aria2c))..add(DiagnosticsProperty('aria2globalStat', aria2globalStat));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is Aria2cModelState&&(identical(other.aria2cDir, aria2cDir) || other.aria2cDir == aria2cDir)&&(identical(other.aria2c, aria2c) || other.aria2c == aria2c)&&(identical(other.aria2globalStat, aria2globalStat) || other.aria2globalStat == aria2globalStat));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,aria2cDir,aria2c,aria2globalStat);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
|
||||||
return 'Aria2cModelState(aria2cDir: $aria2cDir, aria2c: $aria2c, aria2globalStat: $aria2globalStat)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $Aria2cModelStateCopyWith<$Res> {
|
|
||||||
factory $Aria2cModelStateCopyWith(Aria2cModelState value, $Res Function(Aria2cModelState) _then) = _$Aria2cModelStateCopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$Aria2cModelStateCopyWithImpl<$Res>
|
|
||||||
implements $Aria2cModelStateCopyWith<$Res> {
|
|
||||||
_$Aria2cModelStateCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final Aria2cModelState _self;
|
|
||||||
final $Res Function(Aria2cModelState) _then;
|
|
||||||
|
|
||||||
/// Create a copy of Aria2cModelState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? aria2cDir = null,Object? aria2c = freezed,Object? aria2globalStat = freezed,}) {
|
|
||||||
return _then(_self.copyWith(
|
|
||||||
aria2cDir: null == aria2cDir ? _self.aria2cDir : aria2cDir // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,aria2c: freezed == aria2c ? _self.aria2c : aria2c // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Aria2c?,aria2globalStat: freezed == aria2globalStat ? _self.aria2globalStat : aria2globalStat // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Aria2GlobalStat?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Adds pattern-matching-related methods to [Aria2cModelState].
|
|
||||||
extension Aria2cModelStatePatterns on Aria2cModelState {
|
|
||||||
/// A variant of `map` that fallback to returning `orElse`.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return orElse();
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _Aria2cModelState value)? $default,{required TResult orElse(),}){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Aria2cModelState() when $default != null:
|
|
||||||
return $default(_that);case _:
|
|
||||||
return orElse();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A `switch`-like method, using callbacks.
|
|
||||||
///
|
|
||||||
/// Callbacks receives the raw object, upcasted.
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case final Subclass2 value:
|
|
||||||
/// return ...;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _Aria2cModelState value) $default,){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Aria2cModelState():
|
|
||||||
return $default(_that);case _:
|
|
||||||
throw StateError('Unexpected subclass');
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A variant of `map` that fallback to returning `null`.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return null;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _Aria2cModelState value)? $default,){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Aria2cModelState() when $default != null:
|
|
||||||
return $default(_that);case _:
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A variant of `when` that fallback to an `orElse` callback.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return orElse();
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat)? $default,{required TResult orElse(),}) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Aria2cModelState() when $default != null:
|
|
||||||
return $default(_that.aria2cDir,_that.aria2c,_that.aria2globalStat);case _:
|
|
||||||
return orElse();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A `switch`-like method, using callbacks.
|
|
||||||
///
|
|
||||||
/// As opposed to `map`, this offers destructuring.
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case Subclass2(:final field2):
|
|
||||||
/// return ...;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat) $default,) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Aria2cModelState():
|
|
||||||
return $default(_that.aria2cDir,_that.aria2c,_that.aria2globalStat);case _:
|
|
||||||
throw StateError('Unexpected subclass');
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A variant of `when` that fallback to returning `null`
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return null;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat)? $default,) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Aria2cModelState() when $default != null:
|
|
||||||
return $default(_that.aria2cDir,_that.aria2c,_that.aria2globalStat);case _:
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
|
|
||||||
|
|
||||||
class _Aria2cModelState with DiagnosticableTreeMixin implements Aria2cModelState {
|
|
||||||
const _Aria2cModelState({required this.aria2cDir, this.aria2c, this.aria2globalStat});
|
|
||||||
|
|
||||||
|
|
||||||
@override final String aria2cDir;
|
|
||||||
@override final Aria2c? aria2c;
|
|
||||||
@override final Aria2GlobalStat? aria2globalStat;
|
|
||||||
|
|
||||||
/// Create a copy of Aria2cModelState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$Aria2cModelStateCopyWith<_Aria2cModelState> get copyWith => __$Aria2cModelStateCopyWithImpl<_Aria2cModelState>(this, _$identity);
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
||||||
properties
|
|
||||||
..add(DiagnosticsProperty('type', 'Aria2cModelState'))
|
|
||||||
..add(DiagnosticsProperty('aria2cDir', aria2cDir))..add(DiagnosticsProperty('aria2c', aria2c))..add(DiagnosticsProperty('aria2globalStat', aria2globalStat));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Aria2cModelState&&(identical(other.aria2cDir, aria2cDir) || other.aria2cDir == aria2cDir)&&(identical(other.aria2c, aria2c) || other.aria2c == aria2c)&&(identical(other.aria2globalStat, aria2globalStat) || other.aria2globalStat == aria2globalStat));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,aria2cDir,aria2c,aria2globalStat);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
|
||||||
return 'Aria2cModelState(aria2cDir: $aria2cDir, aria2c: $aria2c, aria2globalStat: $aria2globalStat)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class _$Aria2cModelStateCopyWith<$Res> implements $Aria2cModelStateCopyWith<$Res> {
|
|
||||||
factory _$Aria2cModelStateCopyWith(_Aria2cModelState value, $Res Function(_Aria2cModelState) _then) = __$Aria2cModelStateCopyWithImpl;
|
|
||||||
@override @useResult
|
|
||||||
$Res call({
|
|
||||||
String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class __$Aria2cModelStateCopyWithImpl<$Res>
|
|
||||||
implements _$Aria2cModelStateCopyWith<$Res> {
|
|
||||||
__$Aria2cModelStateCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final _Aria2cModelState _self;
|
|
||||||
final $Res Function(_Aria2cModelState) _then;
|
|
||||||
|
|
||||||
/// Create a copy of Aria2cModelState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? aria2cDir = null,Object? aria2c = freezed,Object? aria2globalStat = freezed,}) {
|
|
||||||
return _then(_Aria2cModelState(
|
|
||||||
aria2cDir: null == aria2cDir ? _self.aria2cDir : aria2cDir // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,aria2c: freezed == aria2c ? _self.aria2c : aria2c // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Aria2c?,aria2globalStat: freezed == aria2globalStat ? _self.aria2globalStat : aria2globalStat // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Aria2GlobalStat?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// dart format on
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'aria2c.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// ignore_for_file: type=lint, type=warning
|
|
||||||
|
|
||||||
@ProviderFor(Aria2cModel)
|
|
||||||
const aria2cModelProvider = Aria2cModelProvider._();
|
|
||||||
|
|
||||||
final class Aria2cModelProvider
|
|
||||||
extends $NotifierProvider<Aria2cModel, Aria2cModelState> {
|
|
||||||
const Aria2cModelProvider._()
|
|
||||||
: super(
|
|
||||||
from: null,
|
|
||||||
argument: null,
|
|
||||||
retry: null,
|
|
||||||
name: r'aria2cModelProvider',
|
|
||||||
isAutoDispose: true,
|
|
||||||
dependencies: null,
|
|
||||||
$allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String debugGetCreateSourceHash() => _$aria2cModelHash();
|
|
||||||
|
|
||||||
@$internal
|
|
||||||
@override
|
|
||||||
Aria2cModel create() => Aria2cModel();
|
|
||||||
|
|
||||||
/// {@macro riverpod.override_with_value}
|
|
||||||
Override overrideWithValue(Aria2cModelState value) {
|
|
||||||
return $ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
providerOverride: $SyncValueProvider<Aria2cModelState>(value),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String _$aria2cModelHash() => r'17956c60a79c68ae13b8b8e700ebbafb70e93194';
|
|
||||||
|
|
||||||
abstract class _$Aria2cModel extends $Notifier<Aria2cModelState> {
|
|
||||||
Aria2cModelState build();
|
|
||||||
@$mustCallSuper
|
|
||||||
@override
|
|
||||||
void runBuild() {
|
|
||||||
final created = build();
|
|
||||||
final ref = this.ref as $Ref<Aria2cModelState, Aria2cModelState>;
|
|
||||||
final element =
|
|
||||||
ref.element
|
|
||||||
as $ClassProviderElement<
|
|
||||||
AnyNotifier<Aria2cModelState, Aria2cModelState>,
|
|
||||||
Aria2cModelState,
|
|
||||||
Object?,
|
|
||||||
Object?
|
|
||||||
>;
|
|
||||||
element.handleValue(ref, created);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
198
lib/provider/download_manager.dart
Normal file
198
lib/provider/download_manager.dart
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:starcitizen_doctor/common/rust/api/downloader_api.dart' as downloader_api;
|
||||||
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/utils/provider.dart';
|
||||||
|
|
||||||
|
part 'download_manager.g.dart';
|
||||||
|
|
||||||
|
part 'download_manager.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class DownloadManagerState with _$DownloadManagerState {
|
||||||
|
const factory DownloadManagerState({
|
||||||
|
required String downloadDir,
|
||||||
|
@Default(false) bool isInitialized,
|
||||||
|
downloader_api.DownloadGlobalStat? globalStat,
|
||||||
|
}) = _DownloadManagerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DownloadManagerStateExt on DownloadManagerState {
|
||||||
|
bool get isRunning => isInitialized;
|
||||||
|
|
||||||
|
bool get hasDownloadTask => globalStat != null && (globalStat!.numActive + globalStat!.numWaiting) > BigInt.zero;
|
||||||
|
|
||||||
|
int get totalTaskNum => globalStat == null ? 0 : (globalStat!.numActive + globalStat!.numWaiting).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
class DownloadManager extends _$DownloadManager {
|
||||||
|
bool _disposed = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
DownloadManagerState build() {
|
||||||
|
if (appGlobalState.applicationBinaryModuleDir == null) {
|
||||||
|
throw Exception("applicationBinaryModuleDir is null");
|
||||||
|
}
|
||||||
|
ref.onDispose(() {
|
||||||
|
_disposed = true;
|
||||||
|
});
|
||||||
|
ref.keepAlive();
|
||||||
|
|
||||||
|
final downloadDir = "${appGlobalState.applicationBinaryModuleDir}${Platform.pathSeparator}downloads";
|
||||||
|
|
||||||
|
// Lazy load init
|
||||||
|
() async {
|
||||||
|
try {
|
||||||
|
// Check if there are existing tasks
|
||||||
|
final dir = Directory(downloadDir);
|
||||||
|
if (await dir.exists()) {
|
||||||
|
dPrint("Launch download manager");
|
||||||
|
await initDownloader();
|
||||||
|
} else {
|
||||||
|
dPrint("LazyLoad download manager");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
dPrint("DownloadManager.checkLazyLoad Error:$e");
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
return DownloadManagerState(downloadDir: downloadDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> initDownloader() async {
|
||||||
|
if (state.isInitialized) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create download directory if it doesn't exist
|
||||||
|
final dir = Directory(state.downloadDir);
|
||||||
|
if (!await dir.exists()) {
|
||||||
|
await dir.create(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the Rust downloader
|
||||||
|
downloader_api.downloaderInit(downloadDir: state.downloadDir);
|
||||||
|
|
||||||
|
state = state.copyWith(isInitialized: true);
|
||||||
|
|
||||||
|
// Start listening to state updates
|
||||||
|
_listenState();
|
||||||
|
|
||||||
|
dPrint("DownloadManager initialized");
|
||||||
|
} catch (e) {
|
||||||
|
dPrint("DownloadManager.initDownloader Error: $e");
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _listenState() async {
|
||||||
|
dPrint("DownloadManager._listenState start");
|
||||||
|
while (true) {
|
||||||
|
if (_disposed || !state.isInitialized) {
|
||||||
|
dPrint("DownloadManager._listenState end");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final globalStat = await downloader_api.downloaderGetGlobalStats();
|
||||||
|
state = state.copyWith(globalStat: globalStat);
|
||||||
|
} catch (e) {
|
||||||
|
dPrint("globalStat update error:$e");
|
||||||
|
}
|
||||||
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a torrent from base64 encoded bytes
|
||||||
|
Future<int> addTorrent(List<int> torrentBytes, {String? outputFolder, List<String>? trackers}) async {
|
||||||
|
await initDownloader();
|
||||||
|
final taskId = await downloader_api.downloaderAddTorrent(
|
||||||
|
torrentBytes: torrentBytes,
|
||||||
|
outputFolder: outputFolder,
|
||||||
|
trackers: trackers,
|
||||||
|
);
|
||||||
|
return taskId.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a torrent from magnet link
|
||||||
|
Future<int> addMagnet(String magnetLink, {String? outputFolder, List<String>? trackers}) async {
|
||||||
|
await initDownloader();
|
||||||
|
final taskId = await downloader_api.downloaderAddMagnet(
|
||||||
|
magnetLink: magnetLink,
|
||||||
|
outputFolder: outputFolder,
|
||||||
|
trackers: trackers,
|
||||||
|
);
|
||||||
|
return taskId.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a torrent from URL (only .torrent file URLs are supported)
|
||||||
|
/// HTTP downloads are NOT supported - will throw an exception
|
||||||
|
Future<int> addUrl(String url, {String? outputFolder, List<String>? trackers}) async {
|
||||||
|
await initDownloader();
|
||||||
|
final taskId = await downloader_api.downloaderAddUrl(url: url, outputFolder: outputFolder, trackers: trackers);
|
||||||
|
return taskId.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pauseTask(int taskId) async {
|
||||||
|
await downloader_api.downloaderPause(taskId: BigInt.from(taskId));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> resumeTask(int taskId) async {
|
||||||
|
await downloader_api.downloaderResume(taskId: BigInt.from(taskId));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeTask(int taskId, {bool deleteFiles = false}) async {
|
||||||
|
await downloader_api.downloaderRemove(taskId: BigInt.from(taskId), deleteFiles: deleteFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<downloader_api.DownloadTaskInfo> getTaskInfo(int taskId) async {
|
||||||
|
return await downloader_api.downloaderGetTaskInfo(taskId: BigInt.from(taskId));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<downloader_api.DownloadTaskInfo>> getAllTasks() async {
|
||||||
|
if (!state.isInitialized) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return await downloader_api.downloaderGetAllTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> isNameInTask(String name) async {
|
||||||
|
if (!state.isInitialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return await downloader_api.downloaderIsNameInTask(name: name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pauseAll() async {
|
||||||
|
await downloader_api.downloaderPauseAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> resumeAll() async {
|
||||||
|
await downloader_api.downloaderResumeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> stop() async {
|
||||||
|
await downloader_api.downloaderStop();
|
||||||
|
state = state.copyWith(isInitialized: false, globalStat: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert speed limit text to bytes per second
|
||||||
|
/// Supports formats like: "1", "100k", "10m", "0"
|
||||||
|
int textToByte(String text) {
|
||||||
|
if (text.isEmpty || text == "0") {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
final trimmed = text.trim().toLowerCase();
|
||||||
|
if (int.tryParse(trimmed) != null) {
|
||||||
|
return int.parse(trimmed);
|
||||||
|
}
|
||||||
|
if (trimmed.endsWith("k")) {
|
||||||
|
return int.parse(trimmed.substring(0, trimmed.length - 1)) * 1024;
|
||||||
|
}
|
||||||
|
if (trimmed.endsWith("m")) {
|
||||||
|
return int.parse(trimmed.substring(0, trimmed.length - 1)) * 1024 * 1024;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
277
lib/provider/download_manager.freezed.dart
Normal file
277
lib/provider/download_manager.freezed.dart
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'download_manager.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$DownloadManagerState {
|
||||||
|
|
||||||
|
String get downloadDir; bool get isInitialized; downloader_api.DownloadGlobalStat? get globalStat;
|
||||||
|
/// Create a copy of DownloadManagerState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$DownloadManagerStateCopyWith<DownloadManagerState> get copyWith => _$DownloadManagerStateCopyWithImpl<DownloadManagerState>(this as DownloadManagerState, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is DownloadManagerState&&(identical(other.downloadDir, downloadDir) || other.downloadDir == downloadDir)&&(identical(other.isInitialized, isInitialized) || other.isInitialized == isInitialized)&&(identical(other.globalStat, globalStat) || other.globalStat == globalStat));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,downloadDir,isInitialized,globalStat);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'DownloadManagerState(downloadDir: $downloadDir, isInitialized: $isInitialized, globalStat: $globalStat)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $DownloadManagerStateCopyWith<$Res> {
|
||||||
|
factory $DownloadManagerStateCopyWith(DownloadManagerState value, $Res Function(DownloadManagerState) _then) = _$DownloadManagerStateCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$DownloadManagerStateCopyWithImpl<$Res>
|
||||||
|
implements $DownloadManagerStateCopyWith<$Res> {
|
||||||
|
_$DownloadManagerStateCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final DownloadManagerState _self;
|
||||||
|
final $Res Function(DownloadManagerState) _then;
|
||||||
|
|
||||||
|
/// Create a copy of DownloadManagerState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? downloadDir = null,Object? isInitialized = null,Object? globalStat = freezed,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
downloadDir: null == downloadDir ? _self.downloadDir : downloadDir // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,isInitialized: null == isInitialized ? _self.isInitialized : isInitialized // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,globalStat: freezed == globalStat ? _self.globalStat : globalStat // ignore: cast_nullable_to_non_nullable
|
||||||
|
as downloader_api.DownloadGlobalStat?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [DownloadManagerState].
|
||||||
|
extension DownloadManagerStatePatterns on DownloadManagerState {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _DownloadManagerState value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _DownloadManagerState() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _DownloadManagerState value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _DownloadManagerState():
|
||||||
|
return $default(_that);case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _DownloadManagerState value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _DownloadManagerState() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _DownloadManagerState() when $default != null:
|
||||||
|
return $default(_that.downloadDir,_that.isInitialized,_that.globalStat);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _DownloadManagerState():
|
||||||
|
return $default(_that.downloadDir,_that.isInitialized,_that.globalStat);case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _DownloadManagerState() when $default != null:
|
||||||
|
return $default(_that.downloadDir,_that.isInitialized,_that.globalStat);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
|
||||||
|
class _DownloadManagerState implements DownloadManagerState {
|
||||||
|
const _DownloadManagerState({required this.downloadDir, this.isInitialized = false, this.globalStat});
|
||||||
|
|
||||||
|
|
||||||
|
@override final String downloadDir;
|
||||||
|
@override@JsonKey() final bool isInitialized;
|
||||||
|
@override final downloader_api.DownloadGlobalStat? globalStat;
|
||||||
|
|
||||||
|
/// Create a copy of DownloadManagerState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$DownloadManagerStateCopyWith<_DownloadManagerState> get copyWith => __$DownloadManagerStateCopyWithImpl<_DownloadManagerState>(this, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _DownloadManagerState&&(identical(other.downloadDir, downloadDir) || other.downloadDir == downloadDir)&&(identical(other.isInitialized, isInitialized) || other.isInitialized == isInitialized)&&(identical(other.globalStat, globalStat) || other.globalStat == globalStat));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,downloadDir,isInitialized,globalStat);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'DownloadManagerState(downloadDir: $downloadDir, isInitialized: $isInitialized, globalStat: $globalStat)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$DownloadManagerStateCopyWith<$Res> implements $DownloadManagerStateCopyWith<$Res> {
|
||||||
|
factory _$DownloadManagerStateCopyWith(_DownloadManagerState value, $Res Function(_DownloadManagerState) _then) = __$DownloadManagerStateCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$DownloadManagerStateCopyWithImpl<$Res>
|
||||||
|
implements _$DownloadManagerStateCopyWith<$Res> {
|
||||||
|
__$DownloadManagerStateCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _DownloadManagerState _self;
|
||||||
|
final $Res Function(_DownloadManagerState) _then;
|
||||||
|
|
||||||
|
/// Create a copy of DownloadManagerState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? downloadDir = null,Object? isInitialized = null,Object? globalStat = freezed,}) {
|
||||||
|
return _then(_DownloadManagerState(
|
||||||
|
downloadDir: null == downloadDir ? _self.downloadDir : downloadDir // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,isInitialized: null == isInitialized ? _self.isInitialized : isInitialized // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,globalStat: freezed == globalStat ? _self.globalStat : globalStat // ignore: cast_nullable_to_non_nullable
|
||||||
|
as downloader_api.DownloadGlobalStat?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
63
lib/provider/download_manager.g.dart
Normal file
63
lib/provider/download_manager.g.dart
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'download_manager.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
|
@ProviderFor(DownloadManager)
|
||||||
|
const downloadManagerProvider = DownloadManagerProvider._();
|
||||||
|
|
||||||
|
final class DownloadManagerProvider
|
||||||
|
extends $NotifierProvider<DownloadManager, DownloadManagerState> {
|
||||||
|
const DownloadManagerProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'downloadManagerProvider',
|
||||||
|
isAutoDispose: true,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$downloadManagerHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
DownloadManager create() => DownloadManager();
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(DownloadManagerState value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<DownloadManagerState>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$downloadManagerHash() => r'adc9a147522afbfcfc8a2e16310649220a75d6a3';
|
||||||
|
|
||||||
|
abstract class _$DownloadManager extends $Notifier<DownloadManagerState> {
|
||||||
|
DownloadManagerState build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
final created = build();
|
||||||
|
final ref = this.ref as $Ref<DownloadManagerState, DownloadManagerState>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<DownloadManagerState, DownloadManagerState>,
|
||||||
|
DownloadManagerState,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, created);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ import 'package:fluent_ui/fluent_ui.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
||||||
import 'package:file_sizes/file_sizes.dart';
|
import 'package:file_sizes/file_sizes.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/rust/api/downloader_api.dart';
|
||||||
|
|
||||||
import 'home_downloader_ui_model.dart';
|
import 'home_downloader_ui_model.dart';
|
||||||
|
|
||||||
@ -13,59 +14,51 @@ class HomeDownloaderUI extends HookConsumerWidget {
|
|||||||
final state = ref.watch(homeDownloaderUIModelProvider);
|
final state = ref.watch(homeDownloaderUIModelProvider);
|
||||||
final model = ref.read(homeDownloaderUIModelProvider.notifier);
|
final model = ref.read(homeDownloaderUIModelProvider.notifier);
|
||||||
|
|
||||||
return makeDefaultPage(context,
|
return makeDefaultPage(
|
||||||
content: Column(
|
context,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
content: Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
const SizedBox(height: 12),
|
children: [
|
||||||
Row(
|
const SizedBox(height: 12),
|
||||||
children: [
|
Row(
|
||||||
const Spacer(),
|
children: [
|
||||||
const SizedBox(width: 24),
|
const Spacer(),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 24),
|
||||||
for (final item in <MapEntry<String, IconData>, String>{
|
const SizedBox(width: 12),
|
||||||
const MapEntry("settings", FluentIcons.settings):
|
for (final item in <MapEntry<String, IconData>, String>{
|
||||||
S.current.downloader_speed_limit_settings,
|
const MapEntry("settings", FluentIcons.settings): S.current.downloader_speed_limit_settings,
|
||||||
if (state.tasks.isNotEmpty)
|
if (state.activeTasks.isNotEmpty)
|
||||||
const MapEntry("pause_all", FluentIcons.pause):
|
const MapEntry("pause_all", FluentIcons.pause): S.current.downloader_action_pause_all,
|
||||||
S.current.downloader_action_pause_all,
|
if (state.waitingTasks.isNotEmpty)
|
||||||
if (state.waitingTasks.isNotEmpty)
|
const MapEntry("resume_all", FluentIcons.download): S.current.downloader_action_resume_all,
|
||||||
const MapEntry("resume_all", FluentIcons.download):
|
if (state.activeTasks.isNotEmpty || state.waitingTasks.isNotEmpty)
|
||||||
S.current.downloader_action_resume_all,
|
const MapEntry("cancel_all", FluentIcons.cancel): S.current.downloader_action_cancel_all,
|
||||||
if (state.tasks.isNotEmpty || state.waitingTasks.isNotEmpty)
|
}.entries)
|
||||||
const MapEntry("cancel_all", FluentIcons.cancel):
|
Padding(
|
||||||
S.current.downloader_action_cancel_all,
|
padding: const EdgeInsets.only(left: 6, right: 6),
|
||||||
}.entries)
|
child: Button(
|
||||||
Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 6, right: 6),
|
padding: const EdgeInsets.all(4),
|
||||||
child: Button(
|
child: Row(children: [Icon(item.key.value), const SizedBox(width: 6), Text(item.value)]),
|
||||||
child: Padding(
|
),
|
||||||
padding: const EdgeInsets.all(4),
|
onPressed: () => model.onTapButton(context, item.key.key),
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Icon(item.key.value),
|
|
||||||
const SizedBox(width: 6),
|
|
||||||
Text(item.value),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onPressed: () =>
|
|
||||||
model.onTapButton(context, item.key.key)),
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
),
|
||||||
],
|
const SizedBox(width: 12),
|
||||||
),
|
],
|
||||||
if (model.getTasksLen() == 0)
|
),
|
||||||
Expanded(
|
if (model.getTasksLen() == 0)
|
||||||
child: Center(
|
Expanded(child: Center(child: Text(S.current.downloader_info_no_download_tasks)))
|
||||||
child: Text(S.current.downloader_info_no_download_tasks),
|
else
|
||||||
))
|
Expanded(
|
||||||
else
|
child: ListView.builder(
|
||||||
Expanded(
|
|
||||||
child: ListView.builder(
|
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final (task, type, isFirstType) = model.getTaskAndType(index);
|
final (task, type, isFirstType) = model.getTaskAndType(index);
|
||||||
final nt = HomeDownloaderUIModel.getTaskTypeAndName(task);
|
final nt = HomeDownloaderUIModel.getTaskTypeAndName(task);
|
||||||
|
final statusStr = model.getStatusString(task.status);
|
||||||
|
final isActive = task.status == DownloadTaskStatus.live;
|
||||||
|
final isPaused = task.status == DownloadTaskStatus.paused;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -73,39 +66,30 @@ class HomeDownloaderUI extends HookConsumerWidget {
|
|||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(left: 24, right: 24, top: index == 0 ? 0 : 12, bottom: 12),
|
||||||
left: 24,
|
|
||||||
right: 24,
|
|
||||||
top: index == 0 ? 0 : 12,
|
|
||||||
bottom: 12),
|
|
||||||
margin: const EdgeInsets.only(top: 6, bottom: 6),
|
margin: const EdgeInsets.only(top: 6, bottom: 6),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${model.listHeaderStatusMap[type]}",
|
"${model.listHeaderStatusMap[type]}",
|
||||||
style: const TextStyle(
|
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||||
fontSize: 24,
|
),
|
||||||
fontWeight: FontWeight.bold),
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(left: 12, right: 12, top: 12, bottom: 12),
|
||||||
left: 12, right: 12, top: 12, bottom: 12),
|
margin: const EdgeInsets.only(left: 12, right: 12, top: 6, bottom: 6),
|
||||||
margin: const EdgeInsets.only(
|
|
||||||
left: 12, right: 12, top: 6, bottom: 6),
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: FluentTheme.of(context)
|
color: FluentTheme.of(context).cardColor.withValues(alpha: .06),
|
||||||
.cardColor
|
|
||||||
.withValues(alpha: .06),
|
|
||||||
borderRadius: BorderRadius.circular(7),
|
borderRadius: BorderRadius.circular(7),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -113,47 +97,26 @@ class HomeDownloaderUI extends HookConsumerWidget {
|
|||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(nt.value, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
nt.value,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
S.current.downloader_info_total_size(
|
S.current.downloader_info_total_size(FileSize.getSize(task.totalBytes.toInt())),
|
||||||
FileSize.getSize(
|
|
||||||
task.totalLength ?? 0)),
|
|
||||||
style: const TextStyle(fontSize: 14),
|
style: const TextStyle(fontSize: 14),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
if (nt.key == "torrent" &&
|
if (isActive)
|
||||||
task.verifiedLength != null &&
|
|
||||||
task.verifiedLength != 0)
|
|
||||||
Text(
|
Text(
|
||||||
S.current.downloader_info_verifying(
|
S.current.downloader_info_downloading((task.progress * 100).toStringAsFixed(2)),
|
||||||
FileSize.getSize(
|
|
||||||
task.verifiedLength)),
|
|
||||||
style: const TextStyle(fontSize: 14),
|
|
||||||
)
|
)
|
||||||
else if (task.status == "active")
|
|
||||||
Text(S.current
|
|
||||||
.downloader_info_downloading(
|
|
||||||
((task.completedLength ?? 0) *
|
|
||||||
100 /
|
|
||||||
(task.totalLength ?? 1))
|
|
||||||
.toStringAsFixed(4)))
|
|
||||||
else
|
else
|
||||||
Text(S.current.downloader_info_status(
|
Text(S.current.downloader_info_status(model.statusMap[statusStr] ?? "Unknown")),
|
||||||
model.statusMap[task.status] ??
|
|
||||||
"Unknown")),
|
|
||||||
const SizedBox(width: 24),
|
const SizedBox(width: 24),
|
||||||
if (task.status == "active" &&
|
if (isActive)
|
||||||
task.verifiedLength == null)
|
|
||||||
Text(
|
Text(
|
||||||
"ETA: ${model.formatter.format(DateTime.now().add(Duration(seconds: model.getETA(task))))}"),
|
"ETA: ${model.formatter.format(DateTime.now().add(Duration(seconds: model.getETA(task))))}",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -162,20 +125,18 @@ class HomeDownloaderUI extends HookConsumerWidget {
|
|||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(S.current.downloader_info_uploaded(
|
Text(S.current.downloader_info_uploaded(FileSize.getSize(task.uploadedBytes.toInt()))),
|
||||||
FileSize.getSize(task.uploadLength))),
|
Text(
|
||||||
Text(S.current.downloader_info_downloaded(
|
S.current.downloader_info_downloaded(FileSize.getSize(task.downloadedBytes.toInt())),
|
||||||
FileSize.getSize(task.completedLength))),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 18),
|
const SizedBox(width: 18),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text("↑:${FileSize.getSize(task.uploadSpeed.toInt())}/s"),
|
||||||
"↑:${FileSize.getSize(task.uploadSpeed)}/s"),
|
Text("↓:${FileSize.getSize(task.downloadSpeed.toInt())}/s"),
|
||||||
Text(
|
|
||||||
"↓:${FileSize.getSize(task.downloadSpeed)}/s"),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 32),
|
const SizedBox(width: 32),
|
||||||
@ -184,42 +145,32 @@ class HomeDownloaderUI extends HookConsumerWidget {
|
|||||||
closeAfterClick: false,
|
closeAfterClick: false,
|
||||||
title: Padding(
|
title: Padding(
|
||||||
padding: const EdgeInsets.all(3),
|
padding: const EdgeInsets.all(3),
|
||||||
child:
|
child: Text(S.current.downloader_action_options),
|
||||||
Text(S.current.downloader_action_options),
|
|
||||||
),
|
),
|
||||||
items: [
|
items: [
|
||||||
if (task.status == "paused")
|
if (isPaused)
|
||||||
MenuFlyoutItem(
|
MenuFlyoutItem(
|
||||||
leading:
|
leading: const Icon(FluentIcons.download),
|
||||||
const Icon(FluentIcons.download),
|
text: Text(S.current.downloader_action_continue_download),
|
||||||
text: Text(S.current
|
onPressed: () => model.resumeTask(task.id.toInt()),
|
||||||
.downloader_action_continue_download),
|
)
|
||||||
onPressed: () =>
|
else if (isActive)
|
||||||
model.resumeTask(task.gid))
|
|
||||||
else if (task.status == "active")
|
|
||||||
MenuFlyoutItem(
|
MenuFlyoutItem(
|
||||||
leading: const Icon(FluentIcons.pause),
|
leading: const Icon(FluentIcons.pause),
|
||||||
text: Text(S.current
|
text: Text(S.current.downloader_action_pause_download),
|
||||||
.downloader_action_pause_download),
|
onPressed: () => model.pauseTask(task.id.toInt()),
|
||||||
onPressed: () =>
|
),
|
||||||
model.pauseTask(task.gid)),
|
|
||||||
const MenuFlyoutSeparator(),
|
const MenuFlyoutSeparator(),
|
||||||
MenuFlyoutItem(
|
MenuFlyoutItem(
|
||||||
leading: const Icon(
|
leading: const Icon(FluentIcons.chrome_close, size: 14),
|
||||||
FluentIcons.chrome_close,
|
text: Text(S.current.downloader_action_cancel_download),
|
||||||
size: 14,
|
onPressed: () => model.cancelTask(context, task.id.toInt()),
|
||||||
),
|
),
|
||||||
text: Text(S.current
|
|
||||||
.downloader_action_cancel_download),
|
|
||||||
onPressed: () =>
|
|
||||||
model.cancelTask(context, task.gid)),
|
|
||||||
MenuFlyoutItem(
|
MenuFlyoutItem(
|
||||||
leading: const Icon(
|
leading: const Icon(FluentIcons.folder_open, size: 14),
|
||||||
FluentIcons.folder_open,
|
text: Text(S.current.action_open_folder),
|
||||||
size: 14,
|
onPressed: () => model.openFolder(task),
|
||||||
),
|
),
|
||||||
text: Text(S.current.action_open_folder),
|
|
||||||
onPressed: () => model.openFolder(task)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
@ -230,31 +181,36 @@ class HomeDownloaderUI extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
itemCount: model.getTasksLen(),
|
itemCount: model.getTasksLen(),
|
||||||
)),
|
|
||||||
Container(
|
|
||||||
color: FluentTheme.of(context).cardColor.withValues(alpha: .06),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 12, bottom: 3, top: 3),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: 8,
|
|
||||||
height: 8,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: state.isAvailable ? Colors.green : Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(1000),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Text(S.current.downloader_info_download_upload_speed(
|
|
||||||
FileSize.getSize(state.globalStat?.downloadSpeed ?? 0),
|
|
||||||
FileSize.getSize(state.globalStat?.uploadSpeed ?? 0)))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
Container(
|
||||||
),
|
color: FluentTheme.of(context).cardColor.withValues(alpha: .06),
|
||||||
useBodyContainer: true);
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 12, bottom: 3, top: 3),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 8,
|
||||||
|
height: 8,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: state.isAvailable ? Colors.green : Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(1000),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text(
|
||||||
|
S.current.downloader_info_download_upload_speed(
|
||||||
|
FileSize.getSize((state.globalStat?.downloadSpeed ?? BigInt.zero).toInt()),
|
||||||
|
FileSize.getSize((state.globalStat?.uploadSpeed ?? BigInt.zero).toInt()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
useBodyContainer: true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
// ignore_for_file: avoid_build_context_in_providers, avoid_public_notifier_properties
|
// ignore_for_file: avoid_build_context_in_providers, avoid_public_notifier_properties
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:aria2/aria2.dart';
|
|
||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
@ -9,9 +7,9 @@ import 'package:hive_ce/hive.dart';
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
|
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/rust/api/downloader_api.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/provider.dart';
|
import 'package:starcitizen_doctor/provider/download_manager.dart';
|
||||||
import 'package:starcitizen_doctor/provider/aria2c.dart';
|
|
||||||
|
|
||||||
import '../../../widgets/widgets.dart';
|
import '../../../widgets/widgets.dart';
|
||||||
|
|
||||||
@ -22,10 +20,10 @@ part 'home_downloader_ui_model.freezed.dart';
|
|||||||
@freezed
|
@freezed
|
||||||
abstract class HomeDownloaderUIState with _$HomeDownloaderUIState {
|
abstract class HomeDownloaderUIState with _$HomeDownloaderUIState {
|
||||||
factory HomeDownloaderUIState({
|
factory HomeDownloaderUIState({
|
||||||
@Default([]) List<Aria2Task> tasks,
|
@Default([]) List<DownloadTaskInfo> activeTasks,
|
||||||
@Default([]) List<Aria2Task> waitingTasks,
|
@Default([]) List<DownloadTaskInfo> waitingTasks,
|
||||||
@Default([]) List<Aria2Task> stoppedTasks,
|
@Default([]) List<DownloadTaskInfo> stoppedTasks,
|
||||||
Aria2GlobalStat? globalStat,
|
DownloadGlobalStat? globalStat,
|
||||||
}) = _HomeDownloaderUIState;
|
}) = _HomeDownloaderUIState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,12 +38,11 @@ class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
|
|||||||
bool _disposed = false;
|
bool _disposed = false;
|
||||||
|
|
||||||
final statusMap = {
|
final statusMap = {
|
||||||
"active": S.current.downloader_info_downloading_status,
|
"live": S.current.downloader_info_downloading_status,
|
||||||
"waiting": S.current.downloader_info_waiting,
|
"initializing": S.current.downloader_info_waiting,
|
||||||
"paused": S.current.downloader_info_paused,
|
"paused": S.current.downloader_info_paused,
|
||||||
"error": S.current.downloader_info_download_failed,
|
"error": S.current.downloader_info_download_failed,
|
||||||
"complete": S.current.downloader_info_download_completed,
|
"finished": S.current.downloader_info_download_completed,
|
||||||
"removed": S.current.downloader_info_deleted,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
final listHeaderStatusMap = {
|
final listHeaderStatusMap = {
|
||||||
@ -65,17 +62,17 @@ class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onTapButton(BuildContext context, String key) async {
|
Future<void> onTapButton(BuildContext context, String key) async {
|
||||||
final aria2cState = ref.read(aria2cModelProvider);
|
final downloadManagerState = ref.read(downloadManagerProvider);
|
||||||
|
final downloadManager = ref.read(downloadManagerProvider.notifier);
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "pause_all":
|
case "pause_all":
|
||||||
if (!aria2cState.isRunning) return;
|
if (!downloadManagerState.isRunning) return;
|
||||||
await aria2cState.aria2c?.pauseAll();
|
await downloadManager.pauseAll();
|
||||||
await aria2cState.aria2c?.saveSession();
|
|
||||||
return;
|
return;
|
||||||
case "resume_all":
|
case "resume_all":
|
||||||
if (!aria2cState.isRunning) return;
|
if (!downloadManagerState.isRunning) return;
|
||||||
await aria2cState.aria2c?.unpauseAll();
|
await downloadManager.resumeAll();
|
||||||
await aria2cState.aria2c?.saveSession();
|
|
||||||
return;
|
return;
|
||||||
case "cancel_all":
|
case "cancel_all":
|
||||||
final userOK = await showConfirmDialogs(
|
final userOK = await showConfirmDialogs(
|
||||||
@ -84,12 +81,12 @@ class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
|
|||||||
Text(S.current.downloader_info_manual_file_deletion_note),
|
Text(S.current.downloader_info_manual_file_deletion_note),
|
||||||
);
|
);
|
||||||
if (userOK == true) {
|
if (userOK == true) {
|
||||||
if (!aria2cState.isRunning) return;
|
if (!downloadManagerState.isRunning) return;
|
||||||
try {
|
try {
|
||||||
for (var value in [...state.tasks, ...state.waitingTasks]) {
|
final allTasks = [...state.activeTasks, ...state.waitingTasks];
|
||||||
await aria2cState.aria2c?.remove(value.gid!);
|
for (var task in allTasks) {
|
||||||
|
await downloadManager.removeTask(task.id.toInt(), deleteFiles: false);
|
||||||
}
|
}
|
||||||
await aria2cState.aria2c?.saveSession();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dPrint("DownloadsUIModel cancel_all Error: $e");
|
dPrint("DownloadsUIModel cancel_all Error: $e");
|
||||||
}
|
}
|
||||||
@ -102,91 +99,77 @@ class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int getTasksLen() {
|
int getTasksLen() {
|
||||||
return state.tasks.length + state.waitingTasks.length + state.stoppedTasks.length;
|
return state.activeTasks.length + state.waitingTasks.length + state.stoppedTasks.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
(Aria2Task, String, bool) getTaskAndType(int index) {
|
(DownloadTaskInfo, String, bool) getTaskAndType(int index) {
|
||||||
final tempList = <Aria2Task>[...state.tasks, ...state.waitingTasks, ...state.stoppedTasks];
|
final tempList = <DownloadTaskInfo>[...state.activeTasks, ...state.waitingTasks, ...state.stoppedTasks];
|
||||||
if (index >= 0 && index < state.tasks.length) {
|
if (index >= 0 && index < state.activeTasks.length) {
|
||||||
return (tempList[index], "active", index == 0);
|
return (tempList[index], "active", index == 0);
|
||||||
}
|
}
|
||||||
if (index >= state.tasks.length && index < state.tasks.length + state.waitingTasks.length) {
|
if (index >= state.activeTasks.length && index < state.activeTasks.length + state.waitingTasks.length) {
|
||||||
return (tempList[index], "waiting", index == state.tasks.length);
|
return (tempList[index], "waiting", index == state.activeTasks.length);
|
||||||
}
|
}
|
||||||
if (index >= state.tasks.length + state.waitingTasks.length && index < tempList.length) {
|
if (index >= state.activeTasks.length + state.waitingTasks.length && index < tempList.length) {
|
||||||
return (tempList[index], "stopped", index == state.tasks.length + state.waitingTasks.length);
|
return (tempList[index], "stopped", index == state.activeTasks.length + state.waitingTasks.length);
|
||||||
}
|
}
|
||||||
throw Exception("Index out of range or element is null");
|
throw Exception("Index out of range or element is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
static MapEntry<String, String> getTaskTypeAndName(Aria2Task task) {
|
static MapEntry<String, String> getTaskTypeAndName(DownloadTaskInfo task) {
|
||||||
if (task.bittorrent == null) {
|
// All tasks in rqbit are torrent-based
|
||||||
String uri = task.files?[0]['uris'][0]['uri'] as String;
|
return MapEntry("torrent", task.name);
|
||||||
return MapEntry("url", uri.split('/').last);
|
}
|
||||||
} else if (task.bittorrent != null) {
|
|
||||||
if (task.bittorrent!.containsKey('info')) {
|
int getETA(DownloadTaskInfo task) {
|
||||||
var btName = task.bittorrent?["info"]["name"];
|
if (task.downloadSpeed == BigInt.zero) return 0;
|
||||||
return MapEntry("torrent", btName ?? 'torrent');
|
final remainingBytes = task.totalBytes - task.downloadedBytes;
|
||||||
} else {
|
return (remainingBytes ~/ task.downloadSpeed).toInt();
|
||||||
return MapEntry("magnet", '[METADATA]${task.infoHash}');
|
}
|
||||||
}
|
|
||||||
} else {
|
String getStatusString(DownloadTaskStatus status) {
|
||||||
return const MapEntry("metaLink", '==========metaLink============');
|
switch (status) {
|
||||||
|
case DownloadTaskStatus.live:
|
||||||
|
return "live";
|
||||||
|
case DownloadTaskStatus.initializing:
|
||||||
|
return "initializing";
|
||||||
|
case DownloadTaskStatus.paused:
|
||||||
|
return "paused";
|
||||||
|
case DownloadTaskStatus.error:
|
||||||
|
return "error";
|
||||||
|
case DownloadTaskStatus.finished:
|
||||||
|
return "finished";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getETA(Aria2Task task) {
|
Future<void> resumeTask(int taskId) async {
|
||||||
if (task.downloadSpeed == null || task.downloadSpeed == 0) return 0;
|
final downloadManager = ref.read(downloadManagerProvider.notifier);
|
||||||
final remainingBytes = (task.totalLength ?? 0) - (task.completedLength ?? 0);
|
await downloadManager.resumeTask(taskId);
|
||||||
return remainingBytes ~/ (task.downloadSpeed!);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> resumeTask(String? gid) async {
|
Future<void> pauseTask(int taskId) async {
|
||||||
final aria2c = ref.read(aria2cModelProvider).aria2c;
|
final downloadManager = ref.read(downloadManagerProvider.notifier);
|
||||||
if (gid != null) {
|
await downloadManager.pauseTask(taskId);
|
||||||
await aria2c?.unpause(gid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> pauseTask(String? gid) async {
|
Future<void> cancelTask(BuildContext context, int taskId) async {
|
||||||
final aria2c = ref.read(aria2cModelProvider).aria2c;
|
|
||||||
if (gid != null) {
|
|
||||||
await aria2c?.pause(gid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> cancelTask(BuildContext context, String? gid) async {
|
|
||||||
await Future.delayed(const Duration(milliseconds: 300));
|
await Future.delayed(const Duration(milliseconds: 300));
|
||||||
if (gid != null) {
|
if (!context.mounted) return;
|
||||||
if (!context.mounted) return;
|
final ok = await showConfirmDialogs(
|
||||||
final ok = await showConfirmDialogs(
|
context,
|
||||||
context,
|
S.current.downloader_action_confirm_cancel_download,
|
||||||
S.current.downloader_action_confirm_cancel_download,
|
Text(S.current.downloader_info_manual_file_deletion_note),
|
||||||
Text(S.current.downloader_info_manual_file_deletion_note),
|
);
|
||||||
);
|
if (ok == true) {
|
||||||
if (ok == true) {
|
final downloadManager = ref.read(downloadManagerProvider.notifier);
|
||||||
final aria2c = ref.read(aria2cModelProvider).aria2c;
|
await downloadManager.removeTask(taskId, deleteFiles: false);
|
||||||
await aria2c?.remove(gid);
|
|
||||||
await aria2c?.saveSession();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Aria2File> getFilesFormTask(Aria2Task task) {
|
void openFolder(DownloadTaskInfo task) {
|
||||||
List<Aria2File> l = [];
|
final outputFolder = task.outputFolder;
|
||||||
if (task.files != null) {
|
if (outputFolder.isNotEmpty) {
|
||||||
for (var element in task.files!) {
|
SystemHelper.openDir(outputFolder.replaceAll("/", "\\"));
|
||||||
final f = Aria2File.fromJson(element);
|
|
||||||
l.add(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
void openFolder(Aria2Task task) {
|
|
||||||
final f = getFilesFormTask(task).firstOrNull;
|
|
||||||
if (f != null) {
|
|
||||||
SystemHelper.openDir(File(f.path!).absolute.path.replaceAll("/", "\\"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,21 +177,39 @@ class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
|
|||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (_disposed) return;
|
if (_disposed) return;
|
||||||
final aria2cState = ref.read(aria2cModelProvider);
|
final downloadManagerState = ref.read(downloadManagerProvider);
|
||||||
if (aria2cState.isRunning) {
|
if (downloadManagerState.isRunning) {
|
||||||
final aria2c = aria2cState.aria2c!;
|
final downloadManager = ref.read(downloadManagerProvider.notifier);
|
||||||
final tasks = await aria2c.tellActive();
|
final allTasks = await downloadManager.getAllTasks();
|
||||||
final waitingTasks = await aria2c.tellWaiting(0, 1000000);
|
|
||||||
final stoppedTasks = await aria2c.tellStopped(0, 1000000);
|
final activeTasks = <DownloadTaskInfo>[];
|
||||||
final globalStat = await aria2c.getGlobalStat();
|
final waitingTasks = <DownloadTaskInfo>[];
|
||||||
|
final stoppedTasks = <DownloadTaskInfo>[];
|
||||||
|
|
||||||
|
for (var task in allTasks) {
|
||||||
|
switch (task.status) {
|
||||||
|
case DownloadTaskStatus.live:
|
||||||
|
activeTasks.add(task);
|
||||||
|
break;
|
||||||
|
case DownloadTaskStatus.initializing:
|
||||||
|
case DownloadTaskStatus.paused:
|
||||||
|
waitingTasks.add(task);
|
||||||
|
break;
|
||||||
|
case DownloadTaskStatus.finished:
|
||||||
|
case DownloadTaskStatus.error:
|
||||||
|
stoppedTasks.add(task);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
tasks: tasks,
|
activeTasks: activeTasks,
|
||||||
waitingTasks: waitingTasks,
|
waitingTasks: waitingTasks,
|
||||||
stoppedTasks: stoppedTasks,
|
stoppedTasks: stoppedTasks,
|
||||||
globalStat: globalStat,
|
globalStat: downloadManagerState.globalStat,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
state = state.copyWith(tasks: [], waitingTasks: [], stoppedTasks: [], globalStat: null);
|
state = state.copyWith(activeTasks: [], waitingTasks: [], stoppedTasks: [], globalStat: null);
|
||||||
}
|
}
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
}
|
}
|
||||||
@ -266,22 +267,14 @@ class HomeDownloaderUIModel extends _$HomeDownloaderUIModel {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (ok == true) {
|
if (ok == true) {
|
||||||
final aria2cState = ref.read(aria2cModelProvider);
|
// Note: rqbit doesn't support dynamic speed limit changes yet
|
||||||
final aria2cModel = ref.read(aria2cModelProvider.notifier);
|
// Just save the settings for now
|
||||||
await aria2cModel.launchDaemon(appGlobalState.applicationBinaryModuleDir!);
|
await box.put('downloader_up_limit', upCtrl.text.trim());
|
||||||
final aria2c = aria2cState.aria2c!;
|
await box.put('downloader_down_limit', downCtrl.text.trim());
|
||||||
final upByte = aria2cModel.textToByte(upCtrl.text.trim());
|
|
||||||
final downByte = aria2cModel.textToByte(downCtrl.text.trim());
|
// Show info that speed limits will apply on next restart
|
||||||
final r = await aria2c
|
if (context.mounted) {
|
||||||
.changeGlobalOption(
|
showToast(context, "Speed limit settings saved. Will apply on next download.");
|
||||||
Aria2Option()
|
|
||||||
..maxOverallUploadLimit = upByte
|
|
||||||
..maxOverallDownloadLimit = downByte,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
if (r != null) {
|
|
||||||
await box.put('downloader_up_limit', upCtrl.text.trim());
|
|
||||||
await box.put('downloader_down_limit', downCtrl.text.trim());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$HomeDownloaderUIState {
|
mixin _$HomeDownloaderUIState {
|
||||||
|
|
||||||
List<Aria2Task> get tasks; List<Aria2Task> get waitingTasks; List<Aria2Task> get stoppedTasks; Aria2GlobalStat? get globalStat;
|
List<DownloadTaskInfo> get activeTasks; List<DownloadTaskInfo> get waitingTasks; List<DownloadTaskInfo> get stoppedTasks; DownloadGlobalStat? get globalStat;
|
||||||
/// Create a copy of HomeDownloaderUIState
|
/// Create a copy of HomeDownloaderUIState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@ -25,16 +25,16 @@ $HomeDownloaderUIStateCopyWith<HomeDownloaderUIState> get copyWith => _$HomeDown
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is HomeDownloaderUIState&&const DeepCollectionEquality().equals(other.tasks, tasks)&&const DeepCollectionEquality().equals(other.waitingTasks, waitingTasks)&&const DeepCollectionEquality().equals(other.stoppedTasks, stoppedTasks)&&(identical(other.globalStat, globalStat) || other.globalStat == globalStat));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is HomeDownloaderUIState&&const DeepCollectionEquality().equals(other.activeTasks, activeTasks)&&const DeepCollectionEquality().equals(other.waitingTasks, waitingTasks)&&const DeepCollectionEquality().equals(other.stoppedTasks, stoppedTasks)&&(identical(other.globalStat, globalStat) || other.globalStat == globalStat));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(tasks),const DeepCollectionEquality().hash(waitingTasks),const DeepCollectionEquality().hash(stoppedTasks),globalStat);
|
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(activeTasks),const DeepCollectionEquality().hash(waitingTasks),const DeepCollectionEquality().hash(stoppedTasks),globalStat);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'HomeDownloaderUIState(tasks: $tasks, waitingTasks: $waitingTasks, stoppedTasks: $stoppedTasks, globalStat: $globalStat)';
|
return 'HomeDownloaderUIState(activeTasks: $activeTasks, waitingTasks: $waitingTasks, stoppedTasks: $stoppedTasks, globalStat: $globalStat)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ abstract mixin class $HomeDownloaderUIStateCopyWith<$Res> {
|
|||||||
factory $HomeDownloaderUIStateCopyWith(HomeDownloaderUIState value, $Res Function(HomeDownloaderUIState) _then) = _$HomeDownloaderUIStateCopyWithImpl;
|
factory $HomeDownloaderUIStateCopyWith(HomeDownloaderUIState value, $Res Function(HomeDownloaderUIState) _then) = _$HomeDownloaderUIStateCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
List<Aria2Task> tasks, List<Aria2Task> waitingTasks, List<Aria2Task> stoppedTasks, Aria2GlobalStat? globalStat
|
List<DownloadTaskInfo> activeTasks, List<DownloadTaskInfo> waitingTasks, List<DownloadTaskInfo> stoppedTasks, DownloadGlobalStat? globalStat
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -62,13 +62,13 @@ class _$HomeDownloaderUIStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of HomeDownloaderUIState
|
/// Create a copy of HomeDownloaderUIState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? tasks = null,Object? waitingTasks = null,Object? stoppedTasks = null,Object? globalStat = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? activeTasks = null,Object? waitingTasks = null,Object? stoppedTasks = null,Object? globalStat = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
tasks: null == tasks ? _self.tasks : tasks // ignore: cast_nullable_to_non_nullable
|
activeTasks: null == activeTasks ? _self.activeTasks : activeTasks // ignore: cast_nullable_to_non_nullable
|
||||||
as List<Aria2Task>,waitingTasks: null == waitingTasks ? _self.waitingTasks : waitingTasks // ignore: cast_nullable_to_non_nullable
|
as List<DownloadTaskInfo>,waitingTasks: null == waitingTasks ? _self.waitingTasks : waitingTasks // ignore: cast_nullable_to_non_nullable
|
||||||
as List<Aria2Task>,stoppedTasks: null == stoppedTasks ? _self.stoppedTasks : stoppedTasks // ignore: cast_nullable_to_non_nullable
|
as List<DownloadTaskInfo>,stoppedTasks: null == stoppedTasks ? _self.stoppedTasks : stoppedTasks // ignore: cast_nullable_to_non_nullable
|
||||||
as List<Aria2Task>,globalStat: freezed == globalStat ? _self.globalStat : globalStat // ignore: cast_nullable_to_non_nullable
|
as List<DownloadTaskInfo>,globalStat: freezed == globalStat ? _self.globalStat : globalStat // ignore: cast_nullable_to_non_nullable
|
||||||
as Aria2GlobalStat?,
|
as DownloadGlobalStat?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,10 +153,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<Aria2Task> tasks, List<Aria2Task> waitingTasks, List<Aria2Task> stoppedTasks, Aria2GlobalStat? globalStat)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<DownloadTaskInfo> activeTasks, List<DownloadTaskInfo> waitingTasks, List<DownloadTaskInfo> stoppedTasks, DownloadGlobalStat? globalStat)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _HomeDownloaderUIState() when $default != null:
|
case _HomeDownloaderUIState() when $default != null:
|
||||||
return $default(_that.tasks,_that.waitingTasks,_that.stoppedTasks,_that.globalStat);case _:
|
return $default(_that.activeTasks,_that.waitingTasks,_that.stoppedTasks,_that.globalStat);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -174,10 +174,10 @@ return $default(_that.tasks,_that.waitingTasks,_that.stoppedTasks,_that.globalSt
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<Aria2Task> tasks, List<Aria2Task> waitingTasks, List<Aria2Task> stoppedTasks, Aria2GlobalStat? globalStat) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<DownloadTaskInfo> activeTasks, List<DownloadTaskInfo> waitingTasks, List<DownloadTaskInfo> stoppedTasks, DownloadGlobalStat? globalStat) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _HomeDownloaderUIState():
|
case _HomeDownloaderUIState():
|
||||||
return $default(_that.tasks,_that.waitingTasks,_that.stoppedTasks,_that.globalStat);case _:
|
return $default(_that.activeTasks,_that.waitingTasks,_that.stoppedTasks,_that.globalStat);case _:
|
||||||
throw StateError('Unexpected subclass');
|
throw StateError('Unexpected subclass');
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -194,10 +194,10 @@ return $default(_that.tasks,_that.waitingTasks,_that.stoppedTasks,_that.globalSt
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<Aria2Task> tasks, List<Aria2Task> waitingTasks, List<Aria2Task> stoppedTasks, Aria2GlobalStat? globalStat)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<DownloadTaskInfo> activeTasks, List<DownloadTaskInfo> waitingTasks, List<DownloadTaskInfo> stoppedTasks, DownloadGlobalStat? globalStat)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _HomeDownloaderUIState() when $default != null:
|
case _HomeDownloaderUIState() when $default != null:
|
||||||
return $default(_that.tasks,_that.waitingTasks,_that.stoppedTasks,_that.globalStat);case _:
|
return $default(_that.activeTasks,_that.waitingTasks,_that.stoppedTasks,_that.globalStat);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -209,31 +209,31 @@ return $default(_that.tasks,_that.waitingTasks,_that.stoppedTasks,_that.globalSt
|
|||||||
|
|
||||||
|
|
||||||
class _HomeDownloaderUIState implements HomeDownloaderUIState {
|
class _HomeDownloaderUIState implements HomeDownloaderUIState {
|
||||||
_HomeDownloaderUIState({final List<Aria2Task> tasks = const [], final List<Aria2Task> waitingTasks = const [], final List<Aria2Task> stoppedTasks = const [], this.globalStat}): _tasks = tasks,_waitingTasks = waitingTasks,_stoppedTasks = stoppedTasks;
|
_HomeDownloaderUIState({final List<DownloadTaskInfo> activeTasks = const [], final List<DownloadTaskInfo> waitingTasks = const [], final List<DownloadTaskInfo> stoppedTasks = const [], this.globalStat}): _activeTasks = activeTasks,_waitingTasks = waitingTasks,_stoppedTasks = stoppedTasks;
|
||||||
|
|
||||||
|
|
||||||
final List<Aria2Task> _tasks;
|
final List<DownloadTaskInfo> _activeTasks;
|
||||||
@override@JsonKey() List<Aria2Task> get tasks {
|
@override@JsonKey() List<DownloadTaskInfo> get activeTasks {
|
||||||
if (_tasks is EqualUnmodifiableListView) return _tasks;
|
if (_activeTasks is EqualUnmodifiableListView) return _activeTasks;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_tasks);
|
return EqualUnmodifiableListView(_activeTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Aria2Task> _waitingTasks;
|
final List<DownloadTaskInfo> _waitingTasks;
|
||||||
@override@JsonKey() List<Aria2Task> get waitingTasks {
|
@override@JsonKey() List<DownloadTaskInfo> get waitingTasks {
|
||||||
if (_waitingTasks is EqualUnmodifiableListView) return _waitingTasks;
|
if (_waitingTasks is EqualUnmodifiableListView) return _waitingTasks;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_waitingTasks);
|
return EqualUnmodifiableListView(_waitingTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Aria2Task> _stoppedTasks;
|
final List<DownloadTaskInfo> _stoppedTasks;
|
||||||
@override@JsonKey() List<Aria2Task> get stoppedTasks {
|
@override@JsonKey() List<DownloadTaskInfo> get stoppedTasks {
|
||||||
if (_stoppedTasks is EqualUnmodifiableListView) return _stoppedTasks;
|
if (_stoppedTasks is EqualUnmodifiableListView) return _stoppedTasks;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_stoppedTasks);
|
return EqualUnmodifiableListView(_stoppedTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override final Aria2GlobalStat? globalStat;
|
@override final DownloadGlobalStat? globalStat;
|
||||||
|
|
||||||
/// Create a copy of HomeDownloaderUIState
|
/// Create a copy of HomeDownloaderUIState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@ -245,16 +245,16 @@ _$HomeDownloaderUIStateCopyWith<_HomeDownloaderUIState> get copyWith => __$HomeD
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _HomeDownloaderUIState&&const DeepCollectionEquality().equals(other._tasks, _tasks)&&const DeepCollectionEquality().equals(other._waitingTasks, _waitingTasks)&&const DeepCollectionEquality().equals(other._stoppedTasks, _stoppedTasks)&&(identical(other.globalStat, globalStat) || other.globalStat == globalStat));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _HomeDownloaderUIState&&const DeepCollectionEquality().equals(other._activeTasks, _activeTasks)&&const DeepCollectionEquality().equals(other._waitingTasks, _waitingTasks)&&const DeepCollectionEquality().equals(other._stoppedTasks, _stoppedTasks)&&(identical(other.globalStat, globalStat) || other.globalStat == globalStat));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_tasks),const DeepCollectionEquality().hash(_waitingTasks),const DeepCollectionEquality().hash(_stoppedTasks),globalStat);
|
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_activeTasks),const DeepCollectionEquality().hash(_waitingTasks),const DeepCollectionEquality().hash(_stoppedTasks),globalStat);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'HomeDownloaderUIState(tasks: $tasks, waitingTasks: $waitingTasks, stoppedTasks: $stoppedTasks, globalStat: $globalStat)';
|
return 'HomeDownloaderUIState(activeTasks: $activeTasks, waitingTasks: $waitingTasks, stoppedTasks: $stoppedTasks, globalStat: $globalStat)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -265,7 +265,7 @@ abstract mixin class _$HomeDownloaderUIStateCopyWith<$Res> implements $HomeDownl
|
|||||||
factory _$HomeDownloaderUIStateCopyWith(_HomeDownloaderUIState value, $Res Function(_HomeDownloaderUIState) _then) = __$HomeDownloaderUIStateCopyWithImpl;
|
factory _$HomeDownloaderUIStateCopyWith(_HomeDownloaderUIState value, $Res Function(_HomeDownloaderUIState) _then) = __$HomeDownloaderUIStateCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
List<Aria2Task> tasks, List<Aria2Task> waitingTasks, List<Aria2Task> stoppedTasks, Aria2GlobalStat? globalStat
|
List<DownloadTaskInfo> activeTasks, List<DownloadTaskInfo> waitingTasks, List<DownloadTaskInfo> stoppedTasks, DownloadGlobalStat? globalStat
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -282,13 +282,13 @@ class __$HomeDownloaderUIStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of HomeDownloaderUIState
|
/// Create a copy of HomeDownloaderUIState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? tasks = null,Object? waitingTasks = null,Object? stoppedTasks = null,Object? globalStat = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? activeTasks = null,Object? waitingTasks = null,Object? stoppedTasks = null,Object? globalStat = freezed,}) {
|
||||||
return _then(_HomeDownloaderUIState(
|
return _then(_HomeDownloaderUIState(
|
||||||
tasks: null == tasks ? _self._tasks : tasks // ignore: cast_nullable_to_non_nullable
|
activeTasks: null == activeTasks ? _self._activeTasks : activeTasks // ignore: cast_nullable_to_non_nullable
|
||||||
as List<Aria2Task>,waitingTasks: null == waitingTasks ? _self._waitingTasks : waitingTasks // ignore: cast_nullable_to_non_nullable
|
as List<DownloadTaskInfo>,waitingTasks: null == waitingTasks ? _self._waitingTasks : waitingTasks // ignore: cast_nullable_to_non_nullable
|
||||||
as List<Aria2Task>,stoppedTasks: null == stoppedTasks ? _self._stoppedTasks : stoppedTasks // ignore: cast_nullable_to_non_nullable
|
as List<DownloadTaskInfo>,stoppedTasks: null == stoppedTasks ? _self._stoppedTasks : stoppedTasks // ignore: cast_nullable_to_non_nullable
|
||||||
as List<Aria2Task>,globalStat: freezed == globalStat ? _self.globalStat : globalStat // ignore: cast_nullable_to_non_nullable
|
as List<DownloadTaskInfo>,globalStat: freezed == globalStat ? _self.globalStat : globalStat // ignore: cast_nullable_to_non_nullable
|
||||||
as Aria2GlobalStat?,
|
as DownloadGlobalStat?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ final class HomeDownloaderUIModelProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$homeDownloaderUIModelHash() =>
|
String _$homeDownloaderUIModelHash() =>
|
||||||
r'cb5d0973d56bbf40673afc2a734b49f5d034ab98';
|
r'27e2e4b7a5103eee9d489a347410131edef46be4';
|
||||||
|
|
||||||
abstract class _$HomeDownloaderUIModel
|
abstract class _$HomeDownloaderUIModel
|
||||||
extends $Notifier<HomeDownloaderUIState> {
|
extends $Notifier<HomeDownloaderUIState> {
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
// ignore_for_file: avoid_build_context_in_providers, use_build_context_synchronously
|
// ignore_for_file: avoid_build_context_in_providers, use_build_context_synchronously
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@ -14,7 +13,7 @@ import 'package:starcitizen_doctor/common/utils/async.dart';
|
|||||||
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/provider.dart';
|
import 'package:starcitizen_doctor/common/utils/provider.dart';
|
||||||
import 'package:starcitizen_doctor/provider/aria2c.dart';
|
import 'package:starcitizen_doctor/provider/download_manager.dart';
|
||||||
import 'package:starcitizen_doctor/ui/home/localization/localization_ui_model.dart';
|
import 'package:starcitizen_doctor/ui/home/localization/localization_ui_model.dart';
|
||||||
import 'package:starcitizen_doctor/common/rust/api/ort_api.dart' as ort;
|
import 'package:starcitizen_doctor/common/rust/api/ort_api.dart' as ort;
|
||||||
|
|
||||||
@ -240,11 +239,10 @@ class InputMethodDialogUIModel extends _$InputMethodDialogUIModel {
|
|||||||
Future<String> doDownloadTranslateModel() async {
|
Future<String> doDownloadTranslateModel() async {
|
||||||
state = state.copyWith(isAutoTranslateWorking: true);
|
state = state.copyWith(isAutoTranslateWorking: true);
|
||||||
try {
|
try {
|
||||||
final aria2cManager = ref.read(aria2cModelProvider.notifier);
|
final downloadManager = ref.read(downloadManagerProvider.notifier);
|
||||||
await aria2cManager.launchDaemon(appGlobalState.applicationBinaryModuleDir!);
|
await downloadManager.initDownloader();
|
||||||
final aria2c = ref.read(aria2cModelProvider).aria2c!;
|
|
||||||
|
|
||||||
if (await aria2cManager.isNameInTask(_localTranslateModelName)) {
|
if (await downloadManager.isNameInTask(_localTranslateModelName)) {
|
||||||
throw Exception("Model is already downloading");
|
throw Exception("Model is already downloading");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,9 +257,8 @@ class InputMethodDialogUIModel extends _$InputMethodDialogUIModel {
|
|||||||
}
|
}
|
||||||
// get torrent Data
|
// get torrent Data
|
||||||
final data = await RSHttp.get(torrentUrl!);
|
final data = await RSHttp.get(torrentUrl!);
|
||||||
final b64Str = base64Encode(data.data!);
|
final taskId = await downloadManager.addTorrent(data.data!, outputFolder: _localTranslateModelDir);
|
||||||
final gid = await aria2c.addTorrent(b64Str, extraParams: {"dir": _localTranslateModelDir});
|
return taskId.toString();
|
||||||
return gid;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dPrint("[InputMethodDialogUIModel] doDownloadTranslateModel error: $e");
|
dPrint("[InputMethodDialogUIModel] doDownloadTranslateModel error: $e");
|
||||||
rethrow;
|
rethrow;
|
||||||
@ -330,8 +327,8 @@ class InputMethodDialogUIModel extends _$InputMethodDialogUIModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> isTranslateModelDownloading() async {
|
Future<bool> isTranslateModelDownloading() async {
|
||||||
final aria2cManager = ref.read(aria2cModelProvider.notifier);
|
final downloadManager = ref.read(downloadManagerProvider.notifier);
|
||||||
return await aria2cManager.isNameInTask(_localTranslateModelName);
|
return await downloadManager.isNameInTask(_localTranslateModelName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,7 +43,7 @@ final class InputMethodDialogUIModelProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$inputMethodDialogUIModelHash() =>
|
String _$inputMethodDialogUIModelHash() =>
|
||||||
r'bd96c85ef2073d80de6eba71748b41adb8861e1c';
|
r'5c2989faf94d43bb814e5b80e10d68416c8241ec';
|
||||||
|
|
||||||
abstract class _$InputMethodDialogUIModel
|
abstract class _$InputMethodDialogUIModel
|
||||||
extends $Notifier<InputMethodDialogUIState> {
|
extends $Notifier<InputMethodDialogUIState> {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:starcitizen_doctor/app.dart';
|
import 'package:starcitizen_doctor/app.dart';
|
||||||
import 'package:starcitizen_doctor/common/conf/conf.dart';
|
import 'package:starcitizen_doctor/common/conf/conf.dart';
|
||||||
import 'package:starcitizen_doctor/provider/aria2c.dart';
|
import 'package:starcitizen_doctor/provider/download_manager.dart';
|
||||||
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
|
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
|
||||||
import 'package:starcitizen_doctor/ui/party_room/party_room_ui.dart';
|
import 'package:starcitizen_doctor/ui/party_room/party_room_ui.dart';
|
||||||
import 'package:starcitizen_doctor/ui/settings/settings_ui_model.dart';
|
import 'package:starcitizen_doctor/ui/settings/settings_ui_model.dart';
|
||||||
@ -61,7 +61,7 @@ class IndexUI extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.all(6),
|
padding: const EdgeInsets.all(6),
|
||||||
child: Icon(FluentIcons.installation, size: 22, color: Colors.white.withValues(alpha: .6)),
|
child: Icon(FluentIcons.installation, size: 22, color: Colors.white.withValues(alpha: .6)),
|
||||||
),
|
),
|
||||||
_makeAria2TaskNumWidget(),
|
_makeDownloadTaskNumWidget(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onPressed: () => _goDownloader(context),
|
onPressed: () => _goDownloader(context),
|
||||||
@ -124,11 +124,11 @@ class IndexUI extends HookConsumerWidget {
|
|||||||
curIndexState.value = pageIndex;
|
curIndexState.value = pageIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _makeAria2TaskNumWidget() {
|
Widget _makeDownloadTaskNumWidget() {
|
||||||
return Consumer(
|
return Consumer(
|
||||||
builder: (BuildContext context, WidgetRef ref, Widget? child) {
|
builder: (BuildContext context, WidgetRef ref, Widget? child) {
|
||||||
final aria2cState = ref.watch(aria2cModelProvider);
|
final downloadState = ref.watch(downloadManagerProvider);
|
||||||
if (!aria2cState.hasDownloadTask) {
|
if (!downloadState.hasDownloadTask) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
return Positioned(
|
return Positioned(
|
||||||
@ -137,7 +137,7 @@ class IndexUI extends HookConsumerWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(12)),
|
decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(12)),
|
||||||
padding: const EdgeInsets.only(left: 6, right: 6, bottom: 1.5, top: 1.5),
|
padding: const EdgeInsets.only(left: 6, right: 6, bottom: 1.5, top: 1.5),
|
||||||
child: Text("${aria2cState.aria2TotalTaskNum}", style: const TextStyle(fontSize: 8, color: Colors.white)),
|
child: Text("${downloadState.totalTaskNum}", style: const TextStyle(fontSize: 8, color: Colors.white)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import 'package:starcitizen_doctor/app.dart';
|
|||||||
import 'package:starcitizen_doctor/common/conf/conf.dart';
|
import 'package:starcitizen_doctor/common/conf/conf.dart';
|
||||||
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
|
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||||
import 'package:starcitizen_doctor/provider/aria2c.dart';
|
import 'package:starcitizen_doctor/provider/download_manager.dart';
|
||||||
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
||||||
|
|
||||||
class SplashUI extends HookConsumerWidget {
|
class SplashUI extends HookConsumerWidget {
|
||||||
@ -42,36 +42,36 @@ class SplashUI extends HookConsumerWidget {
|
|||||||
child: diagnosticMode.value
|
child: diagnosticMode.value
|
||||||
? _buildDiagnosticView(diagnosticLogs, step, context)
|
? _buildDiagnosticView(diagnosticLogs, step, context)
|
||||||
: Column(
|
: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
final lastClick = lastClickTime.value;
|
final lastClick = lastClickTime.value;
|
||||||
|
|
||||||
// 重置计数器如果距离上次点击超过2秒
|
// 重置计数器如果距离上次点击超过2秒
|
||||||
if (lastClick != null && now.difference(lastClick).inSeconds > 2) {
|
if (lastClick != null && now.difference(lastClick).inSeconds > 2) {
|
||||||
clickCount.value = 0;
|
clickCount.value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastClickTime.value = now;
|
lastClickTime.value = now;
|
||||||
clickCount.value++;
|
clickCount.value++;
|
||||||
|
|
||||||
if (clickCount.value >= 10) {
|
if (clickCount.value >= 10) {
|
||||||
diagnosticMode.value = true;
|
diagnosticMode.value = true;
|
||||||
clickCount.value = 0;
|
clickCount.value = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Image.asset("assets/app_logo.png", width: 192, height: 192),
|
child: Image.asset("assets/app_logo.png", width: 192, height: 192),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
const ProgressRing(),
|
const ProgressRing(),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
if (step == 0) Text(S.current.app_splash_checking_availability),
|
if (step == 0) Text(S.current.app_splash_checking_availability),
|
||||||
if (step == 1) Text(S.current.app_splash_checking_for_updates),
|
if (step == 1) Text(S.current.app_splash_checking_for_updates),
|
||||||
if (step == 2) Text(S.current.app_splash_almost_done)
|
if (step == 2) Text(S.current.app_splash_almost_done),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
titleRow: Align(
|
titleRow: Align(
|
||||||
@ -124,26 +124,28 @@ class SplashUI extends HookConsumerWidget {
|
|||||||
child: logs.isEmpty
|
child: logs.isEmpty
|
||||||
? Center(child: Text(S.current.splash_waiting_log))
|
? Center(child: Text(S.current.splash_waiting_log))
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
itemCount: logs.length,
|
itemCount: logs.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final log = logs[index];
|
final log = logs[index];
|
||||||
Color textColor = Colors.white;
|
Color textColor = Colors.white;
|
||||||
if (log.contains('✓')) {
|
if (log.contains('✓')) {
|
||||||
textColor = Colors.green;
|
textColor = Colors.green;
|
||||||
} else if (log.contains('✗') || log.contains(S.current.splash_timeout) || log.contains(S.current.splash_error)) {
|
} else if (log.contains('✗') ||
|
||||||
textColor = Colors.red;
|
log.contains(S.current.splash_timeout) ||
|
||||||
} else if (log.contains('⚠')) {
|
log.contains(S.current.splash_error)) {
|
||||||
textColor = Colors.orange;
|
textColor = Colors.red;
|
||||||
}
|
} else if (log.contains('⚠')) {
|
||||||
return Padding(
|
textColor = Colors.orange;
|
||||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
}
|
||||||
child: Text(
|
return Padding(
|
||||||
log,
|
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||||
style: TextStyle(fontFamily: 'Consolas', fontSize: 12, color: textColor),
|
child: Text(
|
||||||
|
log,
|
||||||
|
style: TextStyle(fontFamily: 'Consolas', fontSize: 12, color: textColor),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -154,12 +156,12 @@ class SplashUI extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _initApp(
|
void _initApp(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
AppGlobalModel appModel,
|
AppGlobalModel appModel,
|
||||||
ValueNotifier<int> stepState,
|
ValueNotifier<int> stepState,
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
ValueNotifier<List<String>> diagnosticLogs,
|
ValueNotifier<List<String>> diagnosticLogs,
|
||||||
) async {
|
) async {
|
||||||
void addLog(String message) {
|
void addLog(String message) {
|
||||||
final logMessage = '[${DateTime.now().toString().substring(11, 23)}] $message';
|
final logMessage = '[${DateTime.now().toString().substring(11, 23)}] $message';
|
||||||
diagnosticLogs.value = [...diagnosticLogs.value, logMessage];
|
diagnosticLogs.value = [...diagnosticLogs.value, logMessage];
|
||||||
@ -263,12 +265,12 @@ class SplashUI extends HookConsumerWidget {
|
|||||||
await appModel
|
await appModel
|
||||||
.checkUpdate(context)
|
.checkUpdate(context)
|
||||||
.timeout(
|
.timeout(
|
||||||
const Duration(seconds: 10),
|
const Duration(seconds: 10),
|
||||||
onTimeout: () {
|
onTimeout: () {
|
||||||
addLog(S.current.splash_check_update_timeout);
|
addLog(S.current.splash_check_update_timeout);
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
addLog(S.current.splash_check_update_done);
|
addLog(S.current.splash_check_update_done);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
addLog('⚠ appModel.checkUpdate() 错误: $e - 继续执行');
|
addLog('⚠ appModel.checkUpdate() 错误: $e - 继续执行');
|
||||||
@ -277,14 +279,14 @@ class SplashUI extends HookConsumerWidget {
|
|||||||
addLog(S.current.splash_step1_done);
|
addLog(S.current.splash_step1_done);
|
||||||
stepState.value = 2;
|
stepState.value = 2;
|
||||||
|
|
||||||
// Step 2: Initialize aria2c
|
// Step 2: Initialize download manager
|
||||||
addLog(S.current.splash_init_aria2c);
|
addLog(S.current.splash_init_aria2c);
|
||||||
dPrint("_initApp aria2cModelProvider");
|
dPrint("_initApp downloadManagerProvider");
|
||||||
try {
|
try {
|
||||||
ref.read(aria2cModelProvider);
|
ref.read(downloadManagerProvider);
|
||||||
addLog(S.current.splash_aria2c_done);
|
addLog(S.current.splash_aria2c_done);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
addLog('⚠ aria2cModelProvider 初始化错误: $e');
|
addLog('⚠ downloadManagerProvider 初始化错误: $e');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.mounted) {
|
if (!context.mounted) {
|
||||||
@ -385,4 +387,4 @@ class SplashUI extends HookConsumerWidget {
|
|||||||
dPrint(S.current.splash_reset_db_failed(e.toString()));
|
dPrint(S.current.splash_reset_db_failed(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import 'package:starcitizen_doctor/common/io/rs_http.dart';
|
|||||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/multi_window_manager.dart';
|
import 'package:starcitizen_doctor/common/utils/multi_window_manager.dart';
|
||||||
import 'package:starcitizen_doctor/common/utils/provider.dart';
|
import 'package:starcitizen_doctor/common/utils/provider.dart';
|
||||||
import 'package:starcitizen_doctor/provider/aria2c.dart';
|
import 'package:starcitizen_doctor/provider/download_manager.dart';
|
||||||
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
import 'package:xml/xml.dart';
|
import 'package:xml/xml.dart';
|
||||||
@ -27,7 +27,6 @@ import 'dialogs/hosts_booster_dialog_ui.dart';
|
|||||||
import 'dialogs/rsi_launcher_enhance_dialog_ui.dart';
|
import 'dialogs/rsi_launcher_enhance_dialog_ui.dart';
|
||||||
|
|
||||||
part 'tools_ui_model.g.dart';
|
part 'tools_ui_model.g.dart';
|
||||||
|
|
||||||
part 'tools_ui_model.freezed.dart';
|
part 'tools_ui_model.freezed.dart';
|
||||||
|
|
||||||
class ToolsItemData {
|
class ToolsItemData {
|
||||||
@ -577,12 +576,11 @@ class ToolsUIModel extends _$ToolsUIModel {
|
|||||||
if (!ok) return;
|
if (!ok) return;
|
||||||
try {
|
try {
|
||||||
state = state.copyWith(working: true);
|
state = state.copyWith(working: true);
|
||||||
final aria2cManager = ref.read(aria2cModelProvider.notifier);
|
final downloadManager = ref.read(downloadManagerProvider.notifier);
|
||||||
await aria2cManager.launchDaemon(appGlobalState.applicationBinaryModuleDir!);
|
await downloadManager.initDownloader();
|
||||||
final aria2c = ref.read(aria2cModelProvider).aria2c!;
|
|
||||||
|
|
||||||
// check download task list
|
// check download task list
|
||||||
if (await aria2cManager.isNameInTask("Data.p4k")) {
|
if (await downloadManager.isNameInTask("Data.p4k")) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
showToast(context, S.current.tools_action_info_p4k_download_in_progress);
|
showToast(context, S.current.tools_action_info_p4k_download_in_progress);
|
||||||
state = state.copyWith(working: false);
|
state = state.copyWith(working: false);
|
||||||
@ -619,12 +617,10 @@ class ToolsUIModel extends _$ToolsUIModel {
|
|||||||
state = state.copyWith(working: false);
|
state = state.copyWith(working: false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final b64Str = base64Encode(btData.data!);
|
|
||||||
|
|
||||||
final gid = await aria2c.addTorrent(b64Str, extraParams: {"dir": savePath});
|
final taskId = await downloadManager.addTorrent(btData.data!, outputFolder: savePath);
|
||||||
state = state.copyWith(working: false);
|
state = state.copyWith(working: false);
|
||||||
dPrint("Aria2cManager.aria2c.addUri resp === $gid");
|
dPrint("DownloadManager.addTorrent resp === $taskId");
|
||||||
await aria2c.saveSession();
|
|
||||||
AnalyticsApi.touch("p4k_download");
|
AnalyticsApi.touch("p4k_download");
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
context.push("/index/downloader");
|
context.push("/index/downloader");
|
||||||
|
|||||||
@ -41,7 +41,7 @@ final class ToolsUIModelProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$toolsUIModelHash() => r'ee1de3d555443f72b4fbb395a5728b2de1e8aaf4';
|
String _$toolsUIModelHash() => r'17890d6d16d8e9d98c42d06d9e6c6165965bcee0';
|
||||||
|
|
||||||
abstract class _$ToolsUIModel extends $Notifier<ToolsUIState> {
|
abstract class _$ToolsUIModel extends $Notifier<ToolsUIState> {
|
||||||
ToolsUIState build();
|
ToolsUIState build();
|
||||||
|
|||||||
17
pubspec.lock
17
pubspec.lock
@ -57,15 +57,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.7.0"
|
version: "2.7.0"
|
||||||
aria2:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: HEAD
|
|
||||||
resolved-ref: b274c4c25e7ab49940b43d20e2fd335cfeef1c37
|
|
||||||
url: "https://github.com/xkeyC/dart_aria2_rpc.git"
|
|
||||||
source: git
|
|
||||||
version: "0.1.3"
|
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -774,14 +765,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.9.0"
|
version: "4.9.0"
|
||||||
json_rpc_2:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: json_rpc_2
|
|
||||||
sha256: "246b321532f0e8e2ba474b4d757eaa558ae4fdd0688fdbc1e1ca9705f9b8ca0e"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.3"
|
|
||||||
json_serializable:
|
json_serializable:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -55,9 +55,7 @@ dependencies:
|
|||||||
fixnum: ^1.1.1
|
fixnum: ^1.1.1
|
||||||
rust_builder:
|
rust_builder:
|
||||||
path: rust_builder
|
path: rust_builder
|
||||||
aria2:
|
# aria2 has been replaced by rqbit (Rust-based torrent library)
|
||||||
git: https://github.com/xkeyC/dart_aria2_rpc.git
|
|
||||||
# path: ../../xkeyC/dart_aria2_rpc
|
|
||||||
intl: ^0.20.2
|
intl: ^0.20.2
|
||||||
synchronized: ^3.4.0
|
synchronized: ^3.4.0
|
||||||
super_sliver_list: ^0.4.1
|
super_sliver_list: ^0.4.1
|
||||||
|
|||||||
986
rust/Cargo.lock
generated
986
rust/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -35,6 +35,10 @@ unp4k_rs = { git = "https://github.com/StarCitizenToolBox/unp4k_rs", tag = "V0.0
|
|||||||
uuid = { version = "1.19.0", features = ["v4"] }
|
uuid = { version = "1.19.0", features = ["v4"] }
|
||||||
parking_lot = "0.12.5"
|
parking_lot = "0.12.5"
|
||||||
crossbeam-channel = "0.5.15"
|
crossbeam-channel = "0.5.15"
|
||||||
|
librqbit = { git = "https://github.com/StarCitizenToolBox/rqbit", tag = "webseed-v0.0.1" }
|
||||||
|
tracing = "0.1"
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
bytes = "1.10"
|
||||||
|
|
||||||
# WebView
|
# WebView
|
||||||
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||||
|
|||||||
513
rust/src/api/downloader_api.rs
Normal file
513
rust/src/api/downloader_api.rs
Normal file
@ -0,0 +1,513 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::{bail, Context, Result};
|
||||||
|
use bytes::Bytes;
|
||||||
|
use flutter_rust_bridge::frb;
|
||||||
|
use librqbit::{
|
||||||
|
AddTorrent, AddTorrentOptions, AddTorrentResponse, Session, SessionOptions,
|
||||||
|
TorrentStats, ManagedTorrent, TorrentStatsState,
|
||||||
|
};
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
// Type alias for ManagedTorrentHandle
|
||||||
|
type ManagedTorrentHandle = Arc<ManagedTorrent>;
|
||||||
|
|
||||||
|
// Global session instance
|
||||||
|
static SESSION: OnceCell<Arc<Session>> = OnceCell::new();
|
||||||
|
static SESSION_INIT_LOCK: once_cell::sync::Lazy<Mutex<()>> =
|
||||||
|
once_cell::sync::Lazy::new(|| Mutex::new(()));
|
||||||
|
|
||||||
|
// Store torrent handles
|
||||||
|
static TORRENT_HANDLES: once_cell::sync::Lazy<RwLock<HashMap<usize, ManagedTorrentHandle>>> =
|
||||||
|
once_cell::sync::Lazy::new(|| RwLock::new(HashMap::new()));
|
||||||
|
|
||||||
|
// Store output folders for each task
|
||||||
|
static TASK_OUTPUT_FOLDERS: once_cell::sync::Lazy<RwLock<HashMap<usize, String>>> =
|
||||||
|
once_cell::sync::Lazy::new(|| RwLock::new(HashMap::new()));
|
||||||
|
|
||||||
|
/// Download task status
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum DownloadTaskStatus {
|
||||||
|
Initializing,
|
||||||
|
Live,
|
||||||
|
Paused,
|
||||||
|
Error,
|
||||||
|
Finished,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Download task information
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DownloadTaskInfo {
|
||||||
|
pub id: usize,
|
||||||
|
pub name: String,
|
||||||
|
pub status: DownloadTaskStatus,
|
||||||
|
pub total_bytes: u64,
|
||||||
|
pub downloaded_bytes: u64,
|
||||||
|
pub uploaded_bytes: u64,
|
||||||
|
pub download_speed: u64,
|
||||||
|
pub upload_speed: u64,
|
||||||
|
pub progress: f64,
|
||||||
|
pub num_peers: usize,
|
||||||
|
pub output_folder: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Global statistics
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct DownloadGlobalStat {
|
||||||
|
pub download_speed: u64,
|
||||||
|
pub upload_speed: u64,
|
||||||
|
pub num_active: usize,
|
||||||
|
pub num_waiting: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the download manager session
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn downloader_init(download_dir: String) -> Result<()> {
|
||||||
|
// Already initialized
|
||||||
|
if SESSION.get().is_some() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let rt = tokio::runtime::Handle::current();
|
||||||
|
rt.block_on(async {
|
||||||
|
let _lock = SESSION_INIT_LOCK.lock().await;
|
||||||
|
|
||||||
|
// Double check after acquiring lock
|
||||||
|
if SESSION.get().is_some() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let output_folder = PathBuf::from(&download_dir);
|
||||||
|
std::fs::create_dir_all(&output_folder)?;
|
||||||
|
|
||||||
|
let session = Session::new_with_opts(
|
||||||
|
output_folder,
|
||||||
|
SessionOptions {
|
||||||
|
disable_dht: false,
|
||||||
|
disable_dht_persistence: true,
|
||||||
|
persistence: None,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.context("Failed to create rqbit session")?;
|
||||||
|
|
||||||
|
SESSION
|
||||||
|
.set(session)
|
||||||
|
.map_err(|_| anyhow::anyhow!("Session already initialized"))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the downloader is initialized
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn downloader_is_initialized() -> bool {
|
||||||
|
SESSION.get().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a torrent from bytes (e.g., .torrent file content)
|
||||||
|
pub async fn downloader_add_torrent(
|
||||||
|
torrent_bytes: Vec<u8>,
|
||||||
|
output_folder: Option<String>,
|
||||||
|
trackers: Option<Vec<String>>,
|
||||||
|
) -> Result<usize> {
|
||||||
|
let session = SESSION
|
||||||
|
.get()
|
||||||
|
.context("Downloader not initialized. Call downloader_init first.")?;
|
||||||
|
|
||||||
|
let bytes = Bytes::from(torrent_bytes);
|
||||||
|
let add_torrent = AddTorrent::from_bytes(bytes);
|
||||||
|
|
||||||
|
let mut opts = AddTorrentOptions {
|
||||||
|
overwrite: true,
|
||||||
|
paused: false,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(ref folder) = output_folder {
|
||||||
|
opts.output_folder = Some(folder.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tracker_list) = trackers {
|
||||||
|
opts.trackers = Some(tracker_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = session
|
||||||
|
.add_torrent(add_torrent, Some(opts))
|
||||||
|
.await
|
||||||
|
.context("Failed to add torrent")?;
|
||||||
|
|
||||||
|
match response {
|
||||||
|
AddTorrentResponse::Added(id, handle) => {
|
||||||
|
// Store output folder
|
||||||
|
if let Some(folder) = output_folder.clone() {
|
||||||
|
TASK_OUTPUT_FOLDERS.write().insert(id, folder);
|
||||||
|
}
|
||||||
|
TORRENT_HANDLES.write().insert(id, handle);
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
AddTorrentResponse::AlreadyManaged(id, handle) => {
|
||||||
|
if let Some(folder) = output_folder.clone() {
|
||||||
|
TASK_OUTPUT_FOLDERS.write().insert(id, folder);
|
||||||
|
}
|
||||||
|
TORRENT_HANDLES.write().insert(id, handle);
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
AddTorrentResponse::ListOnly(_) => {
|
||||||
|
bail!("Torrent was only listed, not added")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a torrent from a magnet link
|
||||||
|
pub async fn downloader_add_magnet(
|
||||||
|
magnet_link: String,
|
||||||
|
output_folder: Option<String>,
|
||||||
|
trackers: Option<Vec<String>>,
|
||||||
|
) -> Result<usize> {
|
||||||
|
let session = SESSION
|
||||||
|
.get()
|
||||||
|
.context("Downloader not initialized. Call downloader_init first.")?;
|
||||||
|
|
||||||
|
// Check if it's a magnet link
|
||||||
|
if !magnet_link.starts_with("magnet:") {
|
||||||
|
bail!("Invalid magnet link. Must start with 'magnet:'");
|
||||||
|
}
|
||||||
|
|
||||||
|
let add_torrent = AddTorrent::from_url(magnet_link);
|
||||||
|
|
||||||
|
let mut opts = AddTorrentOptions {
|
||||||
|
overwrite: true,
|
||||||
|
paused: false,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(ref folder) = output_folder {
|
||||||
|
opts.output_folder = Some(folder.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tracker_list) = trackers {
|
||||||
|
opts.trackers = Some(tracker_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = session
|
||||||
|
.add_torrent(add_torrent, Some(opts))
|
||||||
|
.await
|
||||||
|
.context("Failed to add magnet")?;
|
||||||
|
|
||||||
|
match response {
|
||||||
|
AddTorrentResponse::Added(id, handle) => {
|
||||||
|
if let Some(folder) = output_folder.clone() {
|
||||||
|
TASK_OUTPUT_FOLDERS.write().insert(id, folder);
|
||||||
|
}
|
||||||
|
TORRENT_HANDLES.write().insert(id, handle);
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
AddTorrentResponse::AlreadyManaged(id, handle) => {
|
||||||
|
if let Some(folder) = output_folder.clone() {
|
||||||
|
TASK_OUTPUT_FOLDERS.write().insert(id, folder);
|
||||||
|
}
|
||||||
|
TORRENT_HANDLES.write().insert(id, handle);
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
AddTorrentResponse::ListOnly(_) => {
|
||||||
|
bail!("Magnet was only listed, not added")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a torrent from URL (HTTP download not supported, only torrent file URLs)
|
||||||
|
pub async fn downloader_add_url(
|
||||||
|
url: String,
|
||||||
|
output_folder: Option<String>,
|
||||||
|
trackers: Option<Vec<String>>,
|
||||||
|
) -> Result<usize> {
|
||||||
|
// Check if it's a magnet link
|
||||||
|
if url.starts_with("magnet:") {
|
||||||
|
return downloader_add_magnet(url, output_folder, trackers).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a torrent file URL
|
||||||
|
if url.starts_with("http://") || url.starts_with("https://") {
|
||||||
|
// Download the torrent file first
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let response = client
|
||||||
|
.get(&url)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.context("Failed to download torrent file")?;
|
||||||
|
|
||||||
|
if !response.status().is_success() {
|
||||||
|
bail!("Failed to download torrent file: HTTP {}", response.status());
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = response
|
||||||
|
.bytes()
|
||||||
|
.await
|
||||||
|
.context("Failed to read torrent file content")?;
|
||||||
|
|
||||||
|
return downloader_add_torrent(bytes.to_vec(), output_folder, trackers).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
bail!("HTTP downloads are not supported. Only BitTorrent (magnet links and .torrent files) are supported.")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pause a download task
|
||||||
|
pub async fn downloader_pause(task_id: usize) -> Result<()> {
|
||||||
|
let session = SESSION
|
||||||
|
.get()
|
||||||
|
.context("Downloader not initialized")?;
|
||||||
|
|
||||||
|
let handle = {
|
||||||
|
let handles = TORRENT_HANDLES.read();
|
||||||
|
handles.get(&task_id).cloned()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(handle) = handle {
|
||||||
|
session.pause(&handle).await.context("Failed to pause torrent")?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
bail!("Task not found: {}", task_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resume a download task
|
||||||
|
pub async fn downloader_resume(task_id: usize) -> Result<()> {
|
||||||
|
let session = SESSION
|
||||||
|
.get()
|
||||||
|
.context("Downloader not initialized")?;
|
||||||
|
|
||||||
|
let handle = {
|
||||||
|
let handles = TORRENT_HANDLES.read();
|
||||||
|
handles.get(&task_id).cloned()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(handle) = handle {
|
||||||
|
session.unpause(&handle).await.context("Failed to resume torrent")?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
bail!("Task not found: {}", task_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a download task
|
||||||
|
pub async fn downloader_remove(task_id: usize, delete_files: bool) -> Result<()> {
|
||||||
|
let session = SESSION
|
||||||
|
.get()
|
||||||
|
.context("Downloader not initialized")?;
|
||||||
|
|
||||||
|
session
|
||||||
|
.delete(librqbit::api::TorrentIdOrHash::Id(task_id), delete_files)
|
||||||
|
.await
|
||||||
|
.context("Failed to remove torrent")?;
|
||||||
|
|
||||||
|
TORRENT_HANDLES.write().remove(&task_id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get information about a specific task
|
||||||
|
pub async fn downloader_get_task_info(task_id: usize) -> Result<DownloadTaskInfo> {
|
||||||
|
let handle = {
|
||||||
|
let handles = TORRENT_HANDLES.read();
|
||||||
|
handles.get(&task_id).cloned()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(handle) = handle {
|
||||||
|
let stats = handle.stats();
|
||||||
|
let name = handle.name().unwrap_or_else(|| format!("Task {}", task_id));
|
||||||
|
let output_folder = TASK_OUTPUT_FOLDERS
|
||||||
|
.read()
|
||||||
|
.get(&task_id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let status = get_task_status(&stats);
|
||||||
|
let progress = if stats.total_bytes > 0 {
|
||||||
|
stats.progress_bytes as f64 / stats.total_bytes as f64
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get speed from live stats
|
||||||
|
let (download_speed, upload_speed, num_peers) = if let Some(live) = &stats.live {
|
||||||
|
let down = (live.download_speed.mbps * 1024.0 * 1024.0 / 8.0) as u64;
|
||||||
|
let up = (live.upload_speed.mbps * 1024.0 * 1024.0 / 8.0) as u64;
|
||||||
|
let peers = (live.snapshot.peer_stats.queued + live.snapshot.peer_stats.connecting + live.snapshot.peer_stats.live) as usize;
|
||||||
|
(down, up, peers)
|
||||||
|
} else {
|
||||||
|
(0, 0, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(DownloadTaskInfo {
|
||||||
|
id: task_id,
|
||||||
|
name,
|
||||||
|
status,
|
||||||
|
total_bytes: stats.total_bytes,
|
||||||
|
downloaded_bytes: stats.progress_bytes,
|
||||||
|
uploaded_bytes: stats.uploaded_bytes,
|
||||||
|
download_speed,
|
||||||
|
upload_speed,
|
||||||
|
progress,
|
||||||
|
num_peers,
|
||||||
|
output_folder,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
bail!("Task not found: {}", task_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_task_status(stats: &TorrentStats) -> DownloadTaskStatus {
|
||||||
|
if stats.error.is_some() {
|
||||||
|
return DownloadTaskStatus::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if stats.finished {
|
||||||
|
return DownloadTaskStatus::Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
match stats.state {
|
||||||
|
TorrentStatsState::Initializing => DownloadTaskStatus::Initializing,
|
||||||
|
TorrentStatsState::Live => DownloadTaskStatus::Live,
|
||||||
|
TorrentStatsState::Paused => DownloadTaskStatus::Paused,
|
||||||
|
TorrentStatsState::Error => DownloadTaskStatus::Error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all tasks
|
||||||
|
pub async fn downloader_get_all_tasks() -> Result<Vec<DownloadTaskInfo>> {
|
||||||
|
let session = SESSION.get();
|
||||||
|
if session.is_none() {
|
||||||
|
return Ok(vec![]);
|
||||||
|
}
|
||||||
|
let session = session.unwrap();
|
||||||
|
|
||||||
|
// Use RwLock to collect tasks since with_torrents takes Fn (not FnMut)
|
||||||
|
let tasks: RwLock<Vec<DownloadTaskInfo>> = RwLock::new(Vec::new());
|
||||||
|
|
||||||
|
session.with_torrents(|torrents| {
|
||||||
|
for (id, handle) in torrents {
|
||||||
|
let stats = handle.stats();
|
||||||
|
let name = handle.name().unwrap_or_else(|| format!("Task {}", id));
|
||||||
|
let output_folder = TASK_OUTPUT_FOLDERS
|
||||||
|
.read()
|
||||||
|
.get(&id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let status = get_task_status(&stats);
|
||||||
|
let progress = if stats.total_bytes > 0 {
|
||||||
|
stats.progress_bytes as f64 / stats.total_bytes as f64
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get speed from live stats
|
||||||
|
let (download_speed, upload_speed, num_peers) = if let Some(live) = &stats.live {
|
||||||
|
let down = (live.download_speed.mbps * 1024.0 * 1024.0 / 8.0) as u64;
|
||||||
|
let up = (live.upload_speed.mbps * 1024.0 * 1024.0 / 8.0) as u64;
|
||||||
|
let peers = (live.snapshot.peer_stats.queued + live.snapshot.peer_stats.connecting + live.snapshot.peer_stats.live) as usize;
|
||||||
|
(down, up, peers)
|
||||||
|
} else {
|
||||||
|
(0, 0, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
tasks.write().push(DownloadTaskInfo {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
status,
|
||||||
|
total_bytes: stats.total_bytes,
|
||||||
|
downloaded_bytes: stats.progress_bytes,
|
||||||
|
uploaded_bytes: stats.uploaded_bytes,
|
||||||
|
download_speed,
|
||||||
|
upload_speed,
|
||||||
|
progress,
|
||||||
|
num_peers,
|
||||||
|
output_folder,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update handles cache
|
||||||
|
TORRENT_HANDLES.write().insert(id, handle.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(tasks.into_inner())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get global statistics
|
||||||
|
pub async fn downloader_get_global_stats() -> Result<DownloadGlobalStat> {
|
||||||
|
let tasks = downloader_get_all_tasks().await?;
|
||||||
|
|
||||||
|
let mut stat = DownloadGlobalStat::default();
|
||||||
|
|
||||||
|
for task in &tasks {
|
||||||
|
stat.download_speed += task.download_speed;
|
||||||
|
stat.upload_speed += task.upload_speed;
|
||||||
|
|
||||||
|
match task.status {
|
||||||
|
DownloadTaskStatus::Live => stat.num_active += 1,
|
||||||
|
DownloadTaskStatus::Paused | DownloadTaskStatus::Initializing => stat.num_waiting += 1,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(stat)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a task with given name exists
|
||||||
|
pub async fn downloader_is_name_in_task(name: String) -> bool {
|
||||||
|
if let Ok(tasks) = downloader_get_all_tasks().await {
|
||||||
|
for task in tasks {
|
||||||
|
if task.name.contains(&name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pause all tasks
|
||||||
|
pub async fn downloader_pause_all() -> Result<()> {
|
||||||
|
let session = SESSION
|
||||||
|
.get()
|
||||||
|
.context("Downloader not initialized")?;
|
||||||
|
|
||||||
|
let handles: Vec<_> = TORRENT_HANDLES.read().values().cloned().collect();
|
||||||
|
|
||||||
|
for handle in handles {
|
||||||
|
let _ = session.pause(&handle).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resume all tasks
|
||||||
|
pub async fn downloader_resume_all() -> Result<()> {
|
||||||
|
let session = SESSION
|
||||||
|
.get()
|
||||||
|
.context("Downloader not initialized")?;
|
||||||
|
|
||||||
|
let handles: Vec<_> = TORRENT_HANDLES.read().values().cloned().collect();
|
||||||
|
|
||||||
|
for handle in handles {
|
||||||
|
let _ = session.unpause(&handle).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stop the downloader session
|
||||||
|
pub async fn downloader_stop() -> Result<()> {
|
||||||
|
if let Some(session) = SESSION.get() {
|
||||||
|
session.stop().await;
|
||||||
|
}
|
||||||
|
TORRENT_HANDLES.write().clear();
|
||||||
|
TASK_OUTPUT_FOLDERS.write().clear();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@ -8,3 +8,4 @@ pub mod asar_api;
|
|||||||
pub mod ort_api;
|
pub mod ort_api;
|
||||||
pub mod unp4k_api;
|
pub mod unp4k_api;
|
||||||
pub mod webview_api;
|
pub mod webview_api;
|
||||||
|
pub mod downloader_api;
|
||||||
|
|||||||
@ -302,7 +302,7 @@ pub fn get_gpu_info_from_registry() -> anyhow::Result<String> {
|
|||||||
|
|
||||||
/// Resolve shortcut (.lnk) file to get target path
|
/// Resolve shortcut (.lnk) file to get target path
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub fn resolve_shortcut(lnk_path: &str) -> anyhow::Result<String> {
|
pub fn resolve_shortcut(lnk_path: String) -> anyhow::Result<String> {
|
||||||
use windows::core::{HSTRING, Interface};
|
use windows::core::{HSTRING, Interface};
|
||||||
use windows::Win32::System::Com::{
|
use windows::Win32::System::Com::{
|
||||||
CoCreateInstance, CoInitializeEx, CoUninitialize,
|
CoCreateInstance, CoInitializeEx, CoUninitialize,
|
||||||
@ -327,7 +327,7 @@ pub fn resolve_shortcut(lnk_path: &str) -> anyhow::Result<String> {
|
|||||||
let persist_file: IPersistFile = shell_link.cast()?;
|
let persist_file: IPersistFile = shell_link.cast()?;
|
||||||
|
|
||||||
// Load the shortcut file
|
// Load the shortcut file
|
||||||
let lnk_path_w = HSTRING::from(lnk_path);
|
let lnk_path_w = HSTRING::from(&lnk_path);
|
||||||
persist_file.Load(windows::core::PCWSTR(lnk_path_w.as_ptr()), STGM_READ)?;
|
persist_file.Load(windows::core::PCWSTR(lnk_path_w.as_ptr()), STGM_READ)?;
|
||||||
|
|
||||||
// Get target path
|
// Get target path
|
||||||
@ -351,7 +351,7 @@ pub fn resolve_shortcut(lnk_path: &str) -> anyhow::Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
pub fn resolve_shortcut(_: &str) -> anyhow::Result<String> {
|
pub fn resolve_shortcut(_lnk_path: String) -> anyhow::Result<String> {
|
||||||
Ok(String::new())
|
Ok(String::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user