diff --git a/src/main/config/controledMihomo.ts b/src/main/config/controledMihomo.ts index 0bf638a..34d6aa5 100644 --- a/src/main/config/controledMihomo.ts +++ b/src/main/config/controledMihomo.ts @@ -21,7 +21,8 @@ export function setControledMihomoConfig(patch: Partial): void { } if (patch.dns) { const oldDns = controledMihomoConfig.dns || {} - const newDns = Object.assign(oldDns, patch.dns) + const newDns = { ...patch.dns } + newDns.enable = oldDns.enable patch.dns = newDns } if (patch.sniffer) { diff --git a/src/renderer/src/pages/dns.tsx b/src/renderer/src/pages/dns.tsx index a6208be..e643606 100644 --- a/src/renderer/src/pages/dns.tsx +++ b/src/renderer/src/pages/dns.tsx @@ -4,11 +4,14 @@ import { MdDeleteForever } from 'react-icons/md' import SettingCard from '@renderer/components/base/base-setting-card' import SettingItem from '@renderer/components/base/base-setting-item' import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config' +import { useAppConfig } from '@renderer/hooks/use-app-config' import { restartCore } from '@renderer/utils/ipc' -import React, { Key, useState } from 'react' +import React, { Key, ReactNode, useState } from 'react' const DNS: React.FC = () => { const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig() + const { appConfig, patchAppConfig } = useAppConfig() + const { nameserverPolicy, useNameserverPolicy } = appConfig || {} const { dns, hosts } = controledMihomoConfig || {} const { ipv6 = false, @@ -24,7 +27,9 @@ const DNS: React.FC = () => { 'enhanced-mode': enhancedMode = 'fake-ip', 'use-hosts': useHosts = false, 'use-system-hosts': useSystemHosts = false, - nameserver = ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query'] + 'respect-rules': respectRules = false, + nameserver = ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query'], + 'proxy-server-nameserver': proxyServerNameserver = [] } = dns || {} const [values, setValues] = useState({ @@ -34,45 +39,76 @@ const DNS: React.FC = () => { fakeIPRange, fakeIPFilter, useSystemHosts, + respectRules, nameserver, + proxyServerNameserver, + useNameserverPolicy, + nameserverPolicy: Object.entries(nameserverPolicy || {}).map(([domain, value]) => ({ + domain, + value + })), hosts: Object.entries(hosts || {}).map(([domain, value]) => ({ domain, value })) }) const handleListChange = (type: string, value: string, index: number): void => { - const newValues = [...values[type]] - if (index === newValues.length) { - if (value.trim() !== '') { - newValues.push(value) + const list = [...values[type]] + if (value.trim()) { + if (index < list.length) { + list[index] = value + } else if (list.length < 4) { + list.push(value) } } else { - if (value.trim() === '') { - newValues.splice(index, 1) - } else { - newValues[index] = value - } + list.splice(index, 1) } - setValues({ ...values, [type]: newValues }) + setValues({ ...values, [type]: list.slice(0, 4) }) } - const handleHostsChange = (domain: string, value: string, index: number): void => { - const processValue = (val: string): string | string[] => - val.includes(',') ? val.split(',').map((s) => s.trim()) : val.trim() - const isEmpty = (d: string, v: string | string[]): boolean => - d === '' && (Array.isArray(v) ? v.every((item) => item === '') : v === '') - const newHosts = [...values.hosts] - if (!isEmpty(domain.trim(), processValue(value))) { - if (index === newHosts.length) { - newHosts.push({ domain: domain.trim(), value: processValue(value) }) - } else { - newHosts[index] = { domain: domain.trim(), value: processValue(value) } - } - } else if (index < newHosts.length) { - newHosts.splice(index, 1) - } - setValues({ ...values, hosts: newHosts }) + const renderListInputs = (type: string, placeholder: string): ReactNode => { + const currentItems = values[type].slice(0, 4) + const showNewLine = currentItems.length < 4 && currentItems.every((item) => item.trim() !== '') + + return [...currentItems, ...(showNewLine ? [''] : [])].slice(0, 4).map((item, index) => ( +
+ handleListChange(type, v, index)} + /> + {index < values[type].length && ( + + )} +
+ )) + } + + const handleSubkeyChange = (type: string, domain: string, value: string, index: number): void => { + const list = [...values[type]] + const processedValue = value.includes(',') + ? value.split(',').map((s: string) => s.trim()) + : value.trim() + if (domain || processedValue) list[index] = { domain: domain.trim(), value: processedValue } + else list.splice(index, 1) + setValues({ ...values, [type]: list }) } const onSave = async (patch: Partial): Promise => { + await patchAppConfig({ + nameserverPolicy: Object.fromEntries( + values.nameserverPolicy.map(({ domain, value }) => [domain, value]) + ), + useNameserverPolicy: values.useNameserverPolicy + }) await patchControledMihomoConfig(patch) await restartCore() } @@ -85,22 +121,29 @@ const DNS: React.FC = () => { size="sm" color="primary" onPress={() => { - const hostsObject = values.hosts.reduce((acc, { domain, value }) => { - if (domain) { - acc[domain] = value - } - return acc - }, {}) + const hostsObject = Object.fromEntries( + values.hosts.map(({ domain, value }) => [domain, value]) + ) + const dnsConfig = { + ipv6: values.ipv6, + 'fake-ip-range': values.fakeIPRange, + 'fake-ip-filter': values.fakeIPFilter, + 'enhanced-mode': values.enhancedMode, + 'use-hosts': values.useHosts, + 'use-system-hosts': values.useSystemHosts, + 'respect-rules': values.respectRules, + nameserver: values.nameserver, + 'proxy-server-nameserver': values.proxyServerNameserver, + fallback: [], + 'fallback-filter': {} + } + if (values.useNameserverPolicy) { + dnsConfig['nameserver-policy'] = Object.fromEntries( + values.nameserverPolicy.map(({ domain, value }) => [domain, value]) + ) + } onSave({ - dns: { - ipv6: values.ipv6, - 'fake-ip-range': values.fakeIPRange, - 'fake-ip-filter': values.fakeIPFilter, - 'enhanced-mode': values.enhancedMode, - 'use-hosts': values.useHosts, - 'use-system-hosts': values.useSystemHosts, - nameserver: values.nameserver - }, + dns: dnsConfig, hosts: hostsObject }) }} @@ -136,28 +179,7 @@ const DNS: React.FC = () => {

真实IP回应

- {[...values.fakeIPFilter, ''].map((ns, index) => ( -
- handleListChange('fakeIPFilter', v, index)} - /> - {index < values.fakeIPFilter.length && ( - - )} -
- ))} + {renderListInputs('fakeIPFilter', '例: +.lan')}
@@ -171,32 +193,87 @@ const DNS: React.FC = () => { }} /> + + { + setValues({ ...values, respectRules: v }) + }} + /> + +
-

DNS服务器

- {[...values.nameserver, ''].map((ns, index) => ( -
- handleListChange('nameserver', v, index)} - /> - {index < values.nameserver.length && ( - - )} -
- ))} +

代理节点域名解析

+ {renderListInputs('proxyServerNameserver', '例: tls://223.5.5.5')}
+
+

DNS服务器

+ {renderListInputs('nameserver', '例: tls://223.5.5.5')} +
+ + + { + setValues({ ...values, useNameserverPolicy: v }) + }} + /> + + {values.useNameserverPolicy && ( +
+
+

+ {[...values.nameserverPolicy, { domain: '', value: '' }].map( + ({ domain, value }, index) => ( +
+
+ + handleSubkeyChange( + 'nameserverPolicy', + v, + Array.isArray(value) ? value.join(',') : value, + index + ) + } + /> +
+ : +
+ + handleSubkeyChange('nameserverPolicy', domain, v, index) + } + /> + {index < values.nameserverPolicy.length && ( + + )} +
+
+ ) + )} +
+
+ )} { placeholder="域名" value={domain} onValueChange={(v) => - handleHostsChange(v, Array.isArray(value) ? value.join(',') : value, index) + handleSubkeyChange( + 'hosts', + v, + Array.isArray(value) ? value.join(',') : value, + index + ) } /> @@ -238,7 +320,7 @@ const DNS: React.FC = () => { fullWidth placeholder="域名或IP" value={Array.isArray(value) ? value.join(',') : value} - onValueChange={(v) => handleHostsChange(domain, v, index)} + onValueChange={(v) => handleSubkeyChange('hosts', domain, v, index)} /> {index < values.hosts.length && ( diff --git a/src/shared/types.d.ts b/src/shared/types.d.ts index 01795f4..c58d1a9 100644 --- a/src/shared/types.d.ts +++ b/src/shared/types.d.ts @@ -198,6 +198,8 @@ interface IAppConfig { delayTestUrl?: string delayTestTimeout?: number encryptedPassword?: Buffer + useNameserverPolicy: boolean + nameserverPolicy: { [key: string]: string | string[] } } interface IMihomoTunConfig { @@ -240,6 +242,8 @@ interface IMihomoDNSConfig { 'use-system-hosts'?: boolean 'respect-rules'?: boolean nameserver?: string[] + fallback?: string[] + 'fallback-filter'?: { [key: string]: boolean | string | string[] } 'proxy-server-nameserver'?: string[] 'nameserver-policy'?: { [key: string]: string | string[] } }