fix(openlist): 增加登录超时处理和重试机制

This commit is contained in:
VirtualHotBar
2026-03-04 22:03:11 +08:00
parent 2988382b35
commit 96ff7e4309
3 changed files with 69 additions and 34 deletions

View File

@@ -44,7 +44,13 @@ async function appStart(setStartStr: SetStartStrFn) {
if (appStarting) { return }//避免重新执行
appStarting = true
await init(setStartStr)//初始化功能
try {
await init(setStartStr)//初始化功能
} catch (e) {
appStarting = false
console.error('App init failed:', e)
return
}
reactRoot.render(<React.StrictMode>
<BrowserRouter future={{ v7_relativeSplatPath: true }}>

View File

@@ -189,7 +189,7 @@ export default function AddMount_page() {
<div>
<h2 style={{ fontSize: '1.5rem', marginBottom: '2rem', marginLeft: '1.8rem' }}>{!isEditMode ? t('add_mount') : t('edit_mount')}</h2>
{/* 基础选项 - 始终显示 */}
<div style={{ marginBottom: showAllOptions ? '1rem' : '0' }}>
<FormItem label={t('storage')}>
@@ -271,24 +271,23 @@ export default function AddMount_page() {
<Button type={cacheMode === 'minimal' ? 'primary' : 'secondary'} onClick={() => applyCachePreset('minimal')}>{t('preset_low_disk')}</Button>
<Button type={cacheMode === 'off' ? 'primary' : 'secondary'} onClick={() => applyCachePreset('off')}>{t('preset_compatibility')}</Button>
</Space>
<Alert
style={{ marginTop: '0.5rem' }}
type={cacheMode === 'full' ? 'warning' : 'info'}
content={
cacheMode === 'full'
? t('cache_mode_tip_full')
: cacheMode === 'off'
? t('cache_mode_tip_off')
: cacheMode === 'minimal'
? t('cache_mode_tip_minimal')
: t('cache_mode_tip_writes')
}
/>
</FormItem>
</>
}
{!showAllOptions && (
<Alert
style={{ marginTop: '0.5rem' }}
type={cacheMode === 'full' ? 'warning' : 'info'}
content={
cacheMode === 'full'
? t('cache_mode_tip_full')
: cacheMode === 'off'
? t('cache_mode_tip_off')
: cacheMode === 'minimal'
? t('cache_mode_tip_minimal')
: t('cache_mode_tip_writes')
}
/>
)}
{showAllOptions && isMacOS && (
<FormItem label={t('mount_backend')}>
<Select
@@ -333,7 +332,7 @@ export default function AddMount_page() {
<Button disabled={!storageName || !mountPath} onClick={async () => {
// 编辑模式下获取原始路径
const originalMountPath = isEditMode ? getURLSearchParam('mountPath') : '';
if (!isEditMode && getMountStorage(mountPath)) {
Notification.error({
title: t('error'),
@@ -354,13 +353,13 @@ export default function AddMount_page() {
}
mountPathTemp = formatPath(mountPathTemp, isWindows)
if (isEditMode) {
await editMountStorage({
storageName: storageName!,
mountPath: mountPathTemp,
parameters: parameters,
autoMount: autoMount
await editMountStorage({
storageName: storageName!,
mountPath: mountPathTemp,
parameters: parameters,
autoMount: autoMount
}, originalMountPath)
} else {
await addMountStorage(storageName!, mountPathTemp, parameters, autoMount)

View File

@@ -21,14 +21,30 @@ type OpenlistLoginResponse = {
async function openlist_login(username: string, password: string): Promise<string> {
const url = openlistInfo.endpoint.url + '/api/auth/login'
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 8000)
const timeoutMs = 15_000
const timeoutId = setTimeout(
() => controller.abort(new DOMException(`OpenList login timeout after ${timeoutMs}ms`, 'TimeoutError')),
timeoutMs
)
try {
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
signal: controller.signal
})
let res: Response
try {
res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
signal: controller.signal
})
} catch (e) {
if (controller.signal.aborted) {
const reason = controller.signal.reason
const reasonMessage = reason instanceof Error
? reason.message
: (typeof reason === 'string' ? reason : 'request aborted')
throw new Error(`OpenList login timed out: ${reasonMessage}`)
}
throw e
}
const text = await res.text().catch(() => '')
let json: OpenlistLoginResponse | undefined
@@ -61,9 +77,23 @@ async function getOpenlistToken(): Promise<string> {
}
const username = nmConfig.framework.openlist.user
const password = nmConfig.framework.openlist.password
const token = await openlist_login(username, password)
openlistInfo.endpoint.auth.token = token
return token
const maxAttempts = 3
let lastError: unknown
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const token = await openlist_login(username, password)
openlistInfo.endpoint.auth.token = token
return token
} catch (e) {
lastError = e
if (attempt < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, 500))
}
}
}
throw new Error(`OpenList login failed after ${maxAttempts} attempts: ${String(lastError)}`)
}
async function setOpenlistPass(pass: string) {