import 'dart:async'; import 'dart:convert'; import 'dart:ffi'; import 'dart:io'; import 'package:dio/dio.dart'; import '../../api/model/create_task.dart'; import '../../api/model/create_task_batch.dart'; import '../../api/model/downloader_config.dart'; import '../../api/model/extension.dart'; import '../../api/model/http_listen_result.dart'; import '../../api/model/info.dart'; import '../../api/model/install_extension.dart'; import '../../api/model/request.dart'; import '../../api/model/resolve_result.dart'; import '../../api/model/result.dart'; import '../../api/model/switch_extension.dart'; import '../../api/model/task.dart'; import '../../api/model/task_filter.dart'; import '../../api/model/update_check_extension_resp.dart'; import '../../api/model/update_extension_settings.dart'; import '../../util/extensions.dart'; import '../../util/util.dart'; import '../libgopeed_boot.dart'; import '../native/channel/libgopeed_channel.dart'; import '../native/ffi/libgopeed_bind.dart'; import '../native/ffi/libgopeed_ffi.dart'; import '../native/libgopeed_interface.dart'; import '../native/model/invoke_request.dart'; import '../native/model/start_config.dart'; import 'libgopeed_boot_base.dart'; LibgopeedBoot create() => LibgopeedBootNative(); class LibgopeedBootNative with LibgopeedBootBase implements LibgopeedBoot { late LibgopeedAbi _libgopeedAbi; late int _apiInstance; late Dio _dio; LibgopeedBootNative() { if (Util.isDesktop()) { var libName = "libgopeed."; if (Platform.isWindows) { libName += "dll"; } if (Platform.isMacOS) { libName += "dylib"; } if (Platform.isLinux) { libName += "so"; } _libgopeedAbi = LibgopeedFFi(LibgopeedBind(DynamicLibrary.open(libName))); } else { _libgopeedAbi = LibgopeedChannel(); } } Future _invoke( String method, List params, T Function(dynamic json)? fromJsonT, ) async { final invokeRequest = InvokeRequest( method: method, params: params.map((e) { if (e.toJson != null) { return jsonEncode(e.toJson()); } return jsonEncode(e); }).toList()); final resp = await _libgopeedAbi.invoke(_apiInstance, jsonEncode(invokeRequest)); final result = Result.fromJson(jsonDecode(resp), fromJsonT ??= (json) => null as T); return handleResult(result); } List _parseTaskFilter(TaskFilter? filter) { if (filter == null) { return []; } return [filter]; } @override Future init(StartConfig cfg) async { final result = await _libgopeedAbi.create(jsonEncode(cfg.toJson())); _apiInstance = Result.fromJson(jsonDecode(result), (data) => data as int).data!; _dio = createDio(); } @override Future startHttp() async { return _invoke( "startHttp", [], (json) => HttpListenResult.fromJson(json)); } @override Future stopHttp() async { await _invoke("stopHttp", [], null); } @override Future restartHttp() async { await _invoke("restartHttp", [], null); } @override Future info() async { return _invoke("info", [], (json) => Info.fromJson(json)); } @override Future resolve(Request request) async { return _invoke( "resolve", [request], (json) => ResolveResult.fromJson(json)); } @override Future createTask(CreateTask createTask) async { return _invoke( "createTask", [createTask], (json) => json as String); } @override Future createTaskBatch(CreateTaskBatch createTask) async { return _invoke( "createTaskBatch", [createTask], (json) => json as String); } @override Future pauseTask(String id) async { await _invoke("pauseTask", [id], null); } @override Future pauseTasks(TaskFilter? filter) async { await _invoke("pauseTasks", _parseTaskFilter(filter), null); } @override Future continueTask(String id) async { await _invoke("continueTask", [id], null); } @override Future continueTasks(TaskFilter? filter) async { await _invoke("continueTasks", _parseTaskFilter(filter), null); } @override Future deleteTask(String id, bool force) async { await _invoke("deleteTask", [id, force], null); } @override Future deleteTasks(TaskFilter? filter, bool force) async { await _invoke( "deleteTasks", _parseTaskFilter(filter).apply((it) { it.add(force); }), null); } @override Future getTask(String id) async { return _invoke("getTask", [id], (json) => Task.fromJson(json)); } @override Future> getTasks(TaskFilter? filter) async { return _invoke>("getTasks", _parseTaskFilter(filter), (json) => json.map((e) => Task.fromJson(e)).toList()); } @override Future> getTaskStats(String id) async { return _invoke>( "getTaskStats", [id], (json) => json as Map); } @override Future getConfig() async { return _invoke( "getConfig", [], (json) => DownloaderConfig.fromJson(json)); } @override Future putConfig(DownloaderConfig config) async { await _invoke("putConfig", [config], null); } @override Future installExtension(InstallExtension installExtension) async { await _invoke("installExtension", [installExtension], null); } @override Future> getExtensions() async { return _invoke>("getExtensions", [], (json) => json.map((e) => Extension.fromJson(e)).toList()); } @override Future updateExtensionSettings( String identity, UpdateExtensionSettings updateExtensionSettings) async { await _invoke( "updateExtensionSettings", [identity, updateExtensionSettings], null); } @override Future switchExtension( String identity, SwitchExtension switchExtension) async {} @override Future deleteExtension(String identity) async { await _invoke("deleteExtension", [identity], null); } @override Future upgradeCheckExtension( String identity) async { return _invoke("upgradeCheckExtension", [identity], (json) => UpdateCheckExtensionResp.fromJson(json)); } @override Future upgradeExtension(String identity) async { await _invoke("upgradeExtension", [identity], null); } @override Future close() async { await _invoke("close", [], null); } @override Future> proxyRequest(String uri, {data, Options? options}) { return _dio.request(uri, data: data, options: options); } }