feat: refactor browser extension communication to use IPC (#1130)

This commit is contained in:
Levi authored and GitHub committed 2025-10-12 21:17:07 +08:00
1 parent 75a8a3a9ac
commit 9a5680fb45
17 files changed
+353 -116

No files matched your search

@@ -16,6 +16,7 @@ import 'package:url_launcher/url_launcher.dart';
import 'package:window_manager/window_manager.dart';
import '../../../../api/api.dart';
import '../../../../api/model/create_task.dart';
import '../../../../api/model/downloader_config.dart';
import '../../../../api/model/request.dart';
import '../../../../core/common/start_config.dart';
@@ -31,7 +32,7 @@ import '../../../../util/package_info.dart';
import '../../../../util/updater.dart';
import '../../../../util/util.dart';
import '../../../routes/app_pages.dart';
import '../../create/dto/create_router_params.dart';
import '../../../rpc/rpc.dart';
import '../../redirect/views/redirect_view.dart';
const unixSocketPath = 'gopeed.sock';
@@ -78,6 +79,9 @@ class AppController extends GetxController with WindowListener, TrayListener {
_initTray().onError(
(error, stackTrace) => logger.w("initTray error", error, stackTrace));
_initRpcServer().onError((error, stackTrace) =>
logger.w("initRpcServer error", error, stackTrace));
_initForegroundTask().onError((error, stackTrace) =>
logger.w("initForegroundTask error", error, stackTrace));
@@ -271,6 +275,37 @@ class AppController extends GetxController with WindowListener, TrayListener {
trayManager.addListener(this);
}
Future<void> _initRpcServer() async {
if (!Util.isDesktop()) {
return;
}
try {
await startRpcServer({
"/create": (ctx) async {
final meta =
ctx.request.headers["X-Gopeed-Host-Meta"]?.firstOrNull ?? "{}";
final jsonMeta = jsonDecode(meta);
final silent = jsonMeta['silent'] as bool? ?? false;
final params = await ctx.readText();
final createTaskParams = _decodeToCreatTaskParams(params);
if (!silent) {
await windowManager.show();
_handleToCreate0(createTaskParams);
} else {
try {
await createTask(createTaskParams);
} catch (e) {
logger.w(
"create task from extension fail", e, StackTrace.current);
}
}
},
});
} catch (e) {
logger.w("start rpc server fail", e, StackTrace.current);
}
}
Future<void> _initForegroundTask() async {
if (!Util.isMobile()) {
return;
@@ -317,13 +352,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
if (uri.path == "/create") {
final params = uri.queryParameters["params"];
if (params?.isNotEmpty == true) {
final safeParams = params!.replaceAll(" ", "+");
final paramsJson =
String.fromCharCodes(base64Decode(base64.normalize(safeParams)));
Get.rootDelegate.offAndToNamed(Routes.REDIRECT,
arguments: RedirectArgs(Routes.CREATE,
arguments:
CreateRouterParams.fromJson(jsonDecode(paramsJson))));
_handleToCreate(params!);
return;
}
Get.rootDelegate.offAndToNamed(Routes.CREATE);
@@ -346,7 +375,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
}
Get.rootDelegate.offAndToNamed(Routes.REDIRECT,
arguments: RedirectArgs(Routes.CREATE,
arguments: CreateRouterParams(req: Request(url: path))));
arguments: CreateTask(req: Request(url: path))));
}
String runningAddress() {
@@ -524,4 +553,21 @@ class AppController extends GetxController with WindowListener, TrayListener {
apiToken: startConfig.value.apiToken));
await putConfig(downloaderConfig.value);
}
CreateTask _decodeToCreatTaskParams(String params) {
final safeParams = params.replaceAll('"', "").replaceAll(" ", "+");
final paramsJson =
String.fromCharCodes(base64Decode(base64.normalize(safeParams)));
return CreateTask.fromJson(jsonDecode(paramsJson));
}
_handleToCreate(String params) {
final createTaskParams = _decodeToCreatTaskParams(params);
_handleToCreate0(createTaskParams);
}
_handleToCreate0(CreateTask createTaskParams) {
Get.rootDelegate.offAndToNamed(Routes.REDIRECT,
arguments: RedirectArgs(Routes.CREATE, arguments: createTaskParams));
}
}
@@ -1,24 +0,0 @@
import 'package:json_annotation/json_annotation.dart';
import '../../../../api/model/options.dart';
import '../../../../api/model/request.dart';
part 'create_router_params.g.dart';
@JsonSerializable(explicitToJson: true)
class CreateRouterParams {
Request? req;
Options? opt;
CreateRouterParams({
this.req,
this.opt,
});
factory CreateRouterParams.fromJson(
Map<String, dynamic> json,
) =>
_$CreateRouterParamsFromJson(json);
Map<String, dynamic> toJson() => _$CreateRouterParamsToJson(this);
}
@@ -1,31 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'create_router_params.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
CreateRouterParams _$CreateRouterParamsFromJson(Map<String, dynamic> json) =>
CreateRouterParams(
req: json['req'] == null
? null
: Request.fromJson(json['req'] as Map<String, dynamic>),
opt: json['opt'] == null
? null
: Options.fromJson(json['opt'] as Map<String, dynamic>),
);
Map<String, dynamic> _$CreateRouterParamsToJson(CreateRouterParams instance) {
final val = <String, dynamic>{};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('req', instance.req?.toJson());
writeNotNull('opt', instance.opt?.toJson());
return val;
}
@@ -27,7 +27,6 @@ import '../../../views/file_tree_view.dart';
import '../../app/controllers/app_controller.dart';
import '../../history/views/history_view.dart';
import '../controllers/create_controller.dart';
import '../dto/create_router_params.dart';
class CreateView extends GetView<CreateController> {
final _confirmFormKey = GlobalKey<FormState>();
@@ -76,7 +75,7 @@ class CreateView extends GetView<CreateController> {
_pathController.text = appController.downloaderConfig.value.downloadDir;
}
final CreateRouterParams? routerParams = Get.rootDelegate.arguments();
final CreateTask? routerParams = Get.rootDelegate.arguments();
if (routerParams?.req?.url.isNotEmpty ?? false) {
// get url from route arguments
final url = routerParams!.req!.url;