Files
MWClash/lib/models/clash_config.dart
chen08209 676f2d058a Add windows server mode start process verify
Add linux deb dependencies

Add backup recovery strategy select

Support custom text scaling

Optimize the display of different text scale

Optimize windows setup experience

Optimize startTun performance

Optimize android tv experience

Optimize default option

Optimize computed text size

Optimize hyperOS freeform window

Add developer mode

Update core

Optimize more details
2025-05-01 00:02:29 +08:00

474 lines
12 KiB
Dart

// ignore_for_file: invalid_annotation_target
import 'package:fl_clash/common/common.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../enum/enum.dart';
part 'generated/clash_config.freezed.dart';
part 'generated/clash_config.g.dart';
typedef HostsMap = Map<String, String>;
const defaultClashConfig = ClashConfig();
const defaultTun = Tun();
const defaultDns = Dns();
const defaultGeoXUrl = GeoXUrl();
const defaultMixedPort = 7890;
const defaultKeepAliveInterval = 30;
const defaultBypassPrivateRouteAddress = [
"1.0.0.0/8",
"2.0.0.0/7",
"4.0.0.0/6",
"8.0.0.0/7",
"11.0.0.0/8",
"12.0.0.0/6",
"16.0.0.0/4",
"32.0.0.0/3",
"64.0.0.0/3",
"96.0.0.0/4",
"112.0.0.0/5",
"120.0.0.0/6",
"124.0.0.0/7",
"126.0.0.0/8",
"128.0.0.0/3",
"160.0.0.0/5",
"168.0.0.0/8",
"169.0.0.0/9",
"169.128.0.0/10",
"169.192.0.0/11",
"169.224.0.0/12",
"169.240.0.0/13",
"169.248.0.0/14",
"169.252.0.0/15",
"169.255.0.0/16",
"170.0.0.0/7",
"172.0.0.0/12",
"172.32.0.0/11",
"172.64.0.0/10",
"172.128.0.0/9",
"173.0.0.0/8",
"174.0.0.0/7",
"176.0.0.0/4",
"192.0.0.0/9",
"192.128.0.0/11",
"192.160.0.0/13",
"192.169.0.0/16",
"192.170.0.0/15",
"192.172.0.0/14",
"192.176.0.0/12",
"192.192.0.0/10",
"193.0.0.0/8",
"194.0.0.0/7",
"196.0.0.0/6",
"200.0.0.0/5",
"208.0.0.0/4",
"240.0.0.0/5",
"248.0.0.0/6",
"252.0.0.0/7",
"254.0.0.0/8",
"255.0.0.0/9",
"255.128.0.0/10",
"255.192.0.0/11",
"255.224.0.0/12",
"255.240.0.0/13",
"255.248.0.0/14",
"255.252.0.0/15",
"255.254.0.0/16",
"255.255.0.0/17",
"255.255.128.0/18",
"255.255.192.0/19",
"255.255.224.0/20",
"255.255.240.0/21",
"255.255.248.0/22",
"255.255.252.0/23",
"255.255.254.0/24",
"255.255.255.0/25",
"255.255.255.128/26",
"255.255.255.192/27",
"255.255.255.224/28",
"255.255.255.240/29",
"255.255.255.248/30",
"255.255.255.252/31",
"255.255.255.254/32",
"::/1",
"8000::/2",
"c000::/3",
"e000::/4",
"f000::/5",
"f800::/6",
"fe00::/9",
"fec0::/10"
];
@freezed
class ProxyGroup with _$ProxyGroup {
const factory ProxyGroup({
required String name,
@JsonKey(
fromJson: GroupType.parseProfileType,
)
required GroupType type,
List<String>? proxies,
List<String>? use,
int? interval,
bool? lazy,
String? url,
int? timeout,
@JsonKey(name: "max-failed-times") int? maxFailedTimes,
String? filter,
@JsonKey(name: "expected-filter") String? excludeFilter,
@JsonKey(name: "exclude-type") String? excludeType,
@JsonKey(name: "expected-status") dynamic expectedStatus,
bool? hidden,
String? icon,
}) = _ProxyGroup;
factory ProxyGroup.fromJson(Map<String, Object?> json) =>
_$ProxyGroupFromJson(json);
}
@freezed
class RuleProvider with _$RuleProvider {
const factory RuleProvider({
required String name,
}) = _RuleProvider;
factory RuleProvider.fromJson(Map<String, Object?> json) =>
_$RuleProviderFromJson(json);
}
@freezed
class Tun with _$Tun {
const factory Tun({
@Default(false) bool enable,
@Default(appName) String device,
@JsonKey(name: "auto-route") @Default(false) bool autoRoute,
@Default(TunStack.mixed) TunStack stack,
@JsonKey(name: "dns-hijack") @Default(["any:53"]) List<String> dnsHijack,
@JsonKey(name: "route-address") @Default([]) List<String> routeAddress,
}) = _Tun;
factory Tun.fromJson(Map<String, Object?> json) => _$TunFromJson(json);
factory Tun.safeFormJson(Map<String, Object?>? json) {
if (json == null) {
return defaultTun;
}
try {
return Tun.fromJson(json);
} catch (_) {
return defaultTun;
}
}
}
@freezed
class FallbackFilter with _$FallbackFilter {
const factory FallbackFilter({
@Default(true) bool geoip,
@Default("CN") @JsonKey(name: "geoip-code") String geoipCode,
@Default(["gfw"]) List<String> geosite,
@Default(["240.0.0.0/4"]) List<String> ipcidr,
@Default([
"+.google.com",
"+.facebook.com",
"+.youtube.com",
])
List<String> domain,
}) = _FallbackFilter;
factory FallbackFilter.fromJson(Map<String, Object?> json) =>
_$FallbackFilterFromJson(json);
}
@freezed
class Dns with _$Dns {
const factory Dns({
@Default(true) bool enable,
@Default("0.0.0.0:1053") String listen,
@Default(false) @JsonKey(name: "prefer-h3") bool preferH3,
@Default(true) @JsonKey(name: "use-hosts") bool useHosts,
@Default(true) @JsonKey(name: "use-system-hosts") bool useSystemHosts,
@Default(false) @JsonKey(name: "respect-rules") bool respectRules,
@Default(false) bool ipv6,
@Default(["223.5.5.5"])
@JsonKey(name: "default-nameserver")
List<String> defaultNameserver,
@Default(DnsMode.fakeIp)
@JsonKey(name: "enhanced-mode")
DnsMode enhancedMode,
@Default("198.18.0.1/16")
@JsonKey(name: "fake-ip-range")
String fakeIpRange,
@Default([
"*.lan",
"localhost.ptlogin2.qq.com",
])
@JsonKey(name: "fake-ip-filter")
List<String> fakeIpFilter,
@Default({
"www.baidu.com": "114.114.114.114",
"+.internal.crop.com": "10.0.0.1",
"geosite:cn": "https://doh.pub/dns-query"
})
@JsonKey(name: "nameserver-policy")
Map<String, String> nameserverPolicy,
@Default([
"https://doh.pub/dns-query",
"https://dns.alidns.com/dns-query",
])
List<String> nameserver,
@Default([
"tls://8.8.4.4",
"tls://1.1.1.1",
])
List<String> fallback,
@Default([
"https://doh.pub/dns-query",
])
@JsonKey(name: "proxy-server-nameserver")
List<String> proxyServerNameserver,
@Default(FallbackFilter())
@JsonKey(name: "fallback-filter")
FallbackFilter fallbackFilter,
}) = _Dns;
factory Dns.fromJson(Map<String, Object?> json) => _$DnsFromJson(json);
factory Dns.safeDnsFromJson(Map<String, Object?> json) {
try {
return Dns.fromJson(json);
} catch (_) {
return const Dns();
}
}
}
@freezed
class GeoXUrl with _$GeoXUrl {
const factory GeoXUrl({
@Default(
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb",
)
String mmdb,
@Default(
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb",
)
String asn,
@Default(
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat",
)
String geoip,
@Default(
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat",
)
String geosite,
}) = _GeoXUrl;
factory GeoXUrl.fromJson(Map<String, Object?> json) =>
_$GeoXUrlFromJson(json);
factory GeoXUrl.safeFormJson(Map<String, Object?>? json) {
if (json == null) {
return defaultGeoXUrl;
}
try {
return GeoXUrl.fromJson(json);
} catch (_) {
return defaultGeoXUrl;
}
}
}
@freezed
class ParsedRule with _$ParsedRule {
const factory ParsedRule({
required RuleAction ruleAction,
String? content,
String? ruleTarget,
String? ruleProvider,
String? subRule,
@Default(false) bool noResolve,
@Default(false) bool src,
}) = _ParsedRule;
factory ParsedRule.parseString(String value) {
final splits = value.split(",");
final shortSplits = splits
.where(
(item) => !item.contains("src") && !item.contains("no-resolve"),
)
.toList();
final ruleAction = RuleAction.values.firstWhere(
(item) => item.value == shortSplits.first,
orElse: () => RuleAction.DOMAIN,
);
String? subRule;
String? ruleTarget;
if (ruleAction == RuleAction.SUB_RULE) {
subRule = shortSplits.last;
} else {
ruleTarget = shortSplits.last;
}
String? content;
String? ruleProvider;
if (ruleAction == RuleAction.RULE_SET) {
ruleProvider = shortSplits.sublist(1, shortSplits.length - 1).join(",");
} else {
content = shortSplits.sublist(1, shortSplits.length - 1).join(",");
}
return ParsedRule(
ruleAction: ruleAction,
content: content,
src: splits.contains("src"),
ruleProvider: ruleProvider,
noResolve: splits.contains("no-resolve"),
subRule: subRule,
ruleTarget: ruleTarget,
);
}
}
extension ParsedRuleExt on ParsedRule {
String get value {
return [
ruleAction.value,
ruleAction == RuleAction.RULE_SET ? ruleProvider : content,
ruleAction == RuleAction.SUB_RULE ? subRule : ruleTarget,
if (ruleAction.hasParams) ...[
if (src) "src",
if (noResolve) "no-resolve",
]
].join(",");
}
}
@freezed
class Rule with _$Rule {
const factory Rule({
required String id,
required String value,
}) = _Rule;
factory Rule.value(String value) {
return Rule(
value: value,
id: utils.uuidV4,
);
}
factory Rule.fromJson(Map<String, Object?> json) => _$RuleFromJson(json);
}
@freezed
class SubRule with _$SubRule {
const factory SubRule({
required String name,
}) = _SubRule;
factory SubRule.fromJson(Map<String, Object?> json) =>
_$SubRuleFromJson(json);
}
_genRule(List<dynamic>? rules) {
if (rules == null) {
return [];
}
return rules
.map(
(item) => Rule.value(item),
)
.toList();
}
List<RuleProvider> _genRuleProviders(Map<String, dynamic> json) {
return json.entries.map((entry) => RuleProvider(name: entry.key)).toList();
}
List<SubRule> _genSubRules(Map<String, dynamic> json) {
return json.entries
.map(
(entry) => SubRule(
name: entry.key,
),
)
.toList();
}
@freezed
class ClashConfigSnippet with _$ClashConfigSnippet {
const factory ClashConfigSnippet({
@Default([]) @JsonKey(name: "proxy-groups") List<ProxyGroup> proxyGroups,
@JsonKey(fromJson: _genRule) @Default([]) List<Rule> rule,
@JsonKey(name: "rule-providers", fromJson: _genRuleProviders)
@Default([])
List<RuleProvider> ruleProvider,
@JsonKey(name: "sub-rules", fromJson: _genSubRules)
@Default([])
List<SubRule> subRules,
}) = _ClashConfigSnippet;
factory ClashConfigSnippet.fromJson(Map<String, Object?> json) =>
_$ClashConfigSnippetFromJson(json);
}
@freezed
class ClashConfig with _$ClashConfig {
const factory ClashConfig({
@Default(defaultMixedPort) @JsonKey(name: "mixed-port") int mixedPort,
@Default(Mode.rule) Mode mode,
@Default(false) @JsonKey(name: "allow-lan") bool allowLan,
@Default(LogLevel.error) @JsonKey(name: "log-level") LogLevel logLevel,
@Default(false) bool ipv6,
@Default(FindProcessMode.off)
@JsonKey(
name: "find-process-mode",
unknownEnumValue: FindProcessMode.always,
)
FindProcessMode findProcessMode,
@Default(defaultKeepAliveInterval)
@JsonKey(name: "keep-alive-interval")
int keepAliveInterval,
@Default(true) @JsonKey(name: "unified-delay") bool unifiedDelay,
@Default(true) @JsonKey(name: "tcp-concurrent") bool tcpConcurrent,
@Default(defaultTun) @JsonKey(fromJson: Tun.safeFormJson) Tun tun,
@Default(defaultDns) @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns,
@Default(defaultGeoXUrl)
@JsonKey(name: "geox-url", fromJson: GeoXUrl.safeFormJson)
GeoXUrl geoXUrl,
@Default(GeodataLoader.memconservative)
@JsonKey(name: "geodata-loader")
GeodataLoader geodataLoader,
@Default([]) @JsonKey(name: "proxy-groups") List<ProxyGroup> proxyGroups,
@Default([]) List<String> rule,
@JsonKey(name: "global-ua") String? globalUa,
@Default(ExternalControllerStatus.close)
@JsonKey(name: "external-controller")
ExternalControllerStatus externalController,
@Default({}) HostsMap hosts,
}) = _ClashConfig;
factory ClashConfig.fromJson(Map<String, Object?> json) =>
_$ClashConfigFromJson(json);
factory ClashConfig.safeFormJson(Map<String, Object?>? json) {
if (json == null) {
return defaultClashConfig;
}
try {
return ClashConfig.fromJson(json);
} catch (_) {
return defaultClashConfig;
}
}
}