feat: AdaptiveConcurrencyController

This commit is contained in:
xkeyC
2025-12-05 22:06:55 +08:00
parent 3c60b5a2c1
commit 8898569067
13 changed files with 387 additions and 62 deletions

View File

@@ -32,6 +32,18 @@ Future<void> downloaderInit({
bool downloaderIsInitialized() =>
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)
Future<BigInt> downloaderAddTorrent({
required List<int> torrentBytes,
@@ -118,6 +130,17 @@ Future<void> downloaderStop() =>
Future<void> downloaderShutdown() =>
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
/// Note: rqbit Session doesn't support runtime limit changes,
/// 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)
/// Removed tasks are cached in memory and can be queried via downloader_get_completed_tasks_cache
Future<int> downloaderRemoveCompletedTasks() =>
RustLib.instance.api.crateApiDownloaderApiDownloaderRemoveCompletedTasks();

View File

@@ -6,6 +6,7 @@
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_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`
Future<void> sendNotify({
@@ -20,21 +21,27 @@ Future<void> sendNotify({
appId: appId,
);
/// Get system memory size in GB
Future<BigInt> getSystemMemorySizeGb() =>
RustLib.instance.api.crateApiWin32ApiGetSystemMemorySizeGb();
/// Get number of logical processors
Future<int> getNumberOfLogicalProcessors() =>
RustLib.instance.api.crateApiWin32ApiGetNumberOfLogicalProcessors();
/// Get all system information at once
Future<SystemInfo> getSystemInfo() =>
RustLib.instance.api.crateApiWin32ApiGetSystemInfo();
/// Get GPU info from registry (more accurate VRAM)
Future<String> getGpuInfoFromRegistry() =>
RustLib.instance.api.crateApiWin32ApiGetGpuInfoFromRegistry();
/// Resolve shortcut (.lnk) file to get target path
Future<String> resolveShortcut({required String lnkPath}) =>
RustLib.instance.api.crateApiWin32ApiResolveShortcut(lnkPath: lnkPath);
/// Open file explorer and select file/folder
Future<void> openDirWithExplorer({
required String path,
required bool isFile,
@@ -58,16 +65,19 @@ Future<List<ProcessInfo>> getProcessListByName({required String processName}) =>
processName: processName,
);
/// Kill processes by name
Future<int> killProcessByName({required String processName}) => RustLib
.instance
.api
.crateApiWin32ApiKillProcessByName(processName: processName);
/// Get disk physical sector size for performance
Future<int> getDiskPhysicalSectorSize({required String driveLetter}) => RustLib
.instance
.api
.crateApiWin32ApiGetDiskPhysicalSectorSize(driveLetter: driveLetter);
/// Create a desktop shortcut
Future<void> createDesktopShortcut({
required String targetPath,
required String shortcutName,
@@ -76,12 +86,14 @@ Future<void> createDesktopShortcut({
shortcutName: shortcutName,
);
/// Run a program with admin privileges (UAC)
Future<void> runAsAdmin({required String program, required String args}) =>
RustLib.instance.api.crateApiWin32ApiRunAsAdmin(
program: program,
args: args,
);
/// Start a program (without waiting)
Future<void> startProcess({
required String program,
required List<String> args,
@@ -90,12 +102,15 @@ Future<void> startProcess({
args: args,
);
/// Check if NVME patch is applied
Future<bool> checkNvmePatchStatus() =>
RustLib.instance.api.crateApiWin32ApiCheckNvmePatchStatus();
/// Add NVME patch to registry
Future<void> addNvmePatch() =>
RustLib.instance.api.crateApiWin32ApiAddNvmePatch();
/// Remove NVME patch from registry
Future<void> removeNvmePatch() =>
RustLib.instance.api.crateApiWin32ApiRemoveNvmePatch();

View File

@@ -72,7 +72,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
String get codegenVersion => '2.11.1';
@override
int get rustContentHash => -641930410;
int get rustContentHash => -1482626931;
static const kDefaultExternalLibraryLoaderConfig =
ExternalLibraryLoaderConfig(
@@ -118,8 +118,13 @@ abstract class RustLibApi extends BaseApi {
List<String>? trackers,
});
void crateApiDownloaderApiDownloaderClearCompletedTasksCache();
Future<List<DownloadTaskInfo>> crateApiDownloaderApiDownloaderGetAllTasks();
List<DownloadTaskInfo>
crateApiDownloaderApiDownloaderGetCompletedTasksCache();
Future<DownloadGlobalStat> crateApiDownloaderApiDownloaderGetGlobalStats();
Future<DownloadTaskInfo> crateApiDownloaderApiDownloaderGetTaskInfo({
@@ -128,6 +133,10 @@ abstract class RustLibApi extends BaseApi {
Future<bool> crateApiDownloaderApiDownloaderHasActiveTasks();
bool crateApiDownloaderApiDownloaderHasPendingSessionTasks({
required String workingDir,
});
Future<void> crateApiDownloaderApiDownloaderInit({
required String workingDir,
required String defaultDownloadDir,
@@ -633,6 +642,33 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
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
Future<List<DownloadTaskInfo>> crateApiDownloaderApiDownloaderGetAllTasks() {
return handler.executeNormal(
@@ -657,6 +693,34 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
TaskConstMeta get kCrateApiDownloaderApiDownloaderGetAllTasksConstMeta =>
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
Future<DownloadGlobalStat> crateApiDownloaderApiDownloaderGetGlobalStats() {
return handler.executeNormal(
@@ -742,6 +806,38 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
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
Future<void> crateApiDownloaderApiDownloaderInit({
required String workingDir,

View File

@@ -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_) {
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
.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(
int port_,
) {
@@ -1383,6 +1409,33 @@ class RustLibWire implements BaseWire {
_wire__crate__api__downloader_api__downloader_has_active_tasksPtr
.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(
int port_,
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(
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 =