feat(tasks): group extension folder downloads (#1594)

This commit is contained in:
WuFeng authored and GitHub committed 2026-11-02 15:39:08 +08:00
1 parent fc0a1e0ef9
commit 1e36599d52
84 files changed
+6690 -881

No files matched your search

@@ -34,8 +34,9 @@ class AppCapabilities {
class LocalAppCapabilities {
LocalAppCapabilities._() : codecs = createAppCapabilityCodecs() {
registry = CapabilityRegistry(codecs);
_bindGopeed(registry);
_bindStorage(registry);
final config = _ConfigStore();
_bindGopeed(registry, config);
_bindStorage(registry, config);
registry.bind(NavigationMethods.showDownloadingTasks, (_) {
AppRouter.showDownloadingTasks();
return const RpcUnit();
@@ -62,6 +63,7 @@ RpcCodecRegistry createAppCapabilityCodecs() {
..register<ResolveResult>((json) => ResolveResult.fromJson(json! as Map<String, dynamic>))
..register<CreateTask>((json) => CreateTask.fromJson(json! as Map<String, dynamic>))
..register<CreateTaskBatch>((json) => CreateTaskBatch.fromJson(json! as Map<String, dynamic>))
..register<CreateTaskBatchResult>((json) => CreateTaskBatchResult.fromJson(json! as Map<String, dynamic>))
..register<DownloaderConfig>((json) => DownloaderConfig.fromJson(json! as Map<String, dynamic>))
..register<TaskRuntimeStatus>((json) => TaskRuntimeStatus.fromJson(json! as Map<String, dynamic>))
..register<List<Task>>(
@@ -80,7 +82,7 @@ RpcCodecRegistry createAppCapabilityCodecs() {
return codecs;
}
void _bindGopeed(CapabilityRegistry registry) {
void _bindGopeed(CapabilityRegistry registry, _ConfigStore configStore) {
registry
..bind(GopeedMethods.triggerProtocolJob, (p) async {
await api.triggerProtocolJob(p['protocol'] as String, p['name'] as String);
@@ -127,9 +129,9 @@ void _bindGopeed(CapabilityRegistry registry) {
await api.deleteTasks(_optionalStringList(params['ids']), params['force'] as bool? ?? false);
return const RpcUnit();
})
..bind(GopeedMethods.getConfig, (_) => api.getConfig())
..bind(GopeedMethods.getConfig, (_) => configStore.get())
..bind(GopeedMethods.putConfig, (config) async {
await api.putConfig(config);
await configStore.put(config);
return const RpcUnit();
})
..bind(GopeedMethods.installExtension, api.installExtension)
@@ -163,35 +165,59 @@ void _bindGopeed(CapabilityRegistry registry) {
});
}
void _bindStorage(CapabilityRegistry registry) {
// Shared by local and child-window handlers. History owns its config field;
// full config snapshots must preserve the latest history inside the same queue.
class _ConfigStore {
Future<void> _tail = Future<void>.value();
Future<T> _run<T>(Future<T> Function() operation) {
final result = _tail.then((_) => operation());
_tail = result.then<void>((_) {}, onError: (Object _, StackTrace _) {});
return result;
}
Future<DownloaderConfig> get() => _run(api.getConfig);
Future<void> put(DownloaderConfig config) {
final snapshot = DownloaderConfig.fromJson(config.toJson());
return _run(() async {
final latest = await api.getConfig();
snapshot.extra.createHistory = latest.extra.createHistory;
await api.putConfig(snapshot);
});
}
Future<void> updateHistory(void Function(List<String>) mutation) => _run(() async {
final config = await api.getConfig();
final history = List<String>.of(config.extra.createHistory);
mutation(history);
config.extra.createHistory = history;
await api.putConfig(config);
});
}
void _bindStorage(CapabilityRegistry registry, _ConfigStore configStore) {
registry
..bind(StorageMethods.getCreateHistory, (_) async {
final config = await api.getConfig();
final config = await configStore.get();
return config.extra.createHistory;
})
..bind(StorageMethods.saveCreateHistory, (urls) async {
final config = await api.getConfig();
final history = List<String>.of(config.extra.createHistory);
for (final url in urls) {
history.remove(url);
history.insert(0, url);
if (history.length > 64) history.removeLast();
}
config.extra.createHistory = history;
await api.putConfig(config);
await configStore.updateHistory((history) {
for (final url in urls) {
history.remove(url);
history.insert(0, url);
if (history.length > 64) history.removeLast();
}
});
return const RpcUnit();
})
..bind(StorageMethods.removeCreateHistory, (url) async {
final config = await api.getConfig();
final history = List<String>.of(config.extra.createHistory)..remove(url);
config.extra.createHistory = history;
await api.putConfig(config);
await configStore.updateHistory((history) => history.remove(url));
return const RpcUnit();
})
..bind(StorageMethods.clearCreateHistory, (_) async {
final config = await api.getConfig();
config.extra.createHistory = const [];
await api.putConfig(config);
await configStore.updateHistory((history) => history.clear());
return const RpcUnit();
});
}
@@ -17,7 +17,7 @@ abstract final class GopeedMethods {
static const getMirrorCandidates = RpcMethod<Map<String, dynamic>, List<String>>('gopeed.mirrors.candidates');
static const resolve = RpcMethod<ResolveTask, ResolveResult>('gopeed.resolve');
static const createTask = RpcMethod<CreateTask, String>('gopeed.task.create');
static const createTaskBatch = RpcMethod<CreateTaskBatch, List<String>>('gopeed.task.createBatch');
static const createTaskBatch = RpcMethod<CreateTaskBatch, CreateTaskBatchResult>('gopeed.task.createBatch');
static const patchTask = RpcMethod<Map<String, dynamic>, RpcUnit>('gopeed.task.patch');
static const getTasks = RpcMethod<List<String>, List<Task>>('gopeed.task.list');
static const getTaskStatus = RpcMethod<String, TaskRuntimeStatus>('gopeed.task.status');
@@ -53,7 +53,7 @@ class GopeedService {
Future<String> createTask(CreateTask request) => _invoker.invoke(GopeedMethods.createTask, request);
Future<List<String>> createTaskBatch(CreateTaskBatch request) =>
Future<CreateTaskBatchResult> createTaskBatch(CreateTaskBatch request) =>
_invoker.invoke(GopeedMethods.createTaskBatch, request);
Future<void> patchTask(String id, PatchTask request) async {