mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-01-15 04:30:28 +00:00
feat: AdaptiveConcurrencyController
This commit is contained in:
parent
3c60b5a2c1
commit
8898569067
@ -32,6 +32,18 @@ Future<void> downloaderInit({
|
|||||||
bool downloaderIsInitialized() =>
|
bool downloaderIsInitialized() =>
|
||||||
RustLib.instance.api.crateApiDownloaderApiDownloaderIsInitialized();
|
RustLib.instance.api.crateApiDownloaderApiDownloaderIsInitialized();
|
||||||
|
|
||||||
|
/// Check if there are pending tasks to restore from session file (without starting the downloader)
|
||||||
|
/// This reads the session.json file directly to check if there are any torrents saved.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - working_dir: The directory where session data is stored (same as passed to downloader_init)
|
||||||
|
///
|
||||||
|
/// Returns: true if there are tasks to restore, false otherwise
|
||||||
|
bool downloaderHasPendingSessionTasks({required String workingDir}) =>
|
||||||
|
RustLib.instance.api.crateApiDownloaderApiDownloaderHasPendingSessionTasks(
|
||||||
|
workingDir: workingDir,
|
||||||
|
);
|
||||||
|
|
||||||
/// Add a torrent from bytes (e.g., .torrent file content)
|
/// Add a torrent from bytes (e.g., .torrent file content)
|
||||||
Future<BigInt> downloaderAddTorrent({
|
Future<BigInt> downloaderAddTorrent({
|
||||||
required List<int> torrentBytes,
|
required List<int> torrentBytes,
|
||||||
@ -118,6 +130,17 @@ Future<void> downloaderStop() =>
|
|||||||
Future<void> downloaderShutdown() =>
|
Future<void> downloaderShutdown() =>
|
||||||
RustLib.instance.api.crateApiDownloaderApiDownloaderShutdown();
|
RustLib.instance.api.crateApiDownloaderApiDownloaderShutdown();
|
||||||
|
|
||||||
|
/// Get all completed tasks from cache (tasks removed by downloader_remove_completed_tasks)
|
||||||
|
/// This cache is cleared when the downloader is shutdown/restarted
|
||||||
|
List<DownloadTaskInfo> downloaderGetCompletedTasksCache() => RustLib
|
||||||
|
.instance
|
||||||
|
.api
|
||||||
|
.crateApiDownloaderApiDownloaderGetCompletedTasksCache();
|
||||||
|
|
||||||
|
/// Clear the completed tasks cache manually
|
||||||
|
void downloaderClearCompletedTasksCache() => RustLib.instance.api
|
||||||
|
.crateApiDownloaderApiDownloaderClearCompletedTasksCache();
|
||||||
|
|
||||||
/// Update global speed limits
|
/// Update global speed limits
|
||||||
/// Note: rqbit Session doesn't support runtime limit changes,
|
/// Note: rqbit Session doesn't support runtime limit changes,
|
||||||
/// this function is a placeholder that returns an error.
|
/// this function is a placeholder that returns an error.
|
||||||
@ -131,6 +154,7 @@ Future<void> downloaderUpdateSpeedLimits({
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Remove all completed tasks (equivalent to aria2's --seed-time=0 behavior)
|
/// Remove all completed tasks (equivalent to aria2's --seed-time=0 behavior)
|
||||||
|
/// Removed tasks are cached in memory and can be queried via downloader_get_completed_tasks_cache
|
||||||
Future<int> downloaderRemoveCompletedTasks() =>
|
Future<int> downloaderRemoveCompletedTasks() =>
|
||||||
RustLib.instance.api.crateApiDownloaderApiDownloaderRemoveCompletedTasks();
|
RustLib.instance.api.crateApiDownloaderApiDownloaderRemoveCompletedTasks();
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
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({
|
||||||
@ -20,21 +21,27 @@ 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,
|
||||||
@ -58,16 +65,19 @@ 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,
|
||||||
@ -76,12 +86,14 @@ 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,
|
||||||
@ -90,12 +102,15 @@ 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();
|
||||||
|
|
||||||
|
|||||||
@ -72,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 => -641930410;
|
int get rustContentHash => -1482626931;
|
||||||
|
|
||||||
static const kDefaultExternalLibraryLoaderConfig =
|
static const kDefaultExternalLibraryLoaderConfig =
|
||||||
ExternalLibraryLoaderConfig(
|
ExternalLibraryLoaderConfig(
|
||||||
@ -118,8 +118,13 @@ abstract class RustLibApi extends BaseApi {
|
|||||||
List<String>? trackers,
|
List<String>? trackers,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
void crateApiDownloaderApiDownloaderClearCompletedTasksCache();
|
||||||
|
|
||||||
Future<List<DownloadTaskInfo>> crateApiDownloaderApiDownloaderGetAllTasks();
|
Future<List<DownloadTaskInfo>> crateApiDownloaderApiDownloaderGetAllTasks();
|
||||||
|
|
||||||
|
List<DownloadTaskInfo>
|
||||||
|
crateApiDownloaderApiDownloaderGetCompletedTasksCache();
|
||||||
|
|
||||||
Future<DownloadGlobalStat> crateApiDownloaderApiDownloaderGetGlobalStats();
|
Future<DownloadGlobalStat> crateApiDownloaderApiDownloaderGetGlobalStats();
|
||||||
|
|
||||||
Future<DownloadTaskInfo> crateApiDownloaderApiDownloaderGetTaskInfo({
|
Future<DownloadTaskInfo> crateApiDownloaderApiDownloaderGetTaskInfo({
|
||||||
@ -128,6 +133,10 @@ abstract class RustLibApi extends BaseApi {
|
|||||||
|
|
||||||
Future<bool> crateApiDownloaderApiDownloaderHasActiveTasks();
|
Future<bool> crateApiDownloaderApiDownloaderHasActiveTasks();
|
||||||
|
|
||||||
|
bool crateApiDownloaderApiDownloaderHasPendingSessionTasks({
|
||||||
|
required String workingDir,
|
||||||
|
});
|
||||||
|
|
||||||
Future<void> crateApiDownloaderApiDownloaderInit({
|
Future<void> crateApiDownloaderApiDownloaderInit({
|
||||||
required String workingDir,
|
required String workingDir,
|
||||||
required String defaultDownloadDir,
|
required String defaultDownloadDir,
|
||||||
@ -633,6 +642,33 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
argNames: ["url", "outputFolder", "trackers"],
|
argNames: ["url", "outputFolder", "trackers"],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void crateApiDownloaderApiDownloaderClearCompletedTasksCache() {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__downloader_api__downloader_clear_completed_tasks_cache();
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_unit,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta:
|
||||||
|
kCrateApiDownloaderApiDownloaderClearCompletedTasksCacheConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta
|
||||||
|
get kCrateApiDownloaderApiDownloaderClearCompletedTasksCacheConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_clear_completed_tasks_cache",
|
||||||
|
argNames: [],
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<DownloadTaskInfo>> crateApiDownloaderApiDownloaderGetAllTasks() {
|
Future<List<DownloadTaskInfo>> crateApiDownloaderApiDownloaderGetAllTasks() {
|
||||||
return handler.executeNormal(
|
return handler.executeNormal(
|
||||||
@ -657,6 +693,34 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
TaskConstMeta get kCrateApiDownloaderApiDownloaderGetAllTasksConstMeta =>
|
TaskConstMeta get kCrateApiDownloaderApiDownloaderGetAllTasksConstMeta =>
|
||||||
const TaskConstMeta(debugName: "downloader_get_all_tasks", argNames: []);
|
const TaskConstMeta(debugName: "downloader_get_all_tasks", argNames: []);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<DownloadTaskInfo>
|
||||||
|
crateApiDownloaderApiDownloaderGetCompletedTasksCache() {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__downloader_api__downloader_get_completed_tasks_cache();
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_list_download_task_info,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta:
|
||||||
|
kCrateApiDownloaderApiDownloaderGetCompletedTasksCacheConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta
|
||||||
|
get kCrateApiDownloaderApiDownloaderGetCompletedTasksCacheConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_get_completed_tasks_cache",
|
||||||
|
argNames: [],
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<DownloadGlobalStat> crateApiDownloaderApiDownloaderGetGlobalStats() {
|
Future<DownloadGlobalStat> crateApiDownloaderApiDownloaderGetGlobalStats() {
|
||||||
return handler.executeNormal(
|
return handler.executeNormal(
|
||||||
@ -742,6 +806,38 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
argNames: [],
|
argNames: [],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool crateApiDownloaderApiDownloaderHasPendingSessionTasks({
|
||||||
|
required String workingDir,
|
||||||
|
}) {
|
||||||
|
return handler.executeSync(
|
||||||
|
SyncTask(
|
||||||
|
callFfi: () {
|
||||||
|
var arg0 = cst_encode_String(workingDir);
|
||||||
|
return wire
|
||||||
|
.wire__crate__api__downloader_api__downloader_has_pending_session_tasks(
|
||||||
|
arg0,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_bool,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta:
|
||||||
|
kCrateApiDownloaderApiDownloaderHasPendingSessionTasksConstMeta,
|
||||||
|
argValues: [workingDir],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta
|
||||||
|
get kCrateApiDownloaderApiDownloaderHasPendingSessionTasksConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "downloader_has_pending_session_tasks",
|
||||||
|
argNames: ["workingDir"],
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> crateApiDownloaderApiDownloaderInit({
|
Future<void> crateApiDownloaderApiDownloaderInit({
|
||||||
required String workingDir,
|
required String workingDir,
|
||||||
|
|||||||
@ -1321,6 +1321,19 @@ class RustLibWire implements BaseWire {
|
|||||||
)
|
)
|
||||||
>();
|
>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco
|
||||||
|
wire__crate__api__downloader_api__downloader_clear_completed_tasks_cache() {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_clear_completed_tasks_cache();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_clear_completed_tasks_cachePtr =
|
||||||
|
_lookup<ffi.NativeFunction<WireSyncRust2DartDco Function()>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_clear_completed_tasks_cache',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_clear_completed_tasks_cache =
|
||||||
|
_wire__crate__api__downloader_api__downloader_clear_completed_tasks_cachePtr
|
||||||
|
.asFunction<WireSyncRust2DartDco Function()>();
|
||||||
|
|
||||||
void wire__crate__api__downloader_api__downloader_get_all_tasks(int port_) {
|
void wire__crate__api__downloader_api__downloader_get_all_tasks(int port_) {
|
||||||
return _wire__crate__api__downloader_api__downloader_get_all_tasks(port_);
|
return _wire__crate__api__downloader_api__downloader_get_all_tasks(port_);
|
||||||
}
|
}
|
||||||
@ -1333,6 +1346,19 @@ class RustLibWire implements BaseWire {
|
|||||||
_wire__crate__api__downloader_api__downloader_get_all_tasksPtr
|
_wire__crate__api__downloader_api__downloader_get_all_tasksPtr
|
||||||
.asFunction<void Function(int)>();
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco
|
||||||
|
wire__crate__api__downloader_api__downloader_get_completed_tasks_cache() {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_get_completed_tasks_cache();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_get_completed_tasks_cachePtr =
|
||||||
|
_lookup<ffi.NativeFunction<WireSyncRust2DartDco Function()>>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_get_completed_tasks_cache',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_get_completed_tasks_cache =
|
||||||
|
_wire__crate__api__downloader_api__downloader_get_completed_tasks_cachePtr
|
||||||
|
.asFunction<WireSyncRust2DartDco Function()>();
|
||||||
|
|
||||||
void wire__crate__api__downloader_api__downloader_get_global_stats(
|
void wire__crate__api__downloader_api__downloader_get_global_stats(
|
||||||
int port_,
|
int port_,
|
||||||
) {
|
) {
|
||||||
@ -1383,6 +1409,33 @@ class RustLibWire implements BaseWire {
|
|||||||
_wire__crate__api__downloader_api__downloader_has_active_tasksPtr
|
_wire__crate__api__downloader_api__downloader_has_active_tasksPtr
|
||||||
.asFunction<void Function(int)>();
|
.asFunction<void Function(int)>();
|
||||||
|
|
||||||
|
WireSyncRust2DartDco
|
||||||
|
wire__crate__api__downloader_api__downloader_has_pending_session_tasks(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> working_dir,
|
||||||
|
) {
|
||||||
|
return _wire__crate__api__downloader_api__downloader_has_pending_session_tasks(
|
||||||
|
working_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_has_pending_session_tasksPtr =
|
||||||
|
_lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
'frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_has_pending_session_tasks',
|
||||||
|
);
|
||||||
|
late final _wire__crate__api__downloader_api__downloader_has_pending_session_tasks =
|
||||||
|
_wire__crate__api__downloader_api__downloader_has_pending_session_tasksPtr
|
||||||
|
.asFunction<
|
||||||
|
WireSyncRust2DartDco Function(
|
||||||
|
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
|
||||||
|
)
|
||||||
|
>();
|
||||||
|
|
||||||
void wire__crate__api__downloader_api__downloader_init(
|
void wire__crate__api__downloader_api__downloader_init(
|
||||||
int port_,
|
int port_,
|
||||||
ffi.Pointer<wire_cst_list_prim_u_8_strict> working_dir,
|
ffi.Pointer<wire_cst_list_prim_u_8_strict> working_dir,
|
||||||
@ -2083,9 +2136,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 =
|
||||||
|
|||||||
@ -28,9 +28,10 @@ class S {
|
|||||||
static const AppLocalizationDelegate delegate = AppLocalizationDelegate();
|
static const AppLocalizationDelegate delegate = AppLocalizationDelegate();
|
||||||
|
|
||||||
static Future<S> load(Locale locale) {
|
static Future<S> load(Locale locale) {
|
||||||
final name = (locale.countryCode?.isEmpty ?? false)
|
final name =
|
||||||
? locale.languageCode
|
(locale.countryCode?.isEmpty ?? false)
|
||||||
: locale.toString();
|
? locale.languageCode
|
||||||
|
: locale.toString();
|
||||||
final localeName = Intl.canonicalizedLocale(name);
|
final localeName = Intl.canonicalizedLocale(name);
|
||||||
return initializeMessages(localeName).then((_) {
|
return initializeMessages(localeName).then((_) {
|
||||||
Intl.defaultLocale = localeName;
|
Intl.defaultLocale = localeName;
|
||||||
|
|||||||
@ -52,14 +52,14 @@ class DownloadManager extends _$DownloadManager {
|
|||||||
|
|
||||||
// Lazy load init
|
// Lazy load init
|
||||||
() async {
|
() async {
|
||||||
|
await Future.delayed(const Duration(milliseconds: 16));
|
||||||
try {
|
try {
|
||||||
// Check if there are existing tasks (check working dir for session data)
|
// Check if there are pending tasks to restore (without starting the downloader)
|
||||||
final dir = Directory(workingDir);
|
if (downloader_api.downloaderHasPendingSessionTasks(workingDir: workingDir)) {
|
||||||
if (await dir.exists()) {
|
dPrint("Launch download manager - found pending session tasks");
|
||||||
dPrint("Launch download manager");
|
|
||||||
await initDownloader();
|
await initDownloader();
|
||||||
} else {
|
} else {
|
||||||
dPrint("LazyLoad download manager");
|
dPrint("LazyLoad download manager - no pending tasks");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dPrint("DownloadManager.checkLazyLoad Error:$e");
|
dPrint("DownloadManager.checkLazyLoad Error:$e");
|
||||||
@ -246,4 +246,15 @@ class DownloadManager extends _$DownloadManager {
|
|||||||
}
|
}
|
||||||
return await downloader_api.downloaderHasActiveTasks();
|
return await downloader_api.downloaderHasActiveTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all completed tasks from cache (tasks that were removed by removeCompletedTasks)
|
||||||
|
/// This cache is cleared when the downloader is shutdown/restarted
|
||||||
|
List<downloader_api.DownloadTaskInfo> getCompletedTasksCache() {
|
||||||
|
return downloader_api.downloaderGetCompletedTasksCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the completed tasks cache manually
|
||||||
|
void clearCompletedTasksCache() {
|
||||||
|
downloader_api.downloaderClearCompletedTasksCache();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,7 +41,7 @@ final class DownloadManagerProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$downloadManagerHash() => r'f12d3fb1d7c03fdfccff7d07903218f38a860437';
|
String _$downloadManagerHash() => r'55c92224a5eb6bb0f84f0a97fd0585b94f61f711';
|
||||||
|
|
||||||
abstract class _$DownloadManager extends $Notifier<DownloadManagerState> {
|
abstract class _$DownloadManager extends $Notifier<DownloadManagerState> {
|
||||||
DownloadManagerState build();
|
DownloadManagerState build();
|
||||||
|
|||||||
@ -153,7 +153,7 @@ class HomeDownloaderUI extends HookConsumerWidget {
|
|||||||
const SizedBox(width: 32),
|
const SizedBox(width: 32),
|
||||||
if (type != "stopped")
|
if (type != "stopped")
|
||||||
DropDownButton(
|
DropDownButton(
|
||||||
closeAfterClick: false,
|
closeAfterClick: true,
|
||||||
title: Padding(
|
title: Padding(
|
||||||
padding: const EdgeInsets.all(3),
|
padding: const EdgeInsets.all(3),
|
||||||
child: Text(S.current.downloader_action_options),
|
child: Text(S.current.downloader_action_options),
|
||||||
|
|||||||
@ -42,7 +42,7 @@ final class HomeDownloaderUIModelProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$homeDownloaderUIModelHash() =>
|
String _$homeDownloaderUIModelHash() =>
|
||||||
r'567cf106d69ed24a5adb8d7f4ad9c422cf33dc1e';
|
r'bf7d095d761fff078de707562cf311c20db664d9';
|
||||||
|
|
||||||
abstract class _$HomeDownloaderUIModel
|
abstract class _$HomeDownloaderUIModel
|
||||||
extends $Notifier<HomeDownloaderUIState> {
|
extends $Notifier<HomeDownloaderUIState> {
|
||||||
|
|||||||
22
rust/Cargo.lock
generated
22
rust/Cargo.lock
generated
@ -2994,7 +2994,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit"
|
name = "librqbit"
|
||||||
version = "9.0.0-beta.1"
|
version = "9.0.0-beta.1"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -3058,7 +3058,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-bencode"
|
name = "librqbit-bencode"
|
||||||
version = "3.1.0"
|
version = "3.1.0"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
@ -3074,7 +3074,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-buffers"
|
name = "librqbit-buffers"
|
||||||
version = "4.2.0"
|
version = "4.2.0"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"librqbit-clone-to-owned",
|
"librqbit-clone-to-owned",
|
||||||
@ -3085,7 +3085,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-clone-to-owned"
|
name = "librqbit-clone-to-owned"
|
||||||
version = "3.0.1"
|
version = "3.0.1"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
]
|
]
|
||||||
@ -3093,7 +3093,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-core"
|
name = "librqbit-core"
|
||||||
version = "5.0.0"
|
version = "5.0.0"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -3122,7 +3122,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-dht"
|
name = "librqbit-dht"
|
||||||
version = "5.3.0"
|
version = "5.3.0"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"backon",
|
"backon",
|
||||||
@ -3169,7 +3169,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-lsd"
|
name = "librqbit-lsd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"atoi",
|
"atoi",
|
||||||
@ -3189,7 +3189,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-peer-protocol"
|
name = "librqbit-peer-protocol"
|
||||||
version = "4.3.0"
|
version = "4.3.0"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitvec",
|
"bitvec",
|
||||||
@ -3209,7 +3209,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-sha1-wrapper"
|
name = "librqbit-sha1-wrapper"
|
||||||
version = "4.1.0"
|
version = "4.1.0"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_cfg",
|
"assert_cfg",
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
@ -3218,7 +3218,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-tracker-comms"
|
name = "librqbit-tracker-comms"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -3246,7 +3246,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "librqbit-upnp"
|
name = "librqbit-upnp"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "git+https://github.com/StarCitizenToolBox/rqbit?tag=webseed-v0.0.2#7a9b4d7db84b7b9cccc424e294610cc800a9baa4"
|
source = "git+https://github.com/StarCitizenToolBox/rqbit?rev=f8c0b0927904e1d8b0e28e708bd69fd8069d413a#f8c0b0927904e1d8b0e28e708bd69fd8069d413a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bstr",
|
"bstr",
|
||||||
|
|||||||
@ -35,7 +35,7 @@ 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.2" }
|
librqbit = { git = "https://github.com/StarCitizenToolBox/rqbit", rev = "f8c0b0927904e1d8b0e28e708bd69fd8069d413a" }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
bytes = "1.10"
|
bytes = "1.10"
|
||||||
|
|||||||
@ -26,9 +26,9 @@ static SESSION_INIT_LOCK: once_cell::sync::Lazy<Mutex<()>> =
|
|||||||
static TORRENT_HANDLES: once_cell::sync::Lazy<RwLock<HashMap<usize, ManagedTorrentHandle>>> =
|
static TORRENT_HANDLES: once_cell::sync::Lazy<RwLock<HashMap<usize, ManagedTorrentHandle>>> =
|
||||||
once_cell::sync::Lazy::new(|| RwLock::new(HashMap::new()));
|
once_cell::sync::Lazy::new(|| RwLock::new(HashMap::new()));
|
||||||
|
|
||||||
// Store output folders for each task
|
// Store completed tasks info (in-memory cache, cleared on restart)
|
||||||
static TASK_OUTPUT_FOLDERS: once_cell::sync::Lazy<RwLock<HashMap<usize, String>>> =
|
static COMPLETED_TASKS_CACHE: once_cell::sync::Lazy<RwLock<Vec<DownloadTaskInfo>>> =
|
||||||
once_cell::sync::Lazy::new(|| RwLock::new(HashMap::new()));
|
once_cell::sync::Lazy::new(|| RwLock::new(Vec::new()));
|
||||||
|
|
||||||
/// Download task status
|
/// Download task status
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
@ -132,12 +132,15 @@ pub async fn downloader_init(
|
|||||||
},
|
},
|
||||||
webseed_config: Some(WebSeedConfig{
|
webseed_config: Some(WebSeedConfig{
|
||||||
max_concurrent_per_source: 32,
|
max_concurrent_per_source: 32,
|
||||||
max_total_concurrent: 128,
|
max_total_concurrent: 64,
|
||||||
request_timeout_secs: 30,
|
request_timeout_secs: 30,
|
||||||
prefer_for_large_gaps: true,
|
prefer_for_large_gaps: true,
|
||||||
min_gap_for_webseed: 10,
|
min_gap_for_webseed: 10,
|
||||||
max_errors_before_disable: 10,
|
max_errors_before_disable: 10,
|
||||||
disable_cooldown_secs: 600,
|
disable_cooldown_secs: 600,
|
||||||
|
adaptive_increase_threshold: 5,
|
||||||
|
adaptive_decrease_threshold: 10,
|
||||||
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
@ -156,6 +159,44 @@ pub fn downloader_is_initialized() -> bool {
|
|||||||
SESSION.read().is_some()
|
SESSION.read().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if there are pending tasks to restore from session file (without starting the downloader)
|
||||||
|
/// This reads the session.json file directly to check if there are any torrents saved.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - working_dir: The directory where session data is stored (same as passed to downloader_init)
|
||||||
|
///
|
||||||
|
/// Returns: true if there are tasks to restore, false otherwise
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn downloader_has_pending_session_tasks(working_dir: String) -> bool {
|
||||||
|
let session_file = PathBuf::from(&working_dir)
|
||||||
|
.join("rqbit-session")
|
||||||
|
.join("session.json");
|
||||||
|
|
||||||
|
if !session_file.exists() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read and parse the session file
|
||||||
|
match std::fs::read_to_string(&session_file) {
|
||||||
|
Ok(content) => {
|
||||||
|
// Parse as JSON to check if there are any torrents
|
||||||
|
// The structure is: { "torrents": { "0": {...}, "1": {...} } }
|
||||||
|
match serde_json::from_str::<serde_json::Value>(&content) {
|
||||||
|
Ok(json) => {
|
||||||
|
if let Some(torrents) = json.get("torrents") {
|
||||||
|
if let Some(obj) = torrents.as_object() {
|
||||||
|
return !obj.is_empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Err(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper function to get session
|
/// Helper function to get session
|
||||||
fn get_session() -> Result<Arc<Session>> {
|
fn get_session() -> Result<Arc<Session>> {
|
||||||
SESSION.read()
|
SESSION.read()
|
||||||
@ -195,17 +236,10 @@ pub async fn downloader_add_torrent(
|
|||||||
|
|
||||||
match response {
|
match response {
|
||||||
AddTorrentResponse::Added(id, handle) => {
|
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);
|
TORRENT_HANDLES.write().insert(id, handle);
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
AddTorrentResponse::AlreadyManaged(id, handle) => {
|
AddTorrentResponse::AlreadyManaged(id, handle) => {
|
||||||
if let Some(folder) = output_folder.clone() {
|
|
||||||
TASK_OUTPUT_FOLDERS.write().insert(id, folder);
|
|
||||||
}
|
|
||||||
TORRENT_HANDLES.write().insert(id, handle);
|
TORRENT_HANDLES.write().insert(id, handle);
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
@ -251,16 +285,10 @@ pub async fn downloader_add_magnet(
|
|||||||
|
|
||||||
match response {
|
match response {
|
||||||
AddTorrentResponse::Added(id, handle) => {
|
AddTorrentResponse::Added(id, handle) => {
|
||||||
if let Some(folder) = output_folder.clone() {
|
|
||||||
TASK_OUTPUT_FOLDERS.write().insert(id, folder);
|
|
||||||
}
|
|
||||||
TORRENT_HANDLES.write().insert(id, handle);
|
TORRENT_HANDLES.write().insert(id, handle);
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
AddTorrentResponse::AlreadyManaged(id, handle) => {
|
AddTorrentResponse::AlreadyManaged(id, handle) => {
|
||||||
if let Some(folder) = output_folder.clone() {
|
|
||||||
TASK_OUTPUT_FOLDERS.write().insert(id, folder);
|
|
||||||
}
|
|
||||||
TORRENT_HANDLES.write().insert(id, handle);
|
TORRENT_HANDLES.write().insert(id, handle);
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
@ -364,11 +392,13 @@ pub async fn downloader_get_task_info(task_id: usize) -> Result<DownloadTaskInfo
|
|||||||
if let Some(handle) = handle {
|
if let Some(handle) = handle {
|
||||||
let stats = handle.stats();
|
let stats = handle.stats();
|
||||||
let name = handle.name().unwrap_or_else(|| format!("Task {}", task_id));
|
let name = handle.name().unwrap_or_else(|| format!("Task {}", task_id));
|
||||||
let output_folder = TASK_OUTPUT_FOLDERS
|
// Get output_folder from handle's shared options
|
||||||
.read()
|
let output_folder = handle
|
||||||
.get(&task_id)
|
.shared()
|
||||||
.cloned()
|
.options
|
||||||
.unwrap_or_default();
|
.output_folder
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
|
||||||
let status = get_task_status(&stats);
|
let status = get_task_status(&stats);
|
||||||
let progress = if stats.total_bytes > 0 {
|
let progress = if stats.total_bytes > 0 {
|
||||||
@ -440,11 +470,13 @@ pub async fn downloader_get_all_tasks() -> Result<Vec<DownloadTaskInfo>> {
|
|||||||
for (id, handle) in torrents {
|
for (id, handle) in torrents {
|
||||||
let stats = handle.stats();
|
let stats = handle.stats();
|
||||||
let name = handle.name().unwrap_or_else(|| format!("Task {}", id));
|
let name = handle.name().unwrap_or_else(|| format!("Task {}", id));
|
||||||
let output_folder = TASK_OUTPUT_FOLDERS
|
// Get output_folder from handle's shared options
|
||||||
.read()
|
let output_folder = handle
|
||||||
.get(&id)
|
.shared()
|
||||||
.cloned()
|
.options
|
||||||
.unwrap_or_default();
|
.output_folder
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
|
||||||
let status = get_task_status(&stats);
|
let status = get_task_status(&stats);
|
||||||
let progress = if stats.total_bytes > 0 {
|
let progress = if stats.total_bytes > 0 {
|
||||||
@ -552,7 +584,6 @@ pub async fn downloader_stop() -> Result<()> {
|
|||||||
session.stop().await;
|
session.stop().await;
|
||||||
}
|
}
|
||||||
TORRENT_HANDLES.write().clear();
|
TORRENT_HANDLES.write().clear();
|
||||||
TASK_OUTPUT_FOLDERS.write().clear();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,10 +599,24 @@ pub async fn downloader_shutdown() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_HANDLES.write().clear();
|
TORRENT_HANDLES.write().clear();
|
||||||
TASK_OUTPUT_FOLDERS.write().clear();
|
// Clear completed tasks cache on shutdown
|
||||||
|
COMPLETED_TASKS_CACHE.write().clear();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all completed tasks from cache (tasks removed by downloader_remove_completed_tasks)
|
||||||
|
/// This cache is cleared when the downloader is shutdown/restarted
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn downloader_get_completed_tasks_cache() -> Vec<DownloadTaskInfo> {
|
||||||
|
COMPLETED_TASKS_CACHE.read().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the completed tasks cache manually
|
||||||
|
#[frb(sync)]
|
||||||
|
pub fn downloader_clear_completed_tasks_cache() {
|
||||||
|
COMPLETED_TASKS_CACHE.write().clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// Update global speed limits
|
/// Update global speed limits
|
||||||
/// Note: rqbit Session doesn't support runtime limit changes,
|
/// Note: rqbit Session doesn't support runtime limit changes,
|
||||||
/// this function is a placeholder that returns an error.
|
/// this function is a placeholder that returns an error.
|
||||||
@ -586,6 +631,7 @@ pub async fn downloader_update_speed_limits(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Remove all completed tasks (equivalent to aria2's --seed-time=0 behavior)
|
/// Remove all completed tasks (equivalent to aria2's --seed-time=0 behavior)
|
||||||
|
/// Removed tasks are cached in memory and can be queried via downloader_get_completed_tasks_cache
|
||||||
pub async fn downloader_remove_completed_tasks() -> Result<u32> {
|
pub async fn downloader_remove_completed_tasks() -> Result<u32> {
|
||||||
let session = get_session()?;
|
let session = get_session()?;
|
||||||
|
|
||||||
@ -599,8 +645,10 @@ pub async fn downloader_remove_completed_tasks() -> Result<u32> {
|
|||||||
if has_handle {
|
if has_handle {
|
||||||
// Use TorrentIdOrHash::Id for deletion (TorrentId is just usize)
|
// Use TorrentIdOrHash::Id for deletion (TorrentId is just usize)
|
||||||
if session.delete(TorrentIdOrHash::Id(task.id), false).await.is_ok() {
|
if session.delete(TorrentIdOrHash::Id(task.id), false).await.is_ok() {
|
||||||
|
// Save task info to cache before removing
|
||||||
|
COMPLETED_TASKS_CACHE.write().push(task.clone());
|
||||||
|
|
||||||
TORRENT_HANDLES.write().remove(&task.id);
|
TORRENT_HANDLES.write().remove(&task.id);
|
||||||
TASK_OUTPUT_FOLDERS.write().remove(&task.id);
|
|
||||||
removed_count += 1;
|
removed_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
|
|||||||
default_rust_auto_opaque = RustAutoOpaqueNom,
|
default_rust_auto_opaque = RustAutoOpaqueNom,
|
||||||
);
|
);
|
||||||
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1";
|
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1";
|
||||||
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -641930410;
|
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1482626931;
|
||||||
|
|
||||||
// Section: executor
|
// Section: executor
|
||||||
|
|
||||||
@ -304,6 +304,24 @@ fn wire__crate__api__downloader_api__downloader_add_url_impl(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
fn wire__crate__api__downloader_api__downloader_clear_completed_tasks_cache_impl(
|
||||||
|
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::DcoCodec, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "downloader_clear_completed_tasks_cache",
|
||||||
|
port: None,
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
transform_result_dco::<_, _, ()>((move || {
|
||||||
|
let output_ok = Result::<_, ()>::Ok({
|
||||||
|
crate::api::downloader_api::downloader_clear_completed_tasks_cache();
|
||||||
|
})?;
|
||||||
|
Ok(output_ok)
|
||||||
|
})())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
fn wire__crate__api__downloader_api__downloader_get_all_tasks_impl(
|
fn wire__crate__api__downloader_api__downloader_get_all_tasks_impl(
|
||||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
) {
|
) {
|
||||||
@ -327,6 +345,24 @@ fn wire__crate__api__downloader_api__downloader_get_all_tasks_impl(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
fn wire__crate__api__downloader_api__downloader_get_completed_tasks_cache_impl(
|
||||||
|
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::DcoCodec, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "downloader_get_completed_tasks_cache",
|
||||||
|
port: None,
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
transform_result_dco::<_, _, ()>((move || {
|
||||||
|
let output_ok = Result::<_, ()>::Ok(
|
||||||
|
crate::api::downloader_api::downloader_get_completed_tasks_cache(),
|
||||||
|
)?;
|
||||||
|
Ok(output_ok)
|
||||||
|
})())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
fn wire__crate__api__downloader_api__downloader_get_global_stats_impl(
|
fn wire__crate__api__downloader_api__downloader_get_global_stats_impl(
|
||||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
) {
|
) {
|
||||||
@ -400,6 +436,28 @@ fn wire__crate__api__downloader_api__downloader_has_active_tasks_impl(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
fn wire__crate__api__downloader_api__downloader_has_pending_session_tasks_impl(
|
||||||
|
working_dir: impl CstDecode<String>,
|
||||||
|
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::DcoCodec, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "downloader_has_pending_session_tasks",
|
||||||
|
port: None,
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let api_working_dir = working_dir.cst_decode();
|
||||||
|
transform_result_dco::<_, _, ()>((move || {
|
||||||
|
let output_ok = Result::<_, ()>::Ok(
|
||||||
|
crate::api::downloader_api::downloader_has_pending_session_tasks(
|
||||||
|
api_working_dir,
|
||||||
|
),
|
||||||
|
)?;
|
||||||
|
Ok(output_ok)
|
||||||
|
})())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
fn wire__crate__api__downloader_api__downloader_init_impl(
|
fn wire__crate__api__downloader_api__downloader_init_impl(
|
||||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
working_dir: impl CstDecode<String>,
|
working_dir: impl CstDecode<String>,
|
||||||
@ -1204,7 +1262,7 @@ fn wire__crate__api__win32_api__remove_nvme_patch_impl(
|
|||||||
}
|
}
|
||||||
fn wire__crate__api__win32_api__resolve_shortcut_impl(
|
fn wire__crate__api__win32_api__resolve_shortcut_impl(
|
||||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
_lnk_path: impl CstDecode<String>,
|
lnk_path: impl CstDecode<String>,
|
||||||
) {
|
) {
|
||||||
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::DcoCodec, _, _>(
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::DcoCodec, _, _>(
|
||||||
flutter_rust_bridge::for_generated::TaskInfo {
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
@ -1213,11 +1271,11 @@ fn wire__crate__api__win32_api__resolve_shortcut_impl(
|
|||||||
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
},
|
},
|
||||||
move || {
|
move || {
|
||||||
let api__lnk_path = _lnk_path.cst_decode();
|
let api_lnk_path = lnk_path.cst_decode();
|
||||||
move |context| {
|
move |context| {
|
||||||
transform_result_dco::<_, _, flutter_rust_bridge::for_generated::anyhow::Error>(
|
transform_result_dco::<_, _, flutter_rust_bridge::for_generated::anyhow::Error>(
|
||||||
(move || {
|
(move || {
|
||||||
let output_ok = crate::api::win32_api::resolve_shortcut(api__lnk_path)?;
|
let output_ok = crate::api::win32_api::resolve_shortcut(api_lnk_path)?;
|
||||||
Ok(output_ok)
|
Ok(output_ok)
|
||||||
})(),
|
})(),
|
||||||
)
|
)
|
||||||
@ -4067,6 +4125,12 @@ mod io {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_clear_completed_tasks_cache(
|
||||||
|
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
|
||||||
|
wire__crate__api__downloader_api__downloader_clear_completed_tasks_cache_impl()
|
||||||
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_get_all_tasks(
|
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_get_all_tasks(
|
||||||
port_: i64,
|
port_: i64,
|
||||||
@ -4074,6 +4138,12 @@ mod io {
|
|||||||
wire__crate__api__downloader_api__downloader_get_all_tasks_impl(port_)
|
wire__crate__api__downloader_api__downloader_get_all_tasks_impl(port_)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_get_completed_tasks_cache(
|
||||||
|
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
|
||||||
|
wire__crate__api__downloader_api__downloader_get_completed_tasks_cache_impl()
|
||||||
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_get_global_stats(
|
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_get_global_stats(
|
||||||
port_: i64,
|
port_: i64,
|
||||||
@ -4096,6 +4166,13 @@ mod io {
|
|||||||
wire__crate__api__downloader_api__downloader_has_active_tasks_impl(port_)
|
wire__crate__api__downloader_api__downloader_has_active_tasks_impl(port_)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_has_pending_session_tasks(
|
||||||
|
working_dir: *mut wire_cst_list_prim_u_8_strict,
|
||||||
|
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
|
||||||
|
wire__crate__api__downloader_api__downloader_has_pending_session_tasks_impl(working_dir)
|
||||||
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_init(
|
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__downloader_api__downloader_init(
|
||||||
port_: i64,
|
port_: i64,
|
||||||
@ -4378,9 +4455,9 @@ mod io {
|
|||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__win32_api__resolve_shortcut(
|
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__win32_api__resolve_shortcut(
|
||||||
port_: i64,
|
port_: i64,
|
||||||
_lnk_path: *mut wire_cst_list_prim_u_8_strict,
|
lnk_path: *mut wire_cst_list_prim_u_8_strict,
|
||||||
) {
|
) {
|
||||||
wire__crate__api__win32_api__resolve_shortcut_impl(port_, _lnk_path)
|
wire__crate__api__win32_api__resolve_shortcut_impl(port_, lnk_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user