feat: direct call download api by cgo dart

This commit is contained in:
liwei committed 2024-12-02 00:39:28 +08:00
1 parent 467ada5500
commit 91dfd78b77
71 files changed
+6936 -1883

No files matched your search

@@ -14,10 +14,8 @@ import 'package:uri_to_file/uri_to_file.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:window_manager/window_manager.dart';
import '../../../../api/api.dart';
import '../../../../api/libgopeed_boot.dart';
import '../../../../api/model/downloader_config.dart';
import '../../../../core/common/start_config.dart';
import '../../../../core/libgopeed_boot.dart';
import '../../../../database/database.dart';
import '../../../../database/entity.dart';
import '../../../../i18n/message.dart';
@@ -74,12 +72,9 @@ final allTrackerSubscribeUrlCdns = Map.fromIterable(allTrackerSubscribeUrls,
});
class AppController extends GetxController with WindowListener, TrayListener {
static StartConfig? _defaultStartConfig;
final autoStartup = false.obs;
final startConfig = StartConfig().obs;
final runningPort = 0.obs;
final downloaderConfig = DownloaderConfig().obs;
final httpRunningPort = 0.obs;
late AppLinks _appLinks;
StreamSubscription<Uri>? _linkSubscription;
@@ -111,7 +106,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
void onClose() {
_linkSubscription?.cancel();
trayManager.removeListener(this);
LibgopeedBoot.instance.stop();
LibgopeedBoot.instance.close();
}
@override
@@ -218,11 +213,12 @@ class AppController extends GetxController with WindowListener, TrayListener {
),
MenuItem(
label: "startAll".tr,
onClick: (menuItem) async => {continueAllTasks()},
onClick: (menuItem) async =>
{LibgopeedBoot.instance.continueTasks(null)},
),
MenuItem(
label: "pauseAll".tr,
onClick: (menuItem) async => {pauseAllTasks()},
onClick: (menuItem) async => {LibgopeedBoot.instance.pauseTasks(null)},
),
MenuItem(
label: 'setting'.tr,
@@ -247,7 +243,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
label: 'exit'.tr,
onClick: (menuItem) async {
try {
await LibgopeedBoot.instance.stop();
await LibgopeedBoot.instance.close();
} catch (e) {
logger.w("libgopeed stop fail", e);
}
@@ -313,43 +309,9 @@ class AppController extends GetxController with WindowListener, TrayListener {
await Get.rootDelegate.offAndToNamed(Routes.CREATE, arguments: path);
}
String runningAddress() {
if (startConfig.value.network == 'unix') {
return startConfig.value.address;
}
return '${startConfig.value.address.split(':').first}:$runningPort';
}
Future<StartConfig> _initDefaultStartConfig() async {
if (_defaultStartConfig != null) {
return _defaultStartConfig!;
}
_defaultStartConfig = StartConfig();
if (!Util.supportUnixSocket()) {
// not support unix socket, use tcp
_defaultStartConfig!.network = "tcp";
_defaultStartConfig!.address = "127.0.0.1:0";
} else {
_defaultStartConfig!.network = "unix";
_defaultStartConfig!.address =
"${(await getTemporaryDirectory()).path}/$unixSocketPath";
}
_defaultStartConfig!.apiToken = '';
return _defaultStartConfig!;
}
Future<StartConfig> loadStartConfig() async {
final defaultCfg = await _initDefaultStartConfig();
final saveCfg = Database.instance.getStartConfig();
startConfig.value.network = saveCfg?.network ?? defaultCfg.network;
startConfig.value.address = saveCfg?.address ?? defaultCfg.address;
startConfig.value.apiToken = saveCfg?.apiToken ?? defaultCfg.apiToken;
return startConfig.value;
}
Future<DownloaderConfig> loadDownloaderConfig() async {
try {
downloaderConfig.value = await getConfig();
downloaderConfig.value = await LibgopeedBoot.instance.getConfig();
} catch (e) {
logger.w("load downloader config fail", e, StackTrace.current);
downloaderConfig.value = DownloaderConfig();
@@ -382,7 +344,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
});
refreshTrackers();
await saveConfig();
await LibgopeedBoot.instance.putConfig(downloaderConfig.value);
}
refreshTrackers() {
@@ -411,7 +373,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
}
Future<List<String>> _fetchTrackers(String subscribeUrl) async {
final resp = await proxyRequest(subscribeUrl);
final resp = await LibgopeedBoot.instance.proxyRequest(subscribeUrl);
if (resp.statusCode != 200) {
throw Exception(
'Failed to get trackers, status code: ${resp.statusCode}');
@@ -468,12 +430,4 @@ class AppController extends GetxController with WindowListener, TrayListener {
args: ['--${Args.flagHidden}']);
autoStartup.value = await launchAtStartup.isEnabled();
}
Future<void> saveConfig() async {
Database.instance.saveStartConfig(StartConfigEntity(
network: startConfig.value.network,
address: startConfig.value.address,
apiToken: startConfig.value.apiToken));
await putConfig(downloaderConfig.value);
}
}
@@ -7,7 +7,7 @@ import 'package:get/get.dart';
import 'package:path/path.dart' as path;
import 'package:rounded_loading_button_plus/rounded_loading_button.dart';
import '../../../../api/api.dart';
import '../../../../api/libgopeed_boot.dart';
import '../../../../api/model/create_task.dart';
import '../../../../api/model/options.dart';
import '../../../../api/model/request.dart';
@@ -594,7 +594,7 @@ class CreateView extends GetView<CreateController> {
final isDirect = controller.directDownload.value || isMultiLine;
if (isDirect) {
await Future.wait(urls.map((url) {
return createTask(CreateTask(
return LibgopeedBoot.instance.createTask(CreateTask(
req: Request(
url: url,
extra: parseReqExtra(url),
@@ -610,7 +610,7 @@ class CreateView extends GetView<CreateController> {
}));
Get.rootDelegate.offNamed(Routes.TASK);
} else {
final rr = await resolve(Request(
final rr = await LibgopeedBoot.instance.resolve(Request(
url: submitUrl,
extra: parseReqExtra(_urlController.text),
proxy: parseProxy(),
@@ -741,23 +741,28 @@ class CreateView extends GetView<CreateController> {
await Future.wait(
controller.selectedIndexes.map((index) {
final file = rr.res.files[index];
return createTask(CreateTask(
req: file.req!..proxy = parseProxy(),
opt: Options(
name: file.name,
path: path.join(_pathController.text,
rr.res.name, file.path),
selectFiles: [],
extra: optExtra)));
return LibgopeedBoot.instance.createTask(
CreateTask(
req: file.req!..proxy = parseProxy(),
opt: Options(
name: file.name,
path: path.join(
_pathController.text,
rr.res.name,
file.path),
selectFiles: [],
extra: optExtra)));
}));
} else {
await createTask(CreateTask(
rid: rr.id,
opt: Options(
name: _renameController.text,
path: _pathController.text,
selectFiles: controller.selectedIndexes,
extra: optExtra)));
await LibgopeedBoot.instance.createTask(
CreateTask(
rid: rr.id,
opt: Options(
name: _renameController.text,
path: _pathController.text,
selectFiles:
controller.selectedIndexes,
extra: optExtra)));
}
Get.back();
Get.rootDelegate.offNamed(Routes.TASK);
@@ -1,6 +1,6 @@
import 'package:get/get.dart';
import 'package:gopeed/api/api.dart';
import '../../../../api/libgopeed_boot.dart';
import '../../../../api/model/extension.dart';
class ExtensionController extends GetxController {
@@ -17,12 +17,13 @@ class ExtensionController extends GetxController {
}
Future<void> load() async {
extensions.value = await getExtensions();
extensions.value = await LibgopeedBoot.instance.getExtensions();
}
Future<void> checkUpdate() async {
for (final ext in extensions) {
final resp = await upgradeCheckExtension(ext.identity);
final resp =
await LibgopeedBoot.instance.upgradeCheckExtension(ext.identity);
if (resp.newVersion.isNotEmpty) {
updateFlags[ext.identity] = resp.newVersion;
}
@@ -11,7 +11,8 @@ import 'package:path/path.dart' as path;
import 'package:rounded_loading_button_plus/rounded_loading_button.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../../api/api.dart';
import '../../../../api/entry/libgopeed_boot_web.dart';
import '../../../../api/libgopeed_boot.dart';
import '../../../../api/model/extension.dart';
import '../../../../api/model/install_extension.dart';
import '../../../../api/model/switch_extension.dart';
@@ -78,8 +79,9 @@ class ExtensionView extends GetView<ExtensionController> {
}
_installBtnController.start();
try {
await installExtension(InstallExtension(
url: _installUrlController.text));
await LibgopeedBoot.instance.installExtension(
InstallExtension(
url: _installUrlController.text));
Get.snackbar('tip'.tr, 'extensionInstallSuccess'.tr);
await controller.load();
} catch (e) {
@@ -98,7 +100,7 @@ class ExtensionView extends GetView<ExtensionController> {
if (dir != null) {
MacSecureUtil.saveBookmark(dir);
try {
await installExtension(
await LibgopeedBoot.instance.installExtension(
InstallExtension(devMode: true, url: dir));
Get.snackbar(
'tip'.tr, 'extensionInstallSuccess'.tr);
@@ -133,8 +135,10 @@ class ExtensionView extends GetView<ExtensionController> {
)
: Util.isWeb()
? Image.network(
join(
'/fs/extensions/${extension.identity}/${extension.icon}'),
(LibgopeedBoot.instance
as LibgopeedBootWeb)
.join(
'/fs/extensions/${extension.identity}/${extension.icon}'),
width: 48,
height: 48,
)
@@ -155,9 +159,9 @@ class ExtensionView extends GetView<ExtensionController> {
value: !extension.disabled,
onChanged: (value) async {
try {
await switchExtension(
extension.identity,
SwitchExtension(status: value));
await LibgopeedBoot.instance
.switchExtension(extension.identity,
SwitchExtension(status: value));
await controller.load();
} catch (e) {
showErrorMessage(e);
@@ -354,10 +358,11 @@ class ExtensionView extends GetView<ExtensionController> {
try {
confrimController.start();
if (formKey.currentState?.saveAndValidate() == true) {
await updateExtensionSettings(
extension.identity,
UpdateExtensionSettings(
settings: formKey.currentState!.value));
await LibgopeedBoot.instance
.updateExtensionSettings(
extension.identity,
UpdateExtensionSettings(
settings: formKey.currentState!.value));
await controller.load();
Get.back();
}
@@ -454,7 +459,8 @@ class ExtensionView extends GetView<ExtensionController> {
),
onPressed: () async {
try {
await deleteExtension(extension.identity);
await LibgopeedBoot.instance
.deleteExtension(extension.identity);
await controller.load();
Get.back();
} catch (e) {
@@ -487,18 +493,19 @@ class ExtensionView extends GetView<ExtensionController> {
onPressed: () async {
confrimController.start();
try {
await updateExtension(extension.identity);
await LibgopeedBoot.instance
.upgradeExtension(extension.identity);
await controller.load();
controller.updateFlags.remove(extension.identity);
Get.back();
showMessage('tip'.tr, 'extensionUpdateSuccess'.tr);
showMessage('tip'.tr, 'extensionUpgradeSuccess'.tr);
} catch (e) {
showErrorMessage(e);
} finally {
confrimController.stop();
}
},
child: Text('newVersionUpdate'.tr),
child: Text('newVersionUpgrade'.tr),
),
],
));
@@ -1,7 +1,8 @@
import 'dart:convert';
import 'package:get/get.dart';
import 'package:gopeed/api/api.dart';
import '../../../../api/libgopeed_boot.dart';
class SettingController extends GetxController {
final tapStatues = <String, bool>{}.obs;
@@ -28,12 +29,13 @@ class SettingController extends GetxController {
void fetchLatestVersion() async {
String? releaseDataStr;
try {
releaseDataStr = (await proxyRequest(
releaseDataStr = (await LibgopeedBoot.instance.proxyRequest(
"https://api.github.com/repos/GopeedLab/gopeed/releases/latest"))
.data;
} catch (e) {
releaseDataStr =
(await proxyRequest("https://gopeed.com/api/release")).data;
releaseDataStr = (await LibgopeedBoot.instance
.proxyRequest("https://gopeed.com/api/release"))
.data;
}
if (releaseDataStr == null) {
return;
@@ -10,6 +10,7 @@ import 'package:intl/intl.dart';
import 'package:launch_at_startup/launch_at_startup.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../../api/libgopeed_boot.dart';
import '../../../../api/model/downloader_config.dart';
import '../../../../i18n/message.dart';
import '../../../../util/input_formatter.dart';
@@ -35,7 +36,6 @@ class SettingView extends GetView<SettingController> {
Widget build(BuildContext context) {
final appController = Get.find<AppController>();
final downloaderCfg = appController.downloaderConfig;
final startCfg = appController.startConfig;
Timer? timer;
Future<bool> debounceSave(
@@ -51,8 +51,8 @@ class SettingView extends GetView<SettingController> {
return;
}
}
appController
.saveConfig()
LibgopeedBoot.instance
.putConfig(downloaderCfg.value)
.then((_) => completer.complete(true))
.onError(completer.completeError);
if (needRestart) {
@@ -530,7 +530,7 @@ class SettingView extends GetView<SettingController> {
launchUrl(Uri.parse('https://gopeed.com'),
mode: LaunchMode.externalApplication);
},
child: Text('newVersionUpdate'.tr),
child: Text('newVersionUpgrade'.tr),
),
],
));
@@ -637,7 +637,7 @@ class SettingView extends GetView<SettingController> {
final portController = TextEditingController(text: port);
updateAddress() async {
final newAddress = '${ipController.text}:${portController.text}';
if (newAddress != startCfg.value.address) {
if (newAddress != proxy.host) {
proxy.host = newAddress;
await debounceSave();
@@ -718,152 +718,152 @@ class SettingView extends GetView<SettingController> {
);
// advanced config API items start
final buildApiProtocol = _buildConfigItem(
'protocol',
() => startCfg.value.network == 'tcp'
? 'TCP ${startCfg.value.address}'
: 'Unix',
(Key key) {
final items = <Widget>[
SizedBox(
width: 80,
child: DropdownButtonFormField<String>(
value: startCfg.value.network,
onChanged: Util.isDesktop()
? (value) async {
startCfg.update((val) {
val!.network = value!;
});
// final buildApiProtocol = _buildConfigItem(
// 'protocol',
// () => startCfg.value.host == 'tcp'
// ? 'TCP ${startCfg.value.address}'
// : 'Unix',
// (Key key) {
// final items = <Widget>[
// SizedBox(
// width: 80,
// child: DropdownButtonFormField<String>(
// value: startCfg.value.host,
// onChanged: Util.isDesktop()
// ? (value) async {
// startCfg.update((val) {
// val!.host = value!;
// });
await debounceSave(needRestart: true);
}
: null,
items: [
const DropdownMenuItem<String>(
value: 'tcp',
child: Text('TCP'),
),
Util.supportUnixSocket()
? const DropdownMenuItem<String>(
value: 'unix',
child: Text('Unix'),
)
: null,
].where((e) => e != null).map((e) => e!).toList(),
),
)
];
if (Util.isDesktop() && startCfg.value.network == 'tcp') {
final arr = startCfg.value.address.split(':');
var ip = '127.0.0.1';
var port = '0';
if (arr.length > 1) {
ip = arr[0];
port = arr[1];
}
// await debounceSave(needRestart: true);
// }
// : null,
// items: [
// const DropdownMenuItem<String>(
// value: 'tcp',
// child: Text('TCP'),
// ),
// Util.supportUnixSocket()
// ? const DropdownMenuItem<String>(
// value: 'unix',
// child: Text('Unix'),
// )
// : null,
// ].where((e) => e != null).map((e) => e!).toList(),
// ),
// )
// ];
// if (Util.isDesktop() && startCfg.value.host == 'tcp') {
// final arr = startCfg.value.address.split(':');
// var ip = '127.0.0.1';
// var port = '0';
// if (arr.length > 1) {
// ip = arr[0];
// port = arr[1];
// }
final ipController = TextEditingController(text: ip);
final portController = TextEditingController(text: port);
updateAddress() async {
if (ipController.text.isEmpty || portController.text.isEmpty) {
return;
}
final newAddress = '${ipController.text}:${portController.text}';
if (newAddress != startCfg.value.address) {
startCfg.value.address = newAddress;
// final ipController = TextEditingController(text: ip);
// final portController = TextEditingController(text: port);
// updateAddress() async {
// if (ipController.text.isEmpty || portController.text.isEmpty) {
// return;
// }
// final newAddress = '${ipController.text}:${portController.text}';
// if (newAddress != startCfg.value.address) {
// startCfg.value.address = newAddress;
final saved = await debounceSave(
check: () async {
// Check if address already in use
final configIp = ipController.text;
final configPort = int.parse(portController.text);
if (configPort == 0) {
return '';
}
try {
final socket = await Socket.connect(configIp, configPort,
timeout: const Duration(seconds: 3));
socket.close();
return 'portInUse'
.trParams({'port': configPort.toString()});
} catch (e) {
return '';
}
},
needRestart: true);
// final saved = await debounceSave(
// check: () async {
// // Check if address already in use
// final configIp = ipController.text;
// final configPort = int.parse(portController.text);
// if (configPort == 0) {
// return '';
// }
// try {
// final socket = await Socket.connect(configIp, configPort,
// timeout: const Duration(seconds: 3));
// socket.close();
// return 'portInUse'
// .trParams({'port': configPort.toString()});
// } catch (e) {
// return '';
// }
// },
// needRestart: true);
// If save failed, restore the old address
if (!saved) {
final oldAddress =
(await appController.loadStartConfig()).address;
startCfg.update((val) async {
val!.address = oldAddress;
});
}
}
}
// // If save failed, restore the old address
// if (!saved) {
// // final oldAddress =
// // (await appController.loadStartConfig()).address;
// // startCfg.update((val) async {
// // val!.address = oldAddress;
// // });
// }
// }
// }
ipController.addListener(updateAddress);
portController.addListener(updateAddress);
items.addAll([
const Padding(padding: EdgeInsets.only(left: 20)),
Flexible(
child: TextFormField(
controller: ipController,
decoration: const InputDecoration(
labelText: 'IP',
contentPadding: EdgeInsets.all(0.0),
),
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp('[0-9.]')),
],
),
),
const Padding(padding: EdgeInsets.only(left: 10)),
Flexible(
child: TextFormField(
controller: portController,
decoration: InputDecoration(
labelText: 'port'.tr,
contentPadding: const EdgeInsets.all(0.0),
),
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
NumericalRangeFormatter(min: 0, max: 65535),
],
),
),
]);
}
// ipController.addListener(updateAddress);
// portController.addListener(updateAddress);
// items.addAll([
// const Padding(padding: EdgeInsets.only(left: 20)),
// Flexible(
// child: TextFormField(
// controller: ipController,
// decoration: const InputDecoration(
// labelText: 'IP',
// contentPadding: EdgeInsets.all(0.0),
// ),
// keyboardType: TextInputType.number,
// inputFormatters: [
// FilteringTextInputFormatter.allow(RegExp('[0-9.]')),
// ],
// ),
// ),
// const Padding(padding: EdgeInsets.only(left: 10)),
// Flexible(
// child: TextFormField(
// controller: portController,
// decoration: InputDecoration(
// labelText: 'port'.tr,
// contentPadding: const EdgeInsets.all(0.0),
// ),
// keyboardType: TextInputType.number,
// inputFormatters: [
// FilteringTextInputFormatter.digitsOnly,
// NumericalRangeFormatter(min: 0, max: 65535),
// ],
// ),
// ),
// ]);
// }
return Form(
child: Row(
children: items,
),
);
},
);
final buildApiToken = _buildConfigItem('apiToken',
() => startCfg.value.apiToken.isEmpty ? 'notSet'.tr : 'set'.tr,
(Key key) {
final apiTokenController =
TextEditingController(text: startCfg.value.apiToken);
apiTokenController.addListener(() async {
if (apiTokenController.text != startCfg.value.apiToken) {
startCfg.value.apiToken = apiTokenController.text;
// return Form(
// child: Row(
// children: items,
// ),
// );
// },
// );
// final buildApiToken = _buildConfigItem('apiToken',
// () => startCfg.value.apiToken.isEmpty ? 'notSet'.tr : 'set'.tr,
// (Key key) {
// final apiTokenController =
// TextEditingController(text: startCfg.value.apiToken);
// apiTokenController.addListener(() async {
// if (apiTokenController.text != startCfg.value.apiToken) {
// startCfg.value.apiToken = apiTokenController.text;
await debounceSave(needRestart: true);
}
});
return TextField(
key: key,
obscureText: true,
controller: apiTokenController,
focusNode: FocusNode(),
);
});
// await debounceSave(needRestart: true);
// }
// });
// return TextField(
// key: key,
// obscureText: true,
// controller: apiTokenController,
// focusNode: FocusNode(),
// );
// });
// advanced config log items start
buildLogsDir() {
@@ -993,16 +993,16 @@ class SettingView extends GetView<SettingController> {
child: Column(
children: _addDivider([buildProxy()]),
)),
const Text('API'),
Card(
child: Column(
children: _addDivider([
buildApiProtocol(),
Util.isDesktop() && startCfg.value.network == 'tcp'
? buildApiToken()
: null,
]),
)),
// const Text('API'),
// Card(
// child: Column(
// children: _addDivider([
// buildApiProtocol(),
// Util.isDesktop() && startCfg.value.host == 'tcp'
// ? buildApiToken()
// : null,
// ]),
// )),
Text('developer'.tr),
Card(
child: Column(
@@ -1,5 +1,5 @@
import 'package:get/get.dart';
import '../../../../api/api.dart';
import '../../../../api/libgopeed_boot.dart';
import '../../../../api/model/resource.dart';
import '../../../../api/model/task.dart';
@@ -31,7 +31,7 @@ class TaskFilesController extends GetxController {
super.onInit();
final taskId = Get.rootDelegate.parameters['id'];
final tasks = await getTasks([]);
final tasks = await LibgopeedBoot.instance.getTasks(null);
task.value = tasks.firstWhere((element) => element.id == taskId);
parseDirMap(task.value!.meta.res!.files);
toDir("/");
@@ -2,8 +2,9 @@ import 'dart:async';
import 'package:get/get.dart';
import '../../../../api/api.dart';
import '../../../../api/libgopeed_boot.dart';
import '../../../../api/model/task.dart';
import '../../../../api/model/task_filter.dart';
abstract class TaskListController extends GetxController {
List<Status> statuses;
@@ -44,7 +45,8 @@ abstract class TaskListController extends GetxController {
}
getTasksState() async {
final tasks = await getTasks(statuses);
final tasks =
await LibgopeedBoot.instance.getTasks(TaskFilter(statuses: statuses));
// sort tasks by create time
tasks.sort(compare);
this.tasks.value = tasks;
@@ -5,7 +5,8 @@ import 'package:path/path.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../../api/api.dart' as api;
import '../../../../api/entry/libgopeed_boot_web.dart';
import '../../../../api/libgopeed_boot.dart';
import '../../../../util/browser_download/browser_download.dart';
import '../../../../util/file_icon.dart';
import '../../../../util/icons.dart';
@@ -84,8 +85,10 @@ class TaskFilesView extends GetView<TaskFilesController> {
mainAxisAlignment: MainAxisAlignment.end,
children: Util.isWeb()
? () {
final accessUrl = api.join(
"/fs/tasks/${controller.task.value!.id}$fileRelativePath");
final accessUrl = (LibgopeedBoot
.instance as LibgopeedBootWeb)
.join(
"/fs/tasks/${controller.task.value!.id}$fileRelativePath");
return [
IconButton(
icon: