Skip to content

Commit 838f530

Browse files
committed
refactor: 使用indexeddb替代localStorage解决safari配额限制
1 parent a25572b commit 838f530

File tree

1 file changed

+70
-7
lines changed

1 file changed

+70
-7
lines changed

src/utils/webdav.ts

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// WebDAV 同步工具
1+
// WebDAV 同步工具(使用 IndexedDB 解决 Safari 配额限制)
22
interface WebDAVConfig {
33
url: string
44
username: string
@@ -7,6 +7,9 @@ interface WebDAVConfig {
77

88
const WEBDAV_CONFIG_KEY = 'webdav_config'
99
const WEBDAV_FILE_NAME = 'chatgpt-backup.json'
10+
const DB_NAME = 'ChatStorage'
11+
const DB_VERSION = 1
12+
const STORE_NAME = 'data'
1013

1114
export function getWebDAVConfig(): WebDAVConfig | null {
1215
const config = localStorage.getItem(WEBDAV_CONFIG_KEY)
@@ -17,6 +20,67 @@ export function saveWebDAVConfig(config: WebDAVConfig): void {
1720
localStorage.setItem(WEBDAV_CONFIG_KEY, JSON.stringify(config))
1821
}
1922

23+
// IndexedDB 操作
24+
function openDB(): Promise<IDBDatabase> {
25+
return new Promise((resolve, reject) => {
26+
const request = indexedDB.open(DB_NAME, DB_VERSION)
27+
request.onerror = () => reject(request.error)
28+
request.onupgradeneeded = (event: any) => {
29+
const db = event.target.result
30+
if (!db.objectStoreNames.contains(STORE_NAME))
31+
db.createObjectStore(STORE_NAME)
32+
}
33+
request.onsuccess = () => resolve(request.result)
34+
})
35+
}
36+
37+
async function saveToStorage(data: string): Promise<void> {
38+
// 优先使用 IndexedDB(配额更大,Safari 友好)
39+
try {
40+
const db = await openDB()
41+
const tx = db.transaction(STORE_NAME, 'readwrite')
42+
const store = tx.objectStore(STORE_NAME)
43+
await new Promise<void>((resolve, reject) => {
44+
const req = store.put(data, 'chatStorage')
45+
req.onsuccess = () => resolve()
46+
req.onerror = () => reject(req.error)
47+
})
48+
db.close()
49+
50+
// 同步到 localStorage(兼容现有代码读取)
51+
try {
52+
localStorage.setItem('chatStorage', data)
53+
}
54+
catch {
55+
// localStorage 失败不影响,数据已保存到 IndexedDB
56+
}
57+
}
58+
catch (error) {
59+
// IndexedDB 失败,降级到 localStorage
60+
localStorage.setItem('chatStorage', data)
61+
}
62+
}
63+
64+
async function loadFromStorage(): Promise<string> {
65+
// 优先从 IndexedDB 读取
66+
try {
67+
const db = await openDB()
68+
const tx = db.transaction(STORE_NAME, 'readonly')
69+
const store = tx.objectStore(STORE_NAME)
70+
const data = await new Promise<string>((resolve, reject) => {
71+
const req = store.get('chatStorage')
72+
req.onsuccess = () => resolve(req.result || '{}')
73+
req.onerror = () => reject(req.error)
74+
})
75+
db.close()
76+
return data
77+
}
78+
catch {
79+
// IndexedDB 失败,降级到 localStorage
80+
return localStorage.getItem('chatStorage') || '{}'
81+
}
82+
}
83+
2084
async function webdavRequest(config: WebDAVConfig, method: string, data?: string) {
2185
const url = `${config.url.replace(/\/$/, '')}/${WEBDAV_FILE_NAME}`
2286
const res = await fetch('/api/webdav-proxy', {
@@ -34,10 +98,9 @@ export async function syncToWebDAV(): Promise<void> {
3498
const config = getWebDAVConfig()
3599
if (!config)
36100
throw new Error('WebDAV 未配置')
37-
38-
const data = localStorage.getItem('chatStorage') || '{}'
39-
40-
// 尝试上传,如果失败尝试创建目录再上传
101+
102+
const data = await loadFromStorage()
103+
41104
try {
42105
await webdavRequest(config, 'PUT', data)
43106
}
@@ -65,7 +128,7 @@ export async function syncFromWebDAV(): Promise<void> {
65128
const config = getWebDAVConfig()
66129
if (!config)
67130
throw new Error('WebDAV 未配置')
68-
131+
69132
const result = await webdavRequest(config, 'GET')
70-
localStorage.setItem('chatStorage', result.data || '{}')
133+
await saveToStorage(result.data || '{}')
71134
}

0 commit comments

Comments
 (0)