mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-02-06 15:10:20 +00:00
feat: downloader update
This commit is contained in:
@@ -13,6 +13,7 @@ part 'download_manager.freezed.dart';
|
||||
@freezed
|
||||
abstract class DownloadManagerState with _$DownloadManagerState {
|
||||
const factory DownloadManagerState({
|
||||
required String workingDir,
|
||||
required String downloadDir,
|
||||
@Default(false) bool isInitialized,
|
||||
downloader_api.DownloadGlobalStat? globalStat,
|
||||
@@ -36,18 +37,24 @@ class DownloadManager extends _$DownloadManager {
|
||||
if (appGlobalState.applicationBinaryModuleDir == null) {
|
||||
throw Exception("applicationBinaryModuleDir is null");
|
||||
}
|
||||
if (appGlobalState.applicationSupportDir == null) {
|
||||
throw Exception("applicationSupportDir is null");
|
||||
}
|
||||
ref.onDispose(() {
|
||||
_disposed = true;
|
||||
});
|
||||
ref.keepAlive();
|
||||
|
||||
// Working directory for session data (in appSupport)
|
||||
final workingDir = "${appGlobalState.applicationSupportDir}${Platform.pathSeparator}downloader";
|
||||
// Default download directory (can be customized)
|
||||
final downloadDir = "${appGlobalState.applicationBinaryModuleDir}${Platform.pathSeparator}downloads";
|
||||
|
||||
// Lazy load init
|
||||
() async {
|
||||
try {
|
||||
// Check if there are existing tasks
|
||||
final dir = Directory(downloadDir);
|
||||
// Check if there are existing tasks (check working dir for session data)
|
||||
final dir = Directory(workingDir);
|
||||
if (await dir.exists()) {
|
||||
dPrint("Launch download manager");
|
||||
await initDownloader();
|
||||
@@ -59,21 +66,32 @@ class DownloadManager extends _$DownloadManager {
|
||||
}
|
||||
}();
|
||||
|
||||
return DownloadManagerState(downloadDir: downloadDir);
|
||||
return DownloadManagerState(workingDir: workingDir, downloadDir: downloadDir);
|
||||
}
|
||||
|
||||
Future<void> initDownloader() async {
|
||||
Future<void> initDownloader({int? uploadLimitBps, int? downloadLimitBps}) 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);
|
||||
// Create working directory if it doesn't exist
|
||||
final workingDir = Directory(state.workingDir);
|
||||
if (!await workingDir.exists()) {
|
||||
await workingDir.create(recursive: true);
|
||||
}
|
||||
|
||||
// Initialize the Rust downloader
|
||||
downloader_api.downloaderInit(downloadDir: state.downloadDir);
|
||||
// Create download directory if it doesn't exist
|
||||
final downloadDir = Directory(state.downloadDir);
|
||||
if (!await downloadDir.exists()) {
|
||||
await downloadDir.create(recursive: true);
|
||||
}
|
||||
|
||||
// Initialize the Rust downloader with optional speed limits
|
||||
downloader_api.downloaderInit(
|
||||
workingDir: state.workingDir,
|
||||
defaultDownloadDir: state.downloadDir,
|
||||
uploadLimitBps: uploadLimitBps,
|
||||
downloadLimitBps: downloadLimitBps,
|
||||
);
|
||||
|
||||
state = state.copyWith(isInitialized: true);
|
||||
|
||||
@@ -97,6 +115,9 @@ class DownloadManager extends _$DownloadManager {
|
||||
try {
|
||||
final globalStat = await downloader_api.downloaderGetGlobalStats();
|
||||
state = state.copyWith(globalStat: globalStat);
|
||||
|
||||
// Auto-remove completed tasks (no seeding behavior)
|
||||
await removeCompletedTasks();
|
||||
} catch (e) {
|
||||
dPrint("globalStat update error:$e");
|
||||
}
|
||||
@@ -177,6 +198,18 @@ class DownloadManager extends _$DownloadManager {
|
||||
state = state.copyWith(isInitialized: false, globalStat: null);
|
||||
}
|
||||
|
||||
/// Shutdown the downloader completely (allows restart with new settings)
|
||||
Future<void> shutdown() async {
|
||||
await downloader_api.downloaderShutdown();
|
||||
state = state.copyWith(isInitialized: false, globalStat: null);
|
||||
}
|
||||
|
||||
/// Restart the downloader with new speed limit settings
|
||||
Future<void> restart({int? uploadLimitBps, int? downloadLimitBps}) async {
|
||||
await shutdown();
|
||||
await initDownloader(uploadLimitBps: uploadLimitBps, downloadLimitBps: downloadLimitBps);
|
||||
}
|
||||
|
||||
/// Convert speed limit text to bytes per second
|
||||
/// Supports formats like: "1", "100k", "10m", "0"
|
||||
int textToByte(String text) {
|
||||
@@ -195,4 +228,22 @@ class DownloadManager extends _$DownloadManager {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Remove all completed tasks (equivalent to aria2's --seed-time=0 behavior)
|
||||
/// Returns the number of tasks removed
|
||||
Future<int> removeCompletedTasks() async {
|
||||
if (!state.isInitialized) {
|
||||
return 0;
|
||||
}
|
||||
final removed = await downloader_api.downloaderRemoveCompletedTasks();
|
||||
return removed;
|
||||
}
|
||||
|
||||
/// Check if there are any active (non-completed) download tasks
|
||||
Future<bool> hasActiveTasks() async {
|
||||
if (!state.isInitialized) {
|
||||
return false;
|
||||
}
|
||||
return await downloader_api.downloaderHasActiveTasks();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$DownloadManagerState {
|
||||
|
||||
String get downloadDir; bool get isInitialized; downloader_api.DownloadGlobalStat? get globalStat;
|
||||
String get workingDir; 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)
|
||||
@@ -25,16 +25,16 @@ $DownloadManagerStateCopyWith<DownloadManagerState> get copyWith => _$DownloadMa
|
||||
|
||||
@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));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is DownloadManagerState&&(identical(other.workingDir, workingDir) || other.workingDir == workingDir)&&(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);
|
||||
int get hashCode => Object.hash(runtimeType,workingDir,downloadDir,isInitialized,globalStat);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DownloadManagerState(downloadDir: $downloadDir, isInitialized: $isInitialized, globalStat: $globalStat)';
|
||||
return 'DownloadManagerState(workingDir: $workingDir, downloadDir: $downloadDir, isInitialized: $isInitialized, globalStat: $globalStat)';
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ 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
|
||||
String workingDir, String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat
|
||||
});
|
||||
|
||||
|
||||
@@ -62,9 +62,10 @@ class _$DownloadManagerStateCopyWithImpl<$Res>
|
||||
|
||||
/// 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,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? workingDir = null,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
|
||||
workingDir: null == workingDir ? _self.workingDir : workingDir // ignore: cast_nullable_to_non_nullable
|
||||
as String,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?,
|
||||
@@ -152,10 +153,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String workingDir, 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 $default(_that.workingDir,_that.downloadDir,_that.isInitialized,_that.globalStat);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -173,10 +174,10 @@ return $default(_that.downloadDir,_that.isInitialized,_that.globalStat);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String workingDir, 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 _:
|
||||
return $default(_that.workingDir,_that.downloadDir,_that.isInitialized,_that.globalStat);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -193,10 +194,10 @@ return $default(_that.downloadDir,_that.isInitialized,_that.globalStat);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String workingDir, 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 $default(_that.workingDir,_that.downloadDir,_that.isInitialized,_that.globalStat);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -208,9 +209,10 @@ return $default(_that.downloadDir,_that.isInitialized,_that.globalStat);case _:
|
||||
|
||||
|
||||
class _DownloadManagerState implements DownloadManagerState {
|
||||
const _DownloadManagerState({required this.downloadDir, this.isInitialized = false, this.globalStat});
|
||||
const _DownloadManagerState({required this.workingDir, required this.downloadDir, this.isInitialized = false, this.globalStat});
|
||||
|
||||
|
||||
@override final String workingDir;
|
||||
@override final String downloadDir;
|
||||
@override@JsonKey() final bool isInitialized;
|
||||
@override final downloader_api.DownloadGlobalStat? globalStat;
|
||||
@@ -225,16 +227,16 @@ _$DownloadManagerStateCopyWith<_DownloadManagerState> get copyWith => __$Downloa
|
||||
|
||||
@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));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _DownloadManagerState&&(identical(other.workingDir, workingDir) || other.workingDir == workingDir)&&(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);
|
||||
int get hashCode => Object.hash(runtimeType,workingDir,downloadDir,isInitialized,globalStat);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DownloadManagerState(downloadDir: $downloadDir, isInitialized: $isInitialized, globalStat: $globalStat)';
|
||||
return 'DownloadManagerState(workingDir: $workingDir, downloadDir: $downloadDir, isInitialized: $isInitialized, globalStat: $globalStat)';
|
||||
}
|
||||
|
||||
|
||||
@@ -245,7 +247,7 @@ abstract mixin class _$DownloadManagerStateCopyWith<$Res> implements $DownloadMa
|
||||
factory _$DownloadManagerStateCopyWith(_DownloadManagerState value, $Res Function(_DownloadManagerState) _then) = __$DownloadManagerStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat
|
||||
String workingDir, String downloadDir, bool isInitialized, downloader_api.DownloadGlobalStat? globalStat
|
||||
});
|
||||
|
||||
|
||||
@@ -262,9 +264,10 @@ class __$DownloadManagerStateCopyWithImpl<$Res>
|
||||
|
||||
/// 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,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? workingDir = null,Object? downloadDir = null,Object? isInitialized = null,Object? globalStat = freezed,}) {
|
||||
return _then(_DownloadManagerState(
|
||||
downloadDir: null == downloadDir ? _self.downloadDir : downloadDir // ignore: cast_nullable_to_non_nullable
|
||||
workingDir: null == workingDir ? _self.workingDir : workingDir // ignore: cast_nullable_to_non_nullable
|
||||
as String,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?,
|
||||
|
||||
@@ -41,7 +41,7 @@ final class DownloadManagerProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$downloadManagerHash() => r'adc9a147522afbfcfc8a2e16310649220a75d6a3';
|
||||
String _$downloadManagerHash() => r'f0fd818851be0d1c9e6774803aae465c33843cde';
|
||||
|
||||
abstract class _$DownloadManager extends $Notifier<DownloadManagerState> {
|
||||
DownloadManagerState build();
|
||||
|
||||
Reference in New Issue
Block a user