diff --git a/assets/translations/strings_en.i18n.json b/assets/translations/strings_en.i18n.json index 7751f6b3..6e408ba1 100644 --- a/assets/translations/strings_en.i18n.json +++ b/assets/translations/strings_en.i18n.json @@ -243,6 +243,7 @@ }, "generateWarpConfig": "Generate WARP config", "missingWarpConfig": "Missing WARP config", + "warpConfigGenerated": "WARP config generated", "pageTitle": "Config Options", "logLevel": "Log Level", "resolveDestination": "Resolve Destination", diff --git a/lib/features/config_option/data/config_option_repository.dart b/lib/features/config_option/data/config_option_repository.dart index c195c495..8a890562 100644 --- a/lib/features/config_option/data/config_option_repository.dart +++ b/lib/features/config_option/data/config_option_repository.dart @@ -18,7 +18,7 @@ abstract interface class ConfigOptionRepository { ConfigOptionPatch patch, ); TaskEither resetConfigOption(); - TaskEither generateWarpConfig(); + TaskEither generateWarpConfig(); } abstract interface class SingBoxConfigOptionRepository { @@ -115,7 +115,7 @@ class ConfigOptionRepositoryImpl } @override - TaskEither generateWarpConfig() { + TaskEither generateWarpConfig() { return exceptionHandler( () async { final options = getConfigOption().getOrElse((l) => throw l); @@ -131,8 +131,9 @@ class ConfigOptionRepositoryImpl ConfigOptionPatch( warpAccountId: warp.accountId, warpAccessToken: warp.accessToken, + warpWireguardConfig: warp.wireguardConfig, ), - ), + ).map((_) => warp.log), ) .run(); }, diff --git a/lib/features/config_option/model/config_option_entity.dart b/lib/features/config_option/model/config_option_entity.dart index 12076fda..3432983e 100644 --- a/lib/features/config_option/model/config_option_entity.dart +++ b/lib/features/config_option/model/config_option_entity.dart @@ -68,6 +68,7 @@ class ConfigOptionEntity with _$ConfigOptionEntity { @OptionalRangeJsonConverter() @Default(OptionalRange()) OptionalRange warpNoise, + @Default("") String warpWireguardConfig, }) = _ConfigOptionEntity; factory ConfigOptionEntity.initial() => ConfigOptionEntity( @@ -140,6 +141,7 @@ class ConfigOptionEntity with _$ConfigOptionEntity { warpCleanIp: patch.warpCleanIp ?? warpCleanIp, warpPort: patch.warpPort ?? warpPort, warpNoise: patch.warpNoise ?? warpNoise, + warpWireguardConfig: patch.warpWireguardConfig ?? warpWireguardConfig, ); } @@ -184,17 +186,20 @@ class ConfigOptionEntity with _$ConfigOptionEntity { muxPadding: muxPadding, muxMaxStreams: muxMaxStreams, muxProtocol: muxProtocol, - enableWarp: enableWarp, - warpDetourMode: warpDetourMode, - warpLicenseKey: warpLicenseKey, - warpAccountId: warpAccountId, - warpAccessToken: warpAccessToken, - warpCleanIp: warpCleanIp, - warpPort: warpPort, - warpNoise: warpNoise, geoipPath: geoipPath, geositePath: geositePath, rules: rules, + warp: SingboxWarpOption( + enable: enableWarp, + mode: warpDetourMode, + licenseKey: warpLicenseKey, + accountId: warpAccountId, + accessToken: warpAccessToken, + cleanIp: warpCleanIp, + cleanPort: warpPort, + warpNoise: warpNoise, + wireguardConfig: warpWireguardConfig, + ), ); } @@ -248,6 +253,7 @@ class ConfigOptionPatch with _$ConfigOptionPatch { String? warpCleanIp, int? warpPort, @OptionalRangeJsonConverter() OptionalRange? warpNoise, + String? warpWireguardConfig, }) = _ConfigOptionPatch; factory ConfigOptionPatch.fromJson(Map json) => diff --git a/lib/features/config_option/notifier/warp_option_notifier.dart b/lib/features/config_option/notifier/warp_option_notifier.dart index ef790bb3..fcfdc551 100644 --- a/lib/features/config_option/notifier/warp_option_notifier.dart +++ b/lib/features/config_option/notifier/warp_option_notifier.dart @@ -1,4 +1,3 @@ -import 'package:fpdart/fpdart.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hiddify/core/preferences/preferences_provider.dart'; import 'package:hiddify/features/config_option/data/config_option_data_providers.dart'; @@ -27,7 +26,7 @@ class WarpOptionNotifier extends _$WarpOptionNotifier with AppLogger { return WarpOptions( consentGiven: consent, configGeneration: hasWarpConfig - ? const AsyncValue.data(unit) + ? const AsyncValue.data("") : AsyncError(const MissingWarpConfigFailure(), StackTrace.current), ); } @@ -66,6 +65,6 @@ class WarpOptionNotifier extends _$WarpOptionNotifier with AppLogger { class WarpOptions with _$WarpOptions { const factory WarpOptions({ required bool consentGiven, - required AsyncValue configGeneration, + required AsyncValue configGeneration, }) = _WarpOptions; } diff --git a/lib/features/config_option/overview/warp_options_widgets.dart b/lib/features/config_option/overview/warp_options_widgets.dart index dc6855e3..12bcc1e8 100644 --- a/lib/features/config_option/overview/warp_options_widgets.dart +++ b/lib/features/config_option/overview/warp_options_widgets.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:hiddify/core/localization/translations.dart'; import 'package:hiddify/core/model/constants.dart'; import 'package:hiddify/core/model/optional_range.dart'; +import 'package:hiddify/core/widget/custom_alert_dialog.dart'; import 'package:hiddify/features/config_option/model/config_option_entity.dart'; import 'package:hiddify/features/config_option/notifier/warp_option_notifier.dart'; import 'package:hiddify/features/settings/widgets/settings_input_dialog.dart'; @@ -32,6 +33,18 @@ class WarpOptionsTiles extends HookConsumerWidget { final warpPrefaceCompleted = warpOptions.consentGiven; final canChangeOptions = warpPrefaceCompleted && options.enableWarp; + ref.listen( + warpOptionNotifierProvider.select((value) => value.configGeneration), + (previous, next) async { + if (next case AsyncData(value: final log) when log.isNotEmpty) { + await CustomAlertDialog( + title: t.settings.config.warpConfigGenerated, + message: log, + ).show(context); + } + }, + ); + return Column( children: [ SwitchListTile( diff --git a/lib/singbox/model/singbox_config_option.dart b/lib/singbox/model/singbox_config_option.dart index 5f8229bb..408f6528 100644 --- a/lib/singbox/model/singbox_config_option.dart +++ b/lib/singbox/model/singbox_config_option.dart @@ -51,17 +51,10 @@ class SingboxConfigOption with _$SingboxConfigOption { required bool muxPadding, required int muxMaxStreams, required MuxProtocol muxProtocol, - required bool enableWarp, - required WarpDetourMode warpDetourMode, - required String warpLicenseKey, - required String warpAccountId, - required String warpAccessToken, - required String warpCleanIp, - required int warpPort, - @OptionalRangeJsonConverter() required OptionalRange warpNoise, required String geoipPath, required String geositePath, required List rules, + required SingboxWarpOption warp, }) = _SingboxConfigOption; String format() { @@ -72,3 +65,21 @@ class SingboxConfigOption with _$SingboxConfigOption { factory SingboxConfigOption.fromJson(Map json) => _$SingboxConfigOptionFromJson(json); } + +@freezed +class SingboxWarpOption with _$SingboxWarpOption { + const factory SingboxWarpOption({ + required bool enable, + required WarpDetourMode mode, + required String wireguardConfig, + required String licenseKey, + required String accountId, + required String accessToken, + required String cleanIp, + required int cleanPort, + @OptionalRangeJsonConverter() required OptionalRange warpNoise, + }) = _SingboxWarpOption; + + factory SingboxWarpOption.fromJson(Map json) => + _$SingboxWarpOptionFromJson(json); +} diff --git a/lib/singbox/model/warp_account.dart b/lib/singbox/model/warp_account.dart index ba010190..abe362be 100644 --- a/lib/singbox/model/warp_account.dart +++ b/lib/singbox/model/warp_account.dart @@ -1,17 +1,26 @@ -import 'package:flutter/foundation.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:convert'; -part 'warp_account.freezed.dart'; -part 'warp_account.g.dart'; +typedef WarpResponse = ({ + String log, + String accountId, + String accessToken, + String wireguardConfig, +}); -@freezed -class WarpAccount with _$WarpAccount { - const factory WarpAccount({ - required String licenseKey, - required String accountId, - required String accessToken, - }) = _WarpAccount; - - factory WarpAccount.fromJson(Map json) => - _$WarpAccountFromJson(json); +WarpResponse warpFromJson(dynamic json) { + if (json + case { + "account-id": final String newAccountId, + "access-token": final String newAccessToken, + "log": final String log, + "config": final Map wireguardConfig, + }) { + return ( + log: log, + accountId: newAccountId, + accessToken: newAccessToken, + wireguardConfig: jsonEncode(wireguardConfig), + ); + } + throw Exception("invalid response"); } diff --git a/lib/singbox/service/ffi_singbox_service.dart b/lib/singbox/service/ffi_singbox_service.dart index 35d628be..61b72675 100644 --- a/lib/singbox/service/ffi_singbox_service.dart +++ b/lib/singbox/service/ffi_singbox_service.dart @@ -457,7 +457,7 @@ class FFISingboxService with InfraLogger implements SingboxService { } @override - TaskEither generateWarpConfig({ + TaskEither generateWarpConfig({ required String licenseKey, required String previousAccountId, required String previousAccessToken, @@ -477,20 +477,7 @@ class FFISingboxService with InfraLogger implements SingboxService { if (response.startsWith("error:")) { return left(response.replaceFirst('error:', "")); } - if (jsonDecode(response) - case { - "account-id": final String newAccountId, - "access-token": final String newAccessToken, - }) { - return right( - WarpAccount( - licenseKey: licenseKey, - accountId: newAccountId, - accessToken: newAccessToken, - ), - ); - } - return left("invalid response"); + return right(warpFromJson(jsonDecode(response))); }, ), ); diff --git a/lib/singbox/service/platform_singbox_service.dart b/lib/singbox/service/platform_singbox_service.dart index 4c16d00b..e8376584 100644 --- a/lib/singbox/service/platform_singbox_service.dart +++ b/lib/singbox/service/platform_singbox_service.dart @@ -266,7 +266,7 @@ class PlatformSingboxService with InfraLogger implements SingboxService { } @override - TaskEither generateWarpConfig({ + TaskEither generateWarpConfig({ required String licenseKey, required String previousAccountId, required String previousAccessToken, @@ -282,20 +282,7 @@ class PlatformSingboxService with InfraLogger implements SingboxService { "previous-access-token": previousAccessToken, }, ); - if (jsonDecode(warpConfig as String) - case { - "account-id": final String newAccountId, - "access-token": final String newAccessToken, - }) { - return right( - WarpAccount( - licenseKey: licenseKey, - accountId: newAccountId, - accessToken: newAccessToken, - ), - ); - } - return left("invalid response"); + return right(warpFromJson(jsonDecode(warpConfig as String))); }, ); } diff --git a/lib/singbox/service/singbox_service.dart b/lib/singbox/service/singbox_service.dart index fa181dc6..8b9abe46 100644 --- a/lib/singbox/service/singbox_service.dart +++ b/lib/singbox/service/singbox_service.dart @@ -87,7 +87,7 @@ abstract interface class SingboxService { TaskEither clearLogs(); - TaskEither generateWarpConfig({ + TaskEither generateWarpConfig({ required String licenseKey, required String previousAccountId, required String previousAccessToken, diff --git a/libcore b/libcore index 6c65b739..298ca9b1 160000 --- a/libcore +++ b/libcore @@ -1 +1 @@ -Subproject commit 6c65b73981189658f9ddc409eecbf6f6471b8477 +Subproject commit 298ca9b1b830a142eeab03c22ce7501ee4746e34