improve error handling

This commit is contained in:
pompurin404 2024-08-13 17:34:36 +08:00
parent bedf3f8173
commit 2d6e8f5fd0
No known key found for this signature in database
17 changed files with 190 additions and 114 deletions

View File

@ -94,7 +94,7 @@ const ProfileItem: React.FC<Props> = (props) => {
return list return list
}, [info]) }, [info])
const onMenuAction = (key: Key): void => { const onMenuAction = async (key: Key): Promise<void> => {
switch (key) { switch (key) {
case 'edit-info': { case 'edit-info': {
setOpenInfo(true) setOpenInfo(true)
@ -105,7 +105,7 @@ const ProfileItem: React.FC<Props> = (props) => {
break break
} }
case 'delete': { case 'delete': {
removeProfileItem(info.id) await removeProfileItem(info.id)
mutateProfileConfig() mutateProfileConfig()
break break
} }
@ -177,15 +177,10 @@ const ProfileItem: React.FC<Props> = (props) => {
variant="light" variant="light"
color="default" color="default"
disabled={updating} disabled={updating}
onPress={() => { onPress={async () => {
setUpdating(true) setUpdating(true)
addProfileItem(info) await addProfileItem(info)
.catch((e) => {
alert(e)
})
.finally(() => {
setUpdating(false) setUpdating(false)
})
}} }}
> >
<IoMdRefresh <IoMdRefresh

View File

@ -115,16 +115,16 @@ const GeoData: React.FC = () => {
size="sm" size="sm"
isIconOnly isIconOnly
variant="light" variant="light"
onPress={() => { onPress={async () => {
setUpdating(true) setUpdating(true)
mihomoUpgradeGeo() try {
.catch((e) => { await mihomoUpgradeGeo()
new Notification('更新失败', { body: e.message })
})
.finally(() => {
new Notification('Geo 数据库更新成功') new Notification('Geo 数据库更新成功')
} catch (e) {
alert(e)
} finally {
setUpdating(false) setUpdating(false)
}) }
}} }}
> >
<IoMdRefresh className={`text-lg ${updating ? 'animate-spin' : ''}`} /> <IoMdRefresh className={`text-lg ${updating ? 'animate-spin' : ''}`} />

View File

@ -20,18 +20,22 @@ const ProxyProvider: React.FC = () => {
}, [data]) }, [data])
const [updating, setUpdating] = useState(Array(providers.length).fill(false)) const [updating, setUpdating] = useState(Array(providers.length).fill(false))
const onUpdate = (name: string, index: number): void => { const onUpdate = async (name: string, index: number): Promise<void> => {
setUpdating((prev) => { setUpdating((prev) => {
prev[index] = true prev[index] = true
return [...prev] return [...prev]
}) })
mihomoUpdateProxyProviders(name).finally(() => { try {
await mihomoUpdateProxyProviders(name)
mutate()
} catch (e) {
alert(e)
} finally {
setUpdating((prev) => { setUpdating((prev) => {
prev[index] = false prev[index] = false
return [...prev] return [...prev]
}) })
mutate() }
})
} }
if (!providers.length) { if (!providers.length) {

View File

@ -15,18 +15,22 @@ const RuleProvider: React.FC = () => {
}, [data]) }, [data])
const [updating, setUpdating] = useState(Array(providers.length).fill(false)) const [updating, setUpdating] = useState(Array(providers.length).fill(false))
const onUpdate = (name: string, index: number): void => { const onUpdate = async (name: string, index: number): Promise<void> => {
setUpdating((prev) => { setUpdating((prev) => {
prev[index] = true prev[index] = true
return [...prev] return [...prev]
}) })
mihomoUpdateRuleProviders(name).finally(() => { try {
await mihomoUpdateRuleProviders(name)
mutate()
} catch (e) {
alert(e)
} finally {
setUpdating((prev) => { setUpdating((prev) => {
prev[index] = false prev[index] = false
return [...prev] return [...prev]
}) })
mutate() }
})
} }
if (!providers.length) { if (!providers.length) {

View File

@ -22,9 +22,6 @@ const MihomoCoreCard: React.FC = () => {
useEffect(() => { useEffect(() => {
const token = PubSub.subscribe('mihomo-core-changed', () => { const token = PubSub.subscribe('mihomo-core-changed', () => {
mutate() mutate()
setTimeout(() => {
mutate()
}, 1000)
}) })
window.electron.ipcRenderer.on('mihomoMemory', (_e, info: IMihomoMemoryInfo) => { window.electron.ipcRenderer.on('mihomoMemory', (_e, info: IMihomoMemoryInfo) => {
setMem(info.inuse) setMem(info.inuse)
@ -70,11 +67,13 @@ const MihomoCoreCard: React.FC = () => {
variant="light" variant="light"
color="default" color="default"
onPress={async () => { onPress={async () => {
try {
await restartCore() await restartCore()
} catch (e) {
alert(e)
} finally {
mutate() mutate()
setTimeout(() => { }
mutate()
}, 2000)
}} }}
> >
<IoMdRefresh className={`${match ? 'text-white' : 'text-foreground'} text-[24px]`} /> <IoMdRefresh className={`${match ? 'text-white' : 'text-foreground'} text-[24px]`} />

View File

@ -87,11 +87,10 @@ const ProfileCard: React.FC = () => {
disabled={updating} disabled={updating}
variant="light" variant="light"
color="default" color="default"
onPress={() => { onPress={async () => {
setUpdating(true) setUpdating(true)
addProfileItem(info).finally(() => { await addProfileItem(info)
setUpdating(false) setUpdating(false)
})
}} }}
> >
<IoMdRefresh <IoMdRefresh

View File

@ -12,10 +12,15 @@ export const useAppConfig = (listenUpdate = false): RetuenType => {
const { data: appConfig, mutate: mutateAppConfig } = useSWR('getConfig', () => getAppConfig()) const { data: appConfig, mutate: mutateAppConfig } = useSWR('getConfig', () => getAppConfig())
const patchAppConfig = async (value: Partial<IAppConfig>): Promise<void> => { const patchAppConfig = async (value: Partial<IAppConfig>): Promise<void> => {
try {
await patch(value) await patch(value)
} catch (e) {
alert(e)
} finally {
mutateAppConfig() mutateAppConfig()
window.electron.ipcRenderer.send('appConfigUpdated') window.electron.ipcRenderer.send('appConfigUpdated')
} }
}
useEffect(() => { useEffect(() => {
if (!listenUpdate) return if (!listenUpdate) return

View File

@ -15,10 +15,15 @@ export const useControledMihomoConfig = (listenUpdate = false): RetuenType => {
) )
const patchControledMihomoConfig = async (value: Partial<IMihomoConfig>): Promise<void> => { const patchControledMihomoConfig = async (value: Partial<IMihomoConfig>): Promise<void> => {
try {
await patch(value) await patch(value)
} catch (e) {
alert(e)
} finally {
mutateControledMihomoConfig() mutateControledMihomoConfig()
window.electron.ipcRenderer.send('controledMihomoConfigUpdated') window.electron.ipcRenderer.send('controledMihomoConfigUpdated')
} }
}
useEffect(() => { useEffect(() => {
if (!listenUpdate) return if (!listenUpdate) return

View File

@ -22,24 +22,44 @@ export const useOverrideConfig = (): RetuenType => {
) )
const setOverrideConfig = async (config: IOverrideConfig): Promise<void> => { const setOverrideConfig = async (config: IOverrideConfig): Promise<void> => {
try {
await set(config) await set(config)
} catch (e) {
alert(e)
} finally {
mutateOverrideConfig() mutateOverrideConfig()
} }
}
const addOverrideItem = async (item: Partial<IOverrideItem>): Promise<void> => { const addOverrideItem = async (item: Partial<IOverrideItem>): Promise<void> => {
try {
await add(item) await add(item)
} catch (e) {
alert(e)
} finally {
mutateOverrideConfig() mutateOverrideConfig()
} }
}
const removeOverrideItem = async (id: string): Promise<void> => { const removeOverrideItem = async (id: string): Promise<void> => {
try {
await remove(id) await remove(id)
} catch (e) {
alert(e)
} finally {
mutateOverrideConfig() mutateOverrideConfig()
} }
}
const updateOverrideItem = async (item: IOverrideItem): Promise<void> => { const updateOverrideItem = async (item: IOverrideItem): Promise<void> => {
try {
await update(item) await update(item)
} catch (e) {
alert(e)
} finally {
mutateOverrideConfig() mutateOverrideConfig()
} }
}
return { return {
overrideConfig, overrideConfig,

View File

@ -25,29 +25,54 @@ export const useProfileConfig = (): RetuenType => {
) )
const setProfileConfig = async (config: IProfileConfig): Promise<void> => { const setProfileConfig = async (config: IProfileConfig): Promise<void> => {
try {
await set(config) await set(config)
} catch (e) {
alert(e)
} finally {
mutateProfileConfig() mutateProfileConfig()
} }
}
const addProfileItem = async (item: Partial<IProfileItem>): Promise<void> => { const addProfileItem = async (item: Partial<IProfileItem>): Promise<void> => {
try {
await add(item) await add(item)
} catch (e) {
alert(e)
} finally {
mutateProfileConfig() mutateProfileConfig()
} }
}
const removeProfileItem = async (id: string): Promise<void> => { const removeProfileItem = async (id: string): Promise<void> => {
try {
await remove(id) await remove(id)
} catch (e) {
alert(e)
} finally {
mutateProfileConfig() mutateProfileConfig()
} }
}
const updateProfileItem = async (item: IProfileItem): Promise<void> => { const updateProfileItem = async (item: IProfileItem): Promise<void> => {
try {
await update(item) await update(item)
} catch (e) {
alert(e)
} finally {
mutateProfileConfig() mutateProfileConfig()
} }
}
const changeCurrentProfile = async (id: string): Promise<void> => { const changeCurrentProfile = async (id: string): Promise<void> => {
try {
await change(id) await change(id)
} catch (e) {
alert(e)
} finally {
mutateProfileConfig() mutateProfileConfig()
} }
}
useEffect(() => { useEffect(() => {
window.electron.ipcRenderer.on('profileConfigUpdated', () => { window.electron.ipcRenderer.on('profileConfigUpdated', () => {

View File

@ -59,8 +59,14 @@ const Mihomo: React.FC = () => {
size="sm" size="sm"
selectedKeys={new Set([core])} selectedKeys={new Set([core])}
onSelectionChange={async (v) => { onSelectionChange={async (v) => {
try {
await patchAppConfig({ core: v.currentKey as 'mihomo' | 'mihomo-alpha' }) await patchAppConfig({ core: v.currentKey as 'mihomo' | 'mihomo-alpha' })
restartCore().then(() => PubSub.publish('mihomo-core-changed')) await restartCore()
} catch (e) {
alert(e)
} finally {
PubSub.publish('mihomo-core-changed')
}
}} }}
> >
<SelectItem key="mihomo">{CoreMap['mihomo']}</SelectItem> <SelectItem key="mihomo">{CoreMap['mihomo']}</SelectItem>

View File

@ -33,14 +33,9 @@ const Profiles: React.FC = () => {
const sensors = useSensors(useSensor(PointerSensor)) const sensors = useSensors(useSensor(PointerSensor))
const handleImport = async (): Promise<void> => { const handleImport = async (): Promise<void> => {
setImporting(true) setImporting(true)
try {
await addProfileItem({ name: '', type: 'remote', url }) await addProfileItem({ name: '', type: 'remote', url })
} catch (e) {
alert(e)
} finally {
setImporting(false) setImporting(false)
} }
}
const pageRef = useRef<HTMLDivElement>(null) const pageRef = useRef<HTMLDivElement>(null)
const onDragEnd = async (event: DragEndEvent): Promise<void> => { const onDragEnd = async (event: DragEndEvent): Promise<void> => {
@ -75,11 +70,11 @@ const Profiles: React.FC = () => {
if (event.dataTransfer?.files) { if (event.dataTransfer?.files) {
const file = event.dataTransfer.files[0] const file = event.dataTransfer.files[0]
if (file.name.endsWith('.yml') || file.name.endsWith('.yaml')) { if (file.name.endsWith('.yml') || file.name.endsWith('.yaml')) {
const content = await readTextFile(file.path)
try { try {
const content = await readTextFile(file.path)
await addProfileItem({ name: file.name, type: 'local', file: content }) await addProfileItem({ name: file.name, type: 'local', file: content })
} finally { } catch (e) {
setFileOver(false) alert(e)
} }
} else { } else {
alert('不支持的文件类型') alert('不支持的文件类型')
@ -135,14 +130,17 @@ const Profiles: React.FC = () => {
size="sm" size="sm"
color="primary" color="primary"
className="ml-2" className="ml-2"
onPress={() => { onPress={async () => {
getFilePath(['yml', 'yaml']).then(async (files) => { try {
const files = await getFilePath(['yml', 'yaml'])
if (files?.length) { if (files?.length) {
const content = await readTextFile(files[0]) const content = await readTextFile(files[0])
const fileName = files[0].split('/').pop()?.split('\\').pop() const fileName = files[0].split('/').pop()?.split('\\').pop()
await addProfileItem({ name: fileName, type: 'local', file: content }) await addProfileItem({ name: fileName, type: 'local', file: content })
} }
}) } catch (e) {
alert(e)
}
}} }}
> >
@ -167,11 +165,7 @@ const Profiles: React.FC = () => {
updateProfileItem={updateProfileItem} updateProfileItem={updateProfileItem}
info={item} info={item}
onClick={async () => { onClick={async () => {
try {
await changeCurrentProfile(item.id) await changeCurrentProfile(item.id)
} catch (e) {
alert(e)
}
}} }}
/> />
))} ))}

View File

@ -83,13 +83,12 @@ const Proxies: React.FC = () => {
return { groupCounts, allProxies } return { groupCounts, allProxies }
}, [groups, isOpen, proxyDisplayOrder]) }, [groups, isOpen, proxyDisplayOrder])
const onChangeProxy = (group: string, proxy: string): void => { const onChangeProxy = async (group: string, proxy: string): Promise<void> => {
mihomoChangeProxy(group, proxy).then(() => { await mihomoChangeProxy(group, proxy)
if (autoCloseConnection) { if (autoCloseConnection) {
mihomoCloseAllConnections() await mihomoCloseAllConnections()
} }
mutate() mutate()
})
} }
const onProxyDelay = async (proxy: string, url?: string): Promise<IMihomoDelay> => { const onProxyDelay = async (proxy: string, url?: string): Promise<IMihomoDelay> => {
@ -152,7 +151,7 @@ const Proxies: React.FC = () => {
style={{ height: 'calc(100vh - 50px)' }} style={{ height: 'calc(100vh - 50px)' }}
groupCounts={groupCounts} groupCounts={groupCounts}
groupContent={(index) => { groupContent={(index) => {
return ( return groups[index] ? (
<div <div
className={`w-full pt-2 ${index === groupCounts.length - 1 && !isOpen[index] ? 'pb-2' : ''} px-2`} className={`w-full pt-2 ${index === groupCounts.length - 1 && !isOpen[index] ? 'pb-2' : ''} px-2`}
> >
@ -242,6 +241,8 @@ const Proxies: React.FC = () => {
</CardBody> </CardBody>
</Card> </Card>
</div> </div>
) : (
<div>Never See This</div>
) )
}} }}
itemContent={(index, groupIndex) => { itemContent={(index, groupIndex) => {

View File

@ -86,13 +86,18 @@ const Settings: React.FC = () => {
<Switch <Switch
size="sm" size="sm"
isSelected={enable} isSelected={enable}
onValueChange={(v) => { onValueChange={async (v) => {
try {
if (v) { if (v) {
enableAutoRun() await enableAutoRun()
} else { } else {
disableAutoRun() await disableAutoRun()
} }
} catch (e) {
alert(e)
} finally {
mutate() mutate()
}
}} }}
/> />
</SettingItem> </SettingItem>
@ -196,17 +201,22 @@ const Settings: React.FC = () => {
<SettingItem title="检查更新" divider> <SettingItem title="检查更新" divider>
<Button <Button
size="sm" size="sm"
onPress={() => { onPress={async () => {
checkUpdate().then((v) => { try {
if (v) { const version = await checkUpdate()
new window.Notification(`v${v}版本已发布`, { body: '点击前往下载' }).onclick =
(): void => { if (version) {
open(`https://github.com/pompurin404/mihomo-party/releases/tag/v${v}`) new window.Notification(`v${version}版本已发布`, {
body: '点击前往下载'
}).onclick = (): void => {
open(`https://github.com/pompurin404/mihomo-party/releases/tag/v${version}`)
} }
} else { } else {
new window.Notification('当前已是最新版本', { body: '无需更新' }) new window.Notification('当前已是最新版本', { body: '无需更新' })
} }
}) } catch (e) {
alert(e)
}
}} }}
> >

View File

@ -5,7 +5,7 @@ import SettingItem from '@renderer/components/base/base-setting-item'
import PacEditorViewer from '@renderer/components/sysproxy/pac-editor-modal' import PacEditorViewer from '@renderer/components/sysproxy/pac-editor-modal'
import { useAppConfig } from '@renderer/hooks/use-app-config' import { useAppConfig } from '@renderer/hooks/use-app-config'
import { platform } from '@renderer/utils/init' import { platform } from '@renderer/utils/init'
import { triggerSysProxy } from '@renderer/utils/ipc' import { openUWPTool, triggerSysProxy } from '@renderer/utils/ipc'
import { Key, useState } from 'react' import { Key, useState } from 'react'
import React from 'react' import React from 'react'
import { MdDeleteForever } from 'react-icons/md' import { MdDeleteForever } from 'react-icons/md'
@ -90,7 +90,8 @@ const Sysproxy: React.FC = () => {
try { try {
await triggerSysProxy(true) await triggerSysProxy(true)
await patchAppConfig({ sysProxy: { enable: true } }) await patchAppConfig({ sysProxy: { enable: true } })
} catch { } catch (e) {
alert(e)
await patchAppConfig({ sysProxy: { enable: false } }) await patchAppConfig({ sysProxy: { enable: false } })
} }
} }
@ -141,8 +142,8 @@ const Sysproxy: React.FC = () => {
<SettingItem title="UWP 工具" divider> <SettingItem title="UWP 工具" divider>
<Button <Button
size="sm" size="sm"
onPress={() => { onPress={async () => {
window.electron.ipcRenderer.invoke('openUWPTool') await openUWPTool()
}} }}
> >
UWP UWP

View File

@ -71,13 +71,17 @@ const Tun: React.FC = () => {
size="sm" size="sm"
color="primary" color="primary"
isLoading={loading} isLoading={loading}
onPress={() => { onPress={async () => {
setLoading(true) setLoading(true)
setupFirewall() try {
.then(() => { await setupFirewall()
new Notification('防火墙重设成功') new Notification('防火墙重设成功')
}) await restartCore()
.finally(() => setLoading(false)) } catch (e) {
alert(e)
} finally {
setLoading(false)
}
}} }}
> >

View File

@ -233,6 +233,10 @@ export async function getPlatform(): Promise<NodeJS.Platform> {
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('platform')) return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('platform'))
} }
export async function openUWPTool(): Promise<void> {
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('openUWPTool'))
}
export async function setupFirewall(): Promise<void> { export async function setupFirewall(): Promise<void> {
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('setupFirewall')) return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('setupFirewall'))
} }