From 3541f8e3db1b07d7b91124d6dffc120f3f5575ab Mon Sep 17 00:00:00 2001 From: problematicconsumer Date: Sat, 17 Feb 2024 11:58:34 +0330 Subject: [PATCH] Change mapping --- lib/core/model/optional_range.dart | 11 +- lib/core/utils/json_converters.dart | 10 +- .../data/config_option_repository.dart | 10 +- .../model/config_option_entity.dart | 337 ++++++++---------- lib/singbox/model/singbox_config_enum.dart | 52 +-- lib/singbox/model/singbox_config_option.dart | 159 +++------ lib/singbox/model/singbox_rule.dart | 50 ++- lib/singbox/service/ffi_singbox_service.dart | 2 +- .../service/platform_singbox_service.dart | 2 +- 9 files changed, 269 insertions(+), 364 deletions(-) diff --git a/lib/core/model/optional_range.dart b/lib/core/model/optional_range.dart index ae9fa649..98f25674 100644 --- a/lib/core/model/optional_range.dart +++ b/lib/core/model/optional_range.dart @@ -1,5 +1,6 @@ import 'package:dart_mappable/dart_mappable.dart'; import 'package:dartx/dartx.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hiddify/core/localization/translations.dart'; part 'optional_range.mapper.dart'; @@ -42,13 +43,13 @@ class OptionalRange with OptionalRangeMappable { } } -class OptionalRangeJsonMapper extends SimpleMapper { - const OptionalRangeJsonMapper(); +class OptionalRangeJsonConverter + implements JsonConverter { + const OptionalRangeJsonConverter(); @override - OptionalRange decode(dynamic value) => - OptionalRange._fromString(value as String); + OptionalRange fromJson(String json) => OptionalRange._fromString(json); @override - dynamic encode(OptionalRange self) => self.format(); + String toJson(OptionalRange object) => object.format(); } diff --git a/lib/core/utils/json_converters.dart b/lib/core/utils/json_converters.dart index 14585a76..290f6da8 100644 --- a/lib/core/utils/json_converters.dart +++ b/lib/core/utils/json_converters.dart @@ -1,11 +1,11 @@ -import 'package:dart_mappable/dart_mappable.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; -class IntervalInSecondsMapper extends SimpleMapper { - const IntervalInSecondsMapper(); +class IntervalInSecondsConverter implements JsonConverter { + const IntervalInSecondsConverter(); @override - Duration decode(dynamic value) => Duration(seconds: value as int); + Duration fromJson(int json) => Duration(seconds: json); @override - dynamic encode(Duration self) => self.inSeconds; + int toJson(Duration object) => object.inSeconds; } diff --git a/lib/features/config_option/data/config_option_repository.dart b/lib/features/config_option/data/config_option_repository.dart index 9370b598..55dde309 100644 --- a/lib/features/config_option/data/config_option_repository.dart +++ b/lib/features/config_option/data/config_option_repository.dart @@ -34,7 +34,7 @@ class ConfigOptionRepositoryImpl @override Either getConfigOption() { try { - final map = ConfigOptionEntity.initial().toMap(); + final map = ConfigOptionEntity.initial().toJson(); for (final key in map.keys) { final persisted = preferences.get(key); if (persisted != null) { @@ -49,7 +49,7 @@ class ConfigOptionRepositoryImpl map[key] = persisted; } } - final options = ConfigOptionEntityMapper.fromMap(map); + final options = ConfigOptionEntity.fromJson(map); return right(options); } catch (error, stackTrace) { return left(ConfigOptionUnexpectedFailure(error, stackTrace)); @@ -62,7 +62,7 @@ class ConfigOptionRepositoryImpl ) { return exceptionHandler( () async { - final map = patch.toMap(); + final map = patch.toJson(); await updateByJson(map); return right(unit); }, @@ -74,7 +74,7 @@ class ConfigOptionRepositoryImpl TaskEither resetConfigOption() { return exceptionHandler( () async { - final map = ConfigOptionEntity.initial().toMap(); + final map = ConfigOptionEntity.initial().toJson(); await updateByJson(map); return right(unit); }, @@ -86,7 +86,7 @@ class ConfigOptionRepositoryImpl Future updateByJson( Map options, ) async { - final map = ConfigOptionEntity.initial().toMap(); + final map = ConfigOptionEntity.initial().toJson(); for (final key in map.keys) { final value = options[key]; if (value != null) { diff --git a/lib/features/config_option/model/config_option_entity.dart b/lib/features/config_option/model/config_option_entity.dart index b2a4bf99..5e8434ab 100644 --- a/lib/features/config_option/model/config_option_entity.dart +++ b/lib/features/config_option/model/config_option_entity.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:dart_mappable/dart_mappable.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hiddify/core/model/optional_range.dart'; import 'package:hiddify/core/utils/json_converters.dart'; import 'package:hiddify/features/log/model/log_level.dart'; @@ -9,99 +9,68 @@ import 'package:hiddify/singbox/model/singbox_config_option.dart'; import 'package:hiddify/singbox/model/singbox_rule.dart'; import 'package:hiddify/utils/platform_utils.dart'; -part 'config_option_entity.mapper.dart'; +part 'config_option_entity.freezed.dart'; +part 'config_option_entity.g.dart'; -@MappableClass( - caseStyle: CaseStyle.paramCase, - includeCustomMappers: [ - OptionalRangeJsonMapper(), - IntervalInSecondsMapper(), - ], -) -class ConfigOptionEntity with ConfigOptionEntityMappable { - const ConfigOptionEntity({ - required this.serviceMode, - this.logLevel = LogLevel.warn, - this.resolveDestination = false, - this.ipv6Mode = IPv6Mode.disable, - this.remoteDnsAddress = "udp://1.1.1.1", - this.remoteDnsDomainStrategy = DomainStrategy.auto, - this.directDnsAddress = "1.1.1.1", - this.directDnsDomainStrategy = DomainStrategy.auto, - this.mixedPort = 2334, - this.localDnsPort = 6450, - this.tunImplementation = TunImplementation.mixed, - this.mtu = 9000, - this.strictRoute = true, - this.connectionTestUrl = "http://cp.cloudflare.com/", - this.urlTestInterval = const Duration(minutes: 10), - this.enableClashApi = true, - this.clashApiPort = 6756, - this.bypassLan = false, - this.allowConnectionFromLan = false, - this.enableFakeDns = false, - this.enableDnsRouting = true, - this.independentDnsCache = true, - this.enableTlsFragment = false, - this.tlsFragmentSize = const OptionalRange(min: 1, max: 500), - this.tlsFragmentSleep = const OptionalRange(min: 0, max: 500), - this.enableTlsMixedSniCase = false, - this.enableTlsPadding = false, - this.tlsPaddingSize = const OptionalRange(min: 1, max: 1500), - this.enableMux = false, - this.muxPadding = false, - this.muxMaxStreams = 8, - this.muxProtocol = MuxProtocol.h2mux, - this.enableWarp = false, - this.warpDetourMode = WarpDetourMode.outbound, - this.warpLicenseKey = "", - this.warpCleanIp = "auto", - this.warpPort = 0, - this.warpNoise = const OptionalRange(), - }); +@freezed +class ConfigOptionEntity with _$ConfigOptionEntity { + const ConfigOptionEntity._(); - final ServiceMode serviceMode; - final LogLevel logLevel; - final bool resolveDestination; - @MappableField(key: "ipv6-mode") - final IPv6Mode ipv6Mode; - final String remoteDnsAddress; - final DomainStrategy remoteDnsDomainStrategy; - final String directDnsAddress; - final DomainStrategy directDnsDomainStrategy; - final int mixedPort; - final int localDnsPort; - final TunImplementation tunImplementation; - final int mtu; - final bool strictRoute; - final String connectionTestUrl; - final Duration urlTestInterval; - final bool enableClashApi; - final int clashApiPort; - final bool bypassLan; - final bool allowConnectionFromLan; - final bool enableFakeDns; - final bool enableDnsRouting; - final bool independentDnsCache; - final bool enableTlsFragment; - final OptionalRange tlsFragmentSize; - final OptionalRange tlsFragmentSleep; - final bool enableTlsMixedSniCase; - final bool enableTlsPadding; - final OptionalRange tlsPaddingSize; - final bool enableMux; - final bool muxPadding; - final int muxMaxStreams; - final MuxProtocol muxProtocol; - final bool enableWarp; - final WarpDetourMode warpDetourMode; - final String warpLicenseKey; - final String warpCleanIp; - final int warpPort; - final OptionalRange warpNoise; + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory ConfigOptionEntity({ + required ServiceMode serviceMode, + @Default(LogLevel.warn) LogLevel logLevel, + @Default(false) bool resolveDestination, + @Default(IPv6Mode.disable) IPv6Mode ipv6Mode, + @Default("udp://1.1.1.1") String remoteDnsAddress, + @Default(DomainStrategy.auto) DomainStrategy remoteDnsDomainStrategy, + @Default("1.1.1.1") String directDnsAddress, + @Default(DomainStrategy.auto) DomainStrategy directDnsDomainStrategy, + @Default(2334) int mixedPort, + @Default(6450) int localDnsPort, + @Default(TunImplementation.mixed) TunImplementation tunImplementation, + @Default(9000) int mtu, + @Default(true) bool strictRoute, + @Default("http://cp.cloudflare.com/") String connectionTestUrl, + @IntervalInSecondsConverter() + @Default(Duration(minutes: 10)) + Duration urlTestInterval, + @Default(true) bool enableClashApi, + @Default(6756) int clashApiPort, + @Default(false) bool bypassLan, + @Default(false) bool allowConnectionFromLan, + @Default(false) bool enableFakeDns, + @Default(true) bool enableDnsRouting, + @Default(true) bool independentDnsCache, + @Default(false) bool enableTlsFragment, + @OptionalRangeJsonConverter() + @Default(OptionalRange(min: 1, max: 500)) + OptionalRange tlsFragmentSize, + @OptionalRangeJsonConverter() + @Default(OptionalRange(min: 0, max: 500)) + OptionalRange tlsFragmentSleep, + @Default(false) bool enableTlsMixedSniCase, + @Default(false) bool enableTlsPadding, + @OptionalRangeJsonConverter() + @Default(OptionalRange(min: 1, max: 1500)) + OptionalRange tlsPaddingSize, + @Default(false) bool enableMux, + @Default(false) bool muxPadding, + @Default(8) int muxMaxStreams, + @Default(MuxProtocol.h2mux) MuxProtocol muxProtocol, + @Default(false) bool enableWarp, + @Default(WarpDetourMode.outbound) WarpDetourMode warpDetourMode, + @Default("") String warpLicenseKey, + @Default("auto") String warpCleanIp, + @Default(0) int warpPort, + @OptionalRangeJsonConverter() + @Default(OptionalRange()) + OptionalRange warpNoise, + }) = _ConfigOptionEntity; - factory ConfigOptionEntity.initial() => - ConfigOptionEntity(serviceMode: ServiceMode.defaultMode); + factory ConfigOptionEntity.initial() => ConfigOptionEntity( + serviceMode: ServiceMode.defaultMode, + ); bool hasExperimentalOptions() { if (PlatformUtils.isDesktop && serviceMode == ServiceMode.tun) { @@ -120,11 +89,54 @@ class ConfigOptionEntity with ConfigOptionEntityMappable { String format() { const encoder = JsonEncoder.withIndent(' '); - return encoder.convert(toMap()); + return encoder.convert(toJson()); } ConfigOptionEntity patch(ConfigOptionPatch patch) { - return copyWith.$delta(patch.delta()); + return copyWith( + serviceMode: patch.serviceMode ?? serviceMode, + logLevel: patch.logLevel ?? logLevel, + resolveDestination: patch.resolveDestination ?? resolveDestination, + ipv6Mode: patch.ipv6Mode ?? ipv6Mode, + remoteDnsAddress: patch.remoteDnsAddress ?? remoteDnsAddress, + remoteDnsDomainStrategy: + patch.remoteDnsDomainStrategy ?? remoteDnsDomainStrategy, + directDnsAddress: patch.directDnsAddress ?? directDnsAddress, + directDnsDomainStrategy: + patch.directDnsDomainStrategy ?? directDnsDomainStrategy, + mixedPort: patch.mixedPort ?? mixedPort, + localDnsPort: patch.localDnsPort ?? localDnsPort, + tunImplementation: patch.tunImplementation ?? tunImplementation, + mtu: patch.mtu ?? mtu, + strictRoute: patch.strictRoute ?? strictRoute, + connectionTestUrl: patch.connectionTestUrl ?? connectionTestUrl, + urlTestInterval: patch.urlTestInterval ?? urlTestInterval, + enableClashApi: patch.enableClashApi ?? enableClashApi, + clashApiPort: patch.clashApiPort ?? clashApiPort, + bypassLan: patch.bypassLan ?? bypassLan, + allowConnectionFromLan: + patch.allowConnectionFromLan ?? allowConnectionFromLan, + enableFakeDns: patch.enableFakeDns ?? enableFakeDns, + enableDnsRouting: patch.enableDnsRouting ?? enableDnsRouting, + independentDnsCache: patch.independentDnsCache ?? independentDnsCache, + enableTlsFragment: patch.enableTlsFragment ?? enableTlsFragment, + tlsFragmentSize: patch.tlsFragmentSize ?? tlsFragmentSize, + tlsFragmentSleep: patch.tlsFragmentSleep ?? tlsFragmentSleep, + enableTlsMixedSniCase: + patch.enableTlsMixedSniCase ?? enableTlsMixedSniCase, + enableTlsPadding: patch.enableTlsPadding ?? enableTlsPadding, + tlsPaddingSize: patch.tlsPaddingSize ?? tlsPaddingSize, + enableMux: patch.enableMux ?? enableMux, + muxPadding: patch.muxPadding ?? muxPadding, + muxMaxStreams: patch.muxMaxStreams ?? muxMaxStreams, + muxProtocol: patch.muxProtocol ?? muxProtocol, + enableWarp: patch.enableWarp ?? enableWarp, + warpDetourMode: patch.warpDetourMode ?? warpDetourMode, + warpLicenseKey: patch.warpLicenseKey ?? warpLicenseKey, + warpCleanIp: patch.warpCleanIp ?? warpCleanIp, + warpPort: patch.warpPort ?? warpPort, + warpNoise: patch.warpNoise ?? warpNoise, + ); } SingboxConfigOption toSingbox({ @@ -179,98 +191,57 @@ class ConfigOptionEntity with ConfigOptionEntityMappable { rules: rules, ); } + + factory ConfigOptionEntity.fromJson(Map json) => + _$ConfigOptionEntityFromJson(json); } -@MappableClass( - caseStyle: CaseStyle.paramCase, - ignoreNull: true, - includeCustomMappers: [ - OptionalRangeJsonMapper(), - IntervalInSecondsMapper(), - ], -) -class ConfigOptionPatch with ConfigOptionPatchMappable { - const ConfigOptionPatch({ - this.serviceMode, - this.logLevel, - this.resolveDestination, - this.ipv6Mode, - this.remoteDnsAddress, - this.remoteDnsDomainStrategy, - this.directDnsAddress, - this.directDnsDomainStrategy, - this.mixedPort, - this.localDnsPort, - this.tunImplementation, - this.mtu, - this.strictRoute, - this.connectionTestUrl, - this.urlTestInterval, - this.enableClashApi, - this.clashApiPort, - this.bypassLan, - this.allowConnectionFromLan, - this.enableFakeDns, - this.enableDnsRouting, - this.independentDnsCache, - this.enableTlsFragment, - this.tlsFragmentSize, - this.tlsFragmentSleep, - this.enableTlsMixedSniCase, - this.enableTlsPadding, - this.tlsPaddingSize, - this.enableMux, - this.muxPadding, - this.muxMaxStreams, - this.muxProtocol, - this.enableWarp, - this.warpDetourMode, - this.warpLicenseKey, - this.warpCleanIp, - this.warpPort, - this.warpNoise, - }); +@freezed +class ConfigOptionPatch with _$ConfigOptionPatch { + const ConfigOptionPatch._(); - final ServiceMode? serviceMode; - final LogLevel? logLevel; - final bool? resolveDestination; - @MappableField(key: "ipv6-mode") - final IPv6Mode? ipv6Mode; - final String? remoteDnsAddress; - final DomainStrategy? remoteDnsDomainStrategy; - final String? directDnsAddress; - final DomainStrategy? directDnsDomainStrategy; - final int? mixedPort; - final int? localDnsPort; - final TunImplementation? tunImplementation; - final int? mtu; - final bool? strictRoute; - final String? connectionTestUrl; - final Duration? urlTestInterval; - final bool? enableClashApi; - final int? clashApiPort; - final bool? bypassLan; - final bool? allowConnectionFromLan; - final bool? enableFakeDns; - final bool? enableDnsRouting; - final bool? independentDnsCache; - final bool? enableTlsFragment; - final OptionalRange? tlsFragmentSize; - final OptionalRange? tlsFragmentSleep; - final bool? enableTlsMixedSniCase; - final bool? enableTlsPadding; - final OptionalRange? tlsPaddingSize; - final bool? enableMux; - final bool? muxPadding; - final int? muxMaxStreams; - final MuxProtocol? muxProtocol; - final bool? enableWarp; - final WarpDetourMode? warpDetourMode; - final String? warpLicenseKey; - final String? warpCleanIp; - final int? warpPort; - final OptionalRange? warpNoise; + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory ConfigOptionPatch({ + ServiceMode? serviceMode, + LogLevel? logLevel, + bool? resolveDestination, + IPv6Mode? ipv6Mode, + String? remoteDnsAddress, + DomainStrategy? remoteDnsDomainStrategy, + String? directDnsAddress, + DomainStrategy? directDnsDomainStrategy, + int? mixedPort, + int? localDnsPort, + TunImplementation? tunImplementation, + int? mtu, + bool? strictRoute, + String? connectionTestUrl, + @IntervalInSecondsConverter() Duration? urlTestInterval, + bool? enableClashApi, + int? clashApiPort, + bool? bypassLan, + bool? allowConnectionFromLan, + bool? enableFakeDns, + bool? enableDnsRouting, + bool? independentDnsCache, + bool? enableTlsFragment, + @OptionalRangeJsonConverter() OptionalRange? tlsFragmentSize, + @OptionalRangeJsonConverter() OptionalRange? tlsFragmentSleep, + bool? enableTlsMixedSniCase, + bool? enableTlsPadding, + @OptionalRangeJsonConverter() OptionalRange? tlsPaddingSize, + bool? enableMux, + bool? muxPadding, + int? muxMaxStreams, + MuxProtocol? muxProtocol, + bool? enableWarp, + WarpDetourMode? warpDetourMode, + String? warpLicenseKey, + String? warpCleanIp, + int? warpPort, + @OptionalRangeJsonConverter() OptionalRange? warpNoise, + }) = _ConfigOptionPatch; - Map delta() => - toMap()..removeWhere((key, value) => value == null); + factory ConfigOptionPatch.fromJson(Map json) => + _$ConfigOptionPatchFromJson(json); } diff --git a/lib/singbox/model/singbox_config_enum.dart b/lib/singbox/model/singbox_config_enum.dart index 10d616a3..49c157a7 100644 --- a/lib/singbox/model/singbox_config_enum.dart +++ b/lib/singbox/model/singbox_config_enum.dart @@ -1,24 +1,19 @@ import 'dart:io'; -import 'package:dart_mappable/dart_mappable.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hiddify/core/localization/translations.dart'; import 'package:hiddify/utils/platform_utils.dart'; -part 'singbox_config_enum.mapper.dart'; - -@MappableEnum() +@JsonEnum(valueField: 'key') enum ServiceMode { - @MappableValue("proxy") - proxy, + proxy("proxy"), + systemProxy("system-proxy"), + tun("vpn"), + tunService("vpn-service"); - @MappableValue("system-proxy") - systemProxy, + const ServiceMode(this.key); - @MappableValue("vpn") - tun, - - @MappableValue("vpn-service") - tunService; + final String key; static ServiceMode get defaultMode => PlatformUtils.isDesktop ? systemProxy : tun; @@ -44,19 +39,16 @@ enum ServiceMode { }; } -@MappableEnum() +@JsonEnum(valueField: 'key') enum IPv6Mode { - @MappableValue("ipv4_only") - disable, + disable("ipv4_only"), + enable("prefer_ipv4"), + prefer("prefer_ipv6"), + only("ipv6_only"); - @MappableValue("prefer_ipv4") - enable, + const IPv6Mode(this.key); - @MappableValue("prefer_ipv6") - prefer, - - @MappableValue("ipv6_only") - only; + final String key; String present(TranslationsEn t) => switch (this) { disable => t.settings.config.ipv6Modes.disable, @@ -66,21 +58,12 @@ enum IPv6Mode { }; } -@MappableEnum() +@JsonEnum(valueField: 'key') enum DomainStrategy { - @MappableValue("") auto(""), - - @MappableValue("prefer_ipv6") preferIpv6("prefer_ipv6"), - - @MappableValue("prefer_ipv4") preferIpv4("prefer_ipv4"), - - @MappableValue("ipv4_only") ipv4Only("ipv4_only"), - - @MappableValue("ipv6_only") ipv6Only("ipv6_only"); const DomainStrategy(this.key); @@ -93,21 +76,18 @@ enum DomainStrategy { }; } -@MappableEnum() enum TunImplementation { mixed, system, gVisor; } -@MappableEnum() enum MuxProtocol { h2mux, smux, yamux; } -@MappableEnum() enum WarpDetourMode { outbound, inbound; diff --git a/lib/singbox/model/singbox_config_option.dart b/lib/singbox/model/singbox_config_option.dart index 71af3dd1..2bed15c6 100644 --- a/lib/singbox/model/singbox_config_option.dart +++ b/lib/singbox/model/singbox_config_option.dart @@ -1,117 +1,72 @@ import 'dart:convert'; -import 'package:dart_mappable/dart_mappable.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hiddify/core/model/optional_range.dart'; import 'package:hiddify/core/utils/json_converters.dart'; import 'package:hiddify/features/log/model/log_level.dart'; import 'package:hiddify/singbox/model/singbox_config_enum.dart'; import 'package:hiddify/singbox/model/singbox_rule.dart'; -part 'singbox_config_option.mapper.dart'; +part 'singbox_config_option.freezed.dart'; +part 'singbox_config_option.g.dart'; -@MappableClass( - caseStyle: CaseStyle.paramCase, - includeCustomMappers: [ - OptionalRangeJsonMapper(), - IntervalInSecondsMapper(), - ], -) -class SingboxConfigOption with SingboxConfigOptionMappable { - const SingboxConfigOption({ - required this.executeConfigAsIs, - required this.logLevel, - required this.resolveDestination, - required this.ipv6Mode, - required this.remoteDnsAddress, - required this.remoteDnsDomainStrategy, - required this.directDnsAddress, - required this.directDnsDomainStrategy, - required this.mixedPort, - required this.localDnsPort, - required this.tunImplementation, - required this.mtu, - required this.strictRoute, - required this.connectionTestUrl, - required this.urlTestInterval, - required this.enableClashApi, - required this.clashApiPort, - required this.enableTun, - required this.enableTunService, - required this.setSystemProxy, - required this.bypassLan, - required this.allowConnectionFromLan, - required this.enableFakeDns, - required this.enableDnsRouting, - required this.independentDnsCache, - required this.enableTlsFragment, - required this.tlsFragmentSize, - required this.tlsFragmentSleep, - required this.enableTlsMixedSniCase, - required this.enableTlsPadding, - required this.tlsPaddingSize, - required this.enableMux, - required this.muxPadding, - required this.muxMaxStreams, - required this.muxProtocol, - required this.enableWarp, - required this.warpDetourMode, - required this.warpLicenseKey, - required this.warpCleanIp, - required this.warpPort, - required this.warpNoise, - required this.geoipPath, - required this.geositePath, - required this.rules, - }); +@freezed +class SingboxConfigOption with _$SingboxConfigOption { + const SingboxConfigOption._(); - final bool executeConfigAsIs; - final LogLevel logLevel; - final bool resolveDestination; - @MappableField(key: "ipv6-mode") - final IPv6Mode ipv6Mode; - final String remoteDnsAddress; - final DomainStrategy remoteDnsDomainStrategy; - final String directDnsAddress; - final DomainStrategy directDnsDomainStrategy; - final int mixedPort; - final int localDnsPort; - final TunImplementation tunImplementation; - final int mtu; - final bool strictRoute; - final String connectionTestUrl; - final Duration urlTestInterval; - final bool enableClashApi; - final int clashApiPort; - final bool enableTun; - final bool enableTunService; - final bool setSystemProxy; - final bool bypassLan; - final bool allowConnectionFromLan; - final bool enableFakeDns; - final bool enableDnsRouting; - final bool independentDnsCache; - final bool enableTlsFragment; - final OptionalRange tlsFragmentSize; - final OptionalRange tlsFragmentSleep; - final bool enableTlsMixedSniCase; - final bool enableTlsPadding; - final OptionalRange tlsPaddingSize; - final bool enableMux; - final bool muxPadding; - final int muxMaxStreams; - final MuxProtocol muxProtocol; - final bool enableWarp; - final WarpDetourMode warpDetourMode; - final String warpLicenseKey; - final String warpCleanIp; - final int warpPort; - final OptionalRange warpNoise; - final String geoipPath; - final String geositePath; - final List rules; + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory SingboxConfigOption({ + required bool executeConfigAsIs, + required LogLevel logLevel, + required bool resolveDestination, + required IPv6Mode ipv6Mode, + required String remoteDnsAddress, + required DomainStrategy remoteDnsDomainStrategy, + required String directDnsAddress, + required DomainStrategy directDnsDomainStrategy, + required int mixedPort, + required int localDnsPort, + required TunImplementation tunImplementation, + required int mtu, + required bool strictRoute, + required String connectionTestUrl, + @IntervalInSecondsConverter() required Duration urlTestInterval, + required bool enableClashApi, + required int clashApiPort, + required bool enableTun, + required bool enableTunService, + required bool setSystemProxy, + required bool bypassLan, + required bool allowConnectionFromLan, + required bool enableFakeDns, + required bool enableDnsRouting, + required bool independentDnsCache, + required bool enableTlsFragment, + @OptionalRangeJsonConverter() required OptionalRange tlsFragmentSize, + @OptionalRangeJsonConverter() required OptionalRange tlsFragmentSleep, + required bool enableTlsMixedSniCase, + required bool enableTlsPadding, + @OptionalRangeJsonConverter() required OptionalRange tlsPaddingSize, + required bool enableMux, + required bool muxPadding, + required int muxMaxStreams, + required MuxProtocol muxProtocol, + required bool enableWarp, + required WarpDetourMode warpDetourMode, + required String warpLicenseKey, + required String warpCleanIp, + required int warpPort, + @OptionalRangeJsonConverter() required OptionalRange warpNoise, + required String geoipPath, + required String geositePath, + required List rules, + }) = _SingboxConfigOption; String format() { const encoder = JsonEncoder.withIndent(' '); - return encoder.convert(toMap()); + return encoder.convert(toJson()); } + + factory SingboxConfigOption.fromJson(Map json) => + _$SingboxConfigOptionFromJson(json); } diff --git a/lib/singbox/model/singbox_rule.dart b/lib/singbox/model/singbox_rule.dart index d93b2562..b927ffee 100644 --- a/lib/singbox/model/singbox_rule.dart +++ b/lib/singbox/model/singbox_rule.dart @@ -1,37 +1,35 @@ -import 'package:dart_mappable/dart_mappable.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; -part 'singbox_rule.mapper.dart'; +part 'singbox_rule.freezed.dart'; +part 'singbox_rule.g.dart'; -@MappableClass() -class SingboxRule with SingboxRuleMappable { - const SingboxRule({ - this.domains, - this.ip, - this.port, - this.protocol, - this.network = RuleNetwork.tcpAndUdp, - this.outbound = RuleOutbound.proxy, - }); +@freezed +class SingboxRule with _$SingboxRule { + const SingboxRule._(); - final String? domains; - final String? ip; - final String? port; - final String? protocol; - final RuleNetwork network; - final RuleOutbound outbound; + @JsonSerializable(fieldRename: FieldRename.kebab) + const factory SingboxRule({ + String? domains, + String? ip, + String? port, + String? protocol, + @Default(RuleNetwork.tcpAndUdp) RuleNetwork network, + @Default(RuleOutbound.proxy) RuleOutbound outbound, + }) = _SingboxRule; + + factory SingboxRule.fromJson(Map json) => + _$SingboxRuleFromJson(json); } -@MappableEnum() enum RuleOutbound { proxy, bypass, block } -@MappableEnum() +@JsonEnum(valueField: 'key') enum RuleNetwork { - @MappableValue("") - tcpAndUdp, + tcpAndUdp(""), + tcp("tcp"), + udp("udp"); - @MappableValue("tcp") - tcp, + const RuleNetwork(this.key); - @MappableValue("udp") - udp; + final String? key; } diff --git a/lib/singbox/service/ffi_singbox_service.dart b/lib/singbox/service/ffi_singbox_service.dart index 22036b66..3626c5b9 100644 --- a/lib/singbox/service/ffi_singbox_service.dart +++ b/lib/singbox/service/ffi_singbox_service.dart @@ -118,10 +118,10 @@ class FFISingboxService with InfraLogger implements SingboxService { @override TaskEither changeOptions(SingboxConfigOption options) { - final json = options.toJson(); return TaskEither( () => CombineWorker().execute( () { + final json = jsonEncode(options.toJson()); final err = _box .changeConfigOptions(json.toNativeUtf8().cast()) .cast() diff --git a/lib/singbox/service/platform_singbox_service.dart b/lib/singbox/service/platform_singbox_service.dart index bdf96804..2aadacf5 100644 --- a/lib/singbox/service/platform_singbox_service.dart +++ b/lib/singbox/service/platform_singbox_service.dart @@ -80,7 +80,7 @@ class PlatformSingboxService with InfraLogger implements SingboxService { loggy.debug("changing options"); await methodChannel.invokeMethod( "change_config_options", - options.toJson(), + jsonEncode(options.toJson()), ); return right(unit); },