//fake-ip / redir-host enum EnhancedMode { fakeIp, redirHost; String get name { switch (this) { case EnhancedMode.fakeIp: return 'fake-ip'; case EnhancedMode.redirHost: return 'redir-host'; default: return ''; } } String get value { switch (this) { case EnhancedMode.fakeIp: return 'fake-ip'; case EnhancedMode.redirHost: return 'redir-host'; default: return ''; } } } class DNSConfig { final bool enable; final String listen; final bool ipv6; final String enhancedMode; final List defaultNameserver; final List nameserver; final List proxyServerNameserver; final Map nameserverPolicy; final String? fakeIpRange; final List? fakeIpFilter; final List? fallback; final FallbackFilter? fallbackFilter; DNSConfig({ required this.enable, required this.listen, required this.ipv6, required this.enhancedMode, required this.defaultNameserver, required this.nameserver, required this.proxyServerNameserver, required this.nameserverPolicy, this.fakeIpRange, this.fakeIpFilter, this.fallbackFilter, this.fallback }); factory DNSConfig.fromMap(Map map) { return DNSConfig( enable: map['enable'], listen: map['listen'], ipv6: map['ipv6'], enhancedMode: map['enhanced-mode'], defaultNameserver: List.from(map['default-nameserver']), nameserver: List.from(map['nameserver']), proxyServerNameserver: List.from(map['proxy-server-nameserver']), nameserverPolicy: Map.from(map['nameserver-policy']).map((key, value) => MapEntry(key, value)), fakeIpRange: map['fake-ip-range'], fakeIpFilter: map.containsKey('fake-ip-filter') ? List.from(map['fake-ip-filter']) : null, fallback: map.containsKey('fallback') ? List.from(map['fallback']) : null, fallbackFilter: map.containsKey('fallback-filter') ? FallbackFilter() : null, ); } Map toJson() { return { 'enable': enable, 'listen': listen, 'ipv6': ipv6, 'enhanced-mode': enhancedMode, 'default-nameserver': defaultNameserver, 'nameserver': nameserver, 'proxy-server-nameserver': proxyServerNameserver, 'nameserver-policy': nameserverPolicy.map((key, value) => MapEntry(key, value)), if (fakeIpRange != null) 'fake-ip-range': fakeIpRange, if (fakeIpFilter != null) 'fake-ip-filter': fakeIpFilter, if (fallback != null) 'fallback': fallback, if (fallbackFilter != null) 'fallback-filter': fallbackFilter, }; } String toYaml() { var yaml = ''' dns: enable: $enable listen: $listen ipv6: $ipv6 enhanced-mode: $enhancedMode'''; if (fakeIpRange != null) { yaml += '\n fake-ip-range: $fakeIpRange'; } if (fakeIpFilter != null && fakeIpFilter!.isNotEmpty) { yaml += '\n fake-ip-filter:'; for (var filter in fakeIpFilter!) { yaml += '\n - $filter'; } } final fallback = this.fallback; if(fallback != null){ yaml += '\n fallback:\n - ${fallback.map((ns) => ns).join('\n - ')}'; } yaml += '\n default-nameserver:\n - ${defaultNameserver.map((ns) => ns).join('\n - ')}'; yaml += '\n nameserver:\n - ${_formatYamlList(nameserver)}'; yaml += '\n proxy-server-nameserver:\n - ${proxyServerNameserver.map((ns) => ns).join('\n - ')}'; if (fallbackFilter != null) { yaml += '\n${fallbackFilter!.toYaml()}'; } yaml += '\n nameserver-policy:\n${_mapToYaml(nameserverPolicy)}'; return yaml; } String _formatYamlList(List list) { return list.map((item) => item.contains('#') ? "'$item'" : item).join('\n - '); } String _mapToYaml(Map map) { var yamlString = ''; map.forEach((key, value) { if (value is String) { yamlString += " '$key': '$value'\n"; } else if (value is List) { var formattedValues = value.map((v) => "'$v'").join(', '); yamlString += " '$key': [$formattedValues]\n"; } }); return yamlString; } } class FallbackFilter { final bool? geoip; final String? geoipCode; final List? geosite; final List? ipcidr; final List? domain; FallbackFilter({ this.geoip, this.geoipCode, this.geosite, this.ipcidr, this.domain, }); String toYaml() { var yaml = 'fallback-filter:\n'; if (geoip != null) yaml += ' geoip: $geoip\n'; if (geoipCode != null) yaml += " geoip-code: '$geoipCode'\n"; if (geosite != null && geosite!.isNotEmpty) { yaml += ' geosite:\n - ${geosite!.join('\n - ')}\n'; } if (ipcidr != null && ipcidr!.isNotEmpty) { yaml += ' ipcidr:\n - ${ipcidr!.join('\n - ')}\n'; } if (domain != null && domain!.isNotEmpty) { yaml += ' domain:\n - ${domain!.map((d) => "'$d'").join('\n - ')}\n'; } return yaml; } }