Change mapping

This commit is contained in:
problematicconsumer
2024-02-17 11:58:34 +03:30
parent 0aeb0e346f
commit 3541f8e3db
9 changed files with 269 additions and 364 deletions

View File

@@ -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<OptionalRange> {
const OptionalRangeJsonMapper();
class OptionalRangeJsonConverter
implements JsonConverter<OptionalRange, String> {
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();
}

View File

@@ -1,11 +1,11 @@
import 'package:dart_mappable/dart_mappable.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
class IntervalInSecondsMapper extends SimpleMapper<Duration> {
const IntervalInSecondsMapper();
class IntervalInSecondsConverter implements JsonConverter<Duration, int> {
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;
}

View File

@@ -34,7 +34,7 @@ class ConfigOptionRepositoryImpl
@override
Either<ConfigOptionFailure, ConfigOptionEntity> 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<ConfigOptionFailure, Unit> 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<void> updateByJson(
Map<String, dynamic> 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) {

View File

@@ -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<String, dynamic> 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<String, dynamic> delta() =>
toMap()..removeWhere((key, value) => value == null);
factory ConfigOptionPatch.fromJson(Map<String, dynamic> json) =>
_$ConfigOptionPatchFromJson(json);
}

View File

@@ -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;

View File

@@ -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<SingboxRule> 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<SingboxRule> rules,
}) = _SingboxConfigOption;
String format() {
const encoder = JsonEncoder.withIndent(' ');
return encoder.convert(toMap());
return encoder.convert(toJson());
}
factory SingboxConfigOption.fromJson(Map<String, dynamic> json) =>
_$SingboxConfigOptionFromJson(json);
}

View File

@@ -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<String, dynamic> 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;
}

View File

@@ -118,10 +118,10 @@ class FFISingboxService with InfraLogger implements SingboxService {
@override
TaskEither<String, Unit> changeOptions(SingboxConfigOption options) {
final json = options.toJson();
return TaskEither(
() => CombineWorker().execute(
() {
final json = jsonEncode(options.toJson());
final err = _box
.changeConfigOptions(json.toNativeUtf8().cast())
.cast<Utf8>()

View File

@@ -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);
},