geo data config

This commit is contained in:
pompurin404 2024-08-08 19:30:33 +08:00
parent afaeea2aac
commit db6804e25a
No known key found for this signature in database
15 changed files with 248 additions and 30 deletions

View File

@ -238,8 +238,8 @@ async function downloadFile(url, path) {
const resolveMmdb = () =>
resolveResource({
file: 'Country.mmdb',
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb`
file: 'country.mmdb',
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb`
})
const resolveGeosite = () =>
resolveResource({
@ -249,7 +249,12 @@ const resolveGeosite = () =>
const resolveGeoIP = () =>
resolveResource({
file: 'geoip.dat',
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat`
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.dat`
})
const resolveASN = () =>
resolveResource({
file: 'ASN.mmdb',
downloadURL: `https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb`
})
const resolveEnableLoopback = () =>
resolveResource({
@ -285,6 +290,7 @@ const tasks = [
{ name: 'mmdb', func: resolveMmdb, retry: 5 },
{ name: 'geosite', func: resolveGeosite, retry: 5 },
{ name: 'geoip', func: resolveGeoIP, retry: 5 },
{ name: 'asn', func: resolveASN, retry: 5 },
{
name: 'font',
func: resolveFont,

View File

@ -85,6 +85,13 @@ export const mihomoChangeProxy = async (group: string, proxy: string): Promise<I
})) as IMihomoProxy
}
export const mihomoUpgradeGeo = async (): Promise<void> => {
const instance = await getAxios()
return instance.post('/configs/geo').catch((e) => {
return e.response.data
})
}
export const mihomoProxyDelay = async (proxy: string, url?: string): Promise<IMihomoDelay> => {
const appConfig = getAppConfig()
const { delayTestUrl, delayTestTimeout } = appConfig

View File

@ -58,7 +58,7 @@ function initConfig(): void {
}
function initFiles(): void {
const fileList = ['Country.mmdb', 'geoip.dat', 'geosite.dat']
const fileList = ['country.mmdb', 'geoip.dat', 'geosite.dat', 'ASN.mmdb']
for (const file of fileList) {
const targetPath = path.join(mihomoWorkDir(), file)
const testTargrtPath = path.join(mihomoTestDir(), file)

View File

@ -6,6 +6,7 @@ import {
mihomoProxies,
mihomoProxyDelay,
mihomoRules,
mihomoUpgradeGeo,
mihomoVersion,
patchMihomoConfig,
startMihomoConnections,
@ -34,6 +35,7 @@ import { triggerSysProxy } from '../resolve/sysproxy'
import { checkUpdate } from '../resolve/autoUpdater'
import { exePath, mihomoCorePath, mihomoWorkConfigPath } from './dirs'
import { execSync } from 'child_process'
import yaml from 'yaml'
import fs from 'fs'
export function registerIpcMainHandlers(): void {
@ -43,6 +45,7 @@ export function registerIpcMainHandlers(): void {
ipcMain.handle('mihomoRules', mihomoRules)
ipcMain.handle('mihomoProxies', mihomoProxies)
ipcMain.handle('mihomoChangeProxy', (_e, group, proxy) => mihomoChangeProxy(group, proxy))
ipcMain.handle('mihomoUpgradeGeo', mihomoUpgradeGeo)
ipcMain.handle('mihomoProxyDelay', (_e, proxy, url) => mihomoProxyDelay(proxy, url))
ipcMain.handle('startMihomoLogs', startMihomoLogs)
ipcMain.handle('stopMihomoLogs', stopMihomoLogs)
@ -71,6 +74,7 @@ export function registerIpcMainHandlers(): void {
ipcMain.handle('encryptString', (_e, str) => safeStorage.encryptString(str))
ipcMain.handle('getFilePath', getFilePath)
ipcMain.handle('readTextFile', (_e, filePath) => readTextFile(filePath))
ipcMain.handle('getRuntimeConfigStr', getRuntimeConfigStr)
ipcMain.handle('getRuntimeConfig', getRuntimeConfig)
ipcMain.handle('checkUpdate', () => checkUpdate())
ipcMain.handle('getVersion', () => app.getVersion())
@ -91,10 +95,14 @@ function readTextFile(filePath: string): string {
return fs.readFileSync(filePath, 'utf8')
}
function getRuntimeConfig(): string {
function getRuntimeConfigStr(): string {
return fs.readFileSync(mihomoWorkConfigPath(), 'utf8')
}
function getRuntimeConfig(): Record<string, unknown> {
return yaml.parse(getRuntimeConfigStr())
}
async function setupFirewall(): Promise<void> {
return new Promise((resolve, reject) => {
const removeCommand = `

View File

@ -58,6 +58,15 @@ export const defaultControledMihomoConfig: Partial<IMihomoConfig> = {
}
},
'skip-domain': ['+.push.apple.com']
},
'geo-auto-update': false,
'geo-update-interval': 24,
'geodata-mode': false,
'geox-url': {
geoip: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.dat',
geosite: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat',
mmdb: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb',
asn: 'https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb'
}
}

View File

@ -15,9 +15,9 @@ import SniffCard from '@renderer/components/sider/sniff-card'
import OverrideCard from '@renderer/components/sider/override-card'
import ConnCard from '@renderer/components/sider/conn-card'
import LogCard from '@renderer/components/sider/log-card'
import MihomoCoreCard from './components/sider/mihomo-core-card.tsx'
import TestCard from './components/sider/test-card.js'
import UpdaterButton from './components/updater/updater-button.js'
import MihomoCoreCard from '@renderer/components/sider/mihomo-core-card'
import ResourceCard from '@renderer/components/sider/resource-card'
import UpdaterButton from '@renderer/components/updater/updater-button'
const App: React.FC = () => {
const { setTheme } = useTheme()
@ -63,9 +63,24 @@ const App: React.FC = () => {
/>
</div>
</div>
<div className="m-2">
<OutboundModeSwitcher />
</div>
{/* <div className="grid">
<SysproxySwitcher />
<TunSwitcher />
<ProfileCard />
<ProxyCard />
<MihomoCoreCard />
<ConnCard />
<DNSCard />
<SniffCard />
<LogCard />
<RuleCard />
<TestCard />
<OverrideCard />
</div> */}
<div className="flex justify-between mx-2 mb-2">
<SysproxySwitcher />
<TunSwitcher />
@ -86,7 +101,7 @@ const App: React.FC = () => {
<RuleCard />
</div>
<div className="flex justify-between mx-2">
<TestCard />
<ResourceCard />
<OverrideCard />
</div>
</div>

View File

@ -2,7 +2,7 @@ import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button } from
import React, { useEffect, useState } from 'react'
import MonacoEditor, { monaco } from 'react-monaco-editor'
import { useTheme } from 'next-themes'
import { getRuntimeConfig } from '@renderer/utils/ipc'
import { getRuntimeConfigStr } from '@renderer/utils/ipc'
interface Props {
onClose: () => void
}
@ -23,7 +23,7 @@ const ConfigViewer: React.FC<Props> = (props) => {
}
const getContent = async (): Promise<void> => {
setCurrData(await getRuntimeConfig())
setCurrData(await getRuntimeConfigStr())
}
useEffect(() => {

View File

@ -46,7 +46,7 @@ const ProfileCard: React.FC = () => {
>
{info?.name}
</h3>
<div>
<div className="flex">
<Button
isIconOnly
size="sm"

View File

@ -1,18 +1,18 @@
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
import React from 'react'
import { TbWorldCheck } from 'react-icons/tb'
import { FaLayerGroup } from 'react-icons/fa6'
import { useLocation, useNavigate } from 'react-router-dom'
const TestCard: React.FC = () => {
const ResourceCard: React.FC = () => {
const navigate = useNavigate()
const location = useLocation()
const match = location.pathname.includes('/tests')
const match = location.pathname.includes('/resources')
return (
<Card
className={`w-[50%] mr-1 mb-2 ${match ? 'bg-primary' : ''}`}
isPressable
onPress={() => navigate('/tests')}
onPress={() => navigate('/resources')}
>
<CardBody className="pb-1 pt-0 px-0">
<div className="flex justify-between">
@ -22,7 +22,7 @@ const TestCard: React.FC = () => {
variant="flat"
color="default"
>
<TbWorldCheck
<FaLayerGroup
color="default"
className={`${match ? 'text-white' : 'text-foreground'} text-[24px] font-bold`}
/>
@ -31,11 +31,11 @@ const TestCard: React.FC = () => {
</CardBody>
<CardFooter className="pt-1">
<h3 className={`select-none text-md font-bold ${match ? 'text-white' : 'text-foreground'}`}>
</h3>
</CardFooter>
</Card>
)
}
export default TestCard
export default ResourceCard

View File

@ -0,0 +1,163 @@
import { Button, Input, Switch, Tab, Tabs } from '@nextui-org/react'
import BasePage from '@renderer/components/base/base-page'
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 { mihomoUpgradeGeo } from '@renderer/utils/ipc'
import { useState } from 'react'
import { IoMdRefresh } from 'react-icons/io'
const Resources: React.FC = () => {
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
const {
'geox-url': geoxUrl = {
geoip: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.dat',
geosite: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat',
mmdb: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb',
asn: 'https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb'
},
'geodata-mode': geoMode = false,
'geo-auto-update': geoAutoUpdate = false,
'geo-update-interval': geoUpdateInterval = 24
} = controledMihomoConfig || {}
const [geoipInput, setGeoIpInput] = useState(geoxUrl.geoip)
const [geositeInput, setGeositeInput] = useState(geoxUrl.geosite)
const [mmdbInput, setMmdbInput] = useState(geoxUrl.mmdb)
const [asnInput, setAsnInput] = useState(geoxUrl.asn)
const [updating, setUpdating] = useState(false)
return (
<BasePage title="外部资源">
<SettingCard>
<SettingItem title="GeoIP 数据库" divider>
<div className="flex">
{geoipInput !== geoxUrl.geoip && (
<Button
size="sm"
color="primary"
className="mr-2"
onPress={() => {
patchControledMihomoConfig({ 'geox-url': { ...geoxUrl, geoip: geoipInput } })
}}
>
</Button>
)}
<Input size="sm" value={geoipInput} onValueChange={setGeoIpInput} />
</div>
</SettingItem>
<SettingItem title="GeoSite 数据库" divider>
<div className="flex">
{geositeInput !== geoxUrl.geosite && (
<Button
size="sm"
color="primary"
className="mr-2"
onPress={() => {
patchControledMihomoConfig({ 'geox-url': { ...geoxUrl, geosite: geositeInput } })
}}
>
</Button>
)}
<Input size="sm" value={geositeInput} onValueChange={setGeositeInput} />
</div>
</SettingItem>
<SettingItem title="MMDB 数据库" divider>
<div className="flex">
{mmdbInput !== geoxUrl.mmdb && (
<Button
size="sm"
color="primary"
className="mr-2"
onPress={() => {
patchControledMihomoConfig({ 'geox-url': { ...geoxUrl, mmdb: mmdbInput } })
}}
>
</Button>
)}
<Input size="sm" value={mmdbInput} onValueChange={setMmdbInput} />
</div>
</SettingItem>
<SettingItem title="ASN 数据库" divider>
<div className="flex">
{asnInput !== geoxUrl.asn && (
<Button
size="sm"
color="primary"
className="mr-2"
onPress={() => {
patchControledMihomoConfig({ 'geox-url': { ...geoxUrl, asn: asnInput } })
}}
>
</Button>
)}
<Input size="sm" value={asnInput} onValueChange={setAsnInput} />
</div>
</SettingItem>
<SettingItem title="GeoIP 数据模式" divider>
<Tabs
size="sm"
color="primary"
selectedKey={geoMode ? 'dat' : 'db'}
onSelectionChange={(key) => {
patchControledMihomoConfig({ 'geodata-mode': key === 'dat' })
}}
>
<Tab key="db" title="db" />
<Tab key="dat" title="dat" />
</Tabs>
</SettingItem>
<SettingItem
title="自动更新 Geo 数据库"
actions={
<Button
size="sm"
isIconOnly
variant="light"
onPress={() => {
setUpdating(true)
mihomoUpgradeGeo()
.catch((e) => {
new Notification('更新失败', { body: e.message })
})
.finally(() => {
new Notification('Geo 数据库更新成功')
setUpdating(false)
})
}}
>
<IoMdRefresh className={`text-lg ${updating ? 'animate-spin' : ''}`} />
</Button>
}
divider={geoAutoUpdate}
>
<Switch
size="sm"
isSelected={geoAutoUpdate}
onValueChange={(v) => {
patchControledMihomoConfig({ 'geo-auto-update': v })
}}
/>
</SettingItem>
{geoAutoUpdate && (
<SettingItem title="更新间隔(小时)">
<Input
size="sm"
type="number"
className="w-[100px]"
value={geoUpdateInterval.toString()}
onValueChange={(v) => {
patchControledMihomoConfig({ 'geo-update-interval': parseInt(v) })
}}
/>
</SettingItem>
)}
</SettingCard>
</BasePage>
)
}
export default Resources

View File

@ -1,7 +0,0 @@
import BasePage from '@renderer/components/base/base-page'
const Tests: React.FC = () => {
return <BasePage title="测试"></BasePage>
}
export default Tests

View File

@ -9,7 +9,7 @@ import Connections from '@renderer/pages/connections'
import Mihomo from '@renderer/pages/mihomo'
import Sysproxy from '@renderer/pages/syspeoxy'
import Tun from '@renderer/pages/tun'
import Tests from '@renderer/pages/tests'
import Resources from '@renderer/pages/resources'
import DNS from '@renderer/pages/dns'
import Sniffer from '@renderer/pages/sniffer'
@ -35,8 +35,8 @@ const routes = [
element: <Rules />
},
{
path: '/tests',
element: <Tests />
path: '/resources',
element: <Resources />
},
{
path: '/dns',

View File

@ -22,6 +22,10 @@ export async function mihomoChangeProxy(group: string, proxy: string): Promise<I
return await window.electron.ipcRenderer.invoke('mihomoChangeProxy', group, proxy)
}
export async function mihomoUpgradeGeo(): Promise<void> {
return await window.electron.ipcRenderer.invoke('mihomoUpgradeGeo')
}
export async function mihomoProxyDelay(proxy: string, url?: string): Promise<IMihomoDelay> {
const res = await window.electron.ipcRenderer.invoke('mihomoProxyDelay', proxy, url)
return res
@ -135,7 +139,11 @@ export async function readTextFile(filePath: string): Promise<string> {
return await window.electron.ipcRenderer.invoke('readTextFile', filePath)
}
export async function getRuntimeConfig(): Promise<string> {
export async function getRuntimeConfigStr(): Promise<string> {
return await window.electron.ipcRenderer.invoke('getRuntimeConfigStr')
}
export async function getRuntimeConfig(): Promise<IMihomoConfig> {
return await window.electron.ipcRenderer.invoke('getRuntimeConfig')
}

View File

@ -246,6 +246,15 @@ interface IMihomoConfig {
'proxy-groups'?: []
rules?: []
hosts?: { [key: string]: string | string[] }
'geodata-mode'?: boolean
'geo-auto-update'?: boolean
'geo-update-interval'?: number
'geox-url'?: {
geoip?: string
geosite?: string
mmdb?: string
asn?: string
}
tun: IMihomoTunConfig
dns: IMihomoDNSConfig
sniffer: IMihomoSnifferConfig