From ed370457992102ba0e47311115acaa1453618de3 Mon Sep 17 00:00:00 2001 From: RT15548 Date: Tue, 30 Dec 2025 23:09:51 +0800 Subject: [PATCH] Add files via upload --- core/server-storage.js | 57 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/core/server-storage.js b/core/server-storage.js index e7bfdbc..d05fc50 100644 --- a/core/server-storage.js +++ b/core/server-storage.js @@ -20,7 +20,7 @@ class StorageFile { this._retryTimer = null; this._maxRetries = Number.isFinite(opts.maxRetries) ? opts.maxRetries : 5; const debounceMs = Number.isFinite(opts.debounceMs) ? opts.debounceMs : 2000; - this._saveDebounced = debounce(() => this.saveNow(), debounceMs); + this._saveDebounced = debounce(() => this.saveNow({ silent: true }), debounceMs); } async load() { @@ -71,12 +71,31 @@ class StorageFile { } } - async saveNow() { + /** + * 立即保存 + * @param {Object} options + * @param {boolean} options.silent - 静默模式:失败时不抛异常,返回 false + * @returns {Promise} 是否保存成功 + */ + async saveNow({ silent = true } = {}) { + // 🔧 核心修复:非静默模式等待当前保存完成 if (this._saving) { this._pendingSave = true; - return; + + if (!silent) { + await this._waitForSaveComplete(); + if (this._dirtyVersion > this._savedVersion) { + return this.saveNow({ silent }); + } + return this._dirtyVersion === this._savedVersion; + } + + return true; + } + + if (!this.cache || this._dirtyVersion === this._savedVersion) { + return true; } - if (!this.cache || this._dirtyVersion === this._savedVersion) return; this._saving = true; this._pendingSave = false; @@ -90,31 +109,55 @@ class StorageFile { headers: getRequestHeaders(), body: JSON.stringify({ name: this.filename, data: base64 }), }); - if (!res.ok) throw new Error(`HTTP ${res.status}`); + if (!res.ok) { + throw new Error(`服务器返回 ${res.status}`); + } + this._savedVersion = Math.max(this._savedVersion, versionToSave); this._retryCount = 0; if (this._retryTimer) { clearTimeout(this._retryTimer); this._retryTimer = null; } + return true; + } catch (err) { console.error('[ServerStorage] 保存失败:', err); this._retryCount++; + const delay = Math.min(30000, 2000 * (2 ** Math.max(0, this._retryCount - 1))); if (!this._retryTimer && this._retryCount <= this._maxRetries) { this._retryTimer = setTimeout(() => { this._retryTimer = null; - this.saveNow(); + this.saveNow({ silent: true }); }, delay); } + + if (!silent) { + throw err; + } + return false; + } finally { this._saving = false; + if (this._pendingSave || this._dirtyVersion > this._savedVersion) { this._saveDebounced(); } } } + /** 等待保存完成 */ + _waitForSaveComplete() { + return new Promise(resolve => { + const check = () => { + if (!this._saving) resolve(); + else setTimeout(check, 50); + }; + check(); + }); + } + clearCache() { this.cache = null; this._loading = null; @@ -137,4 +180,4 @@ class StorageFile { export const TasksStorage = new StorageFile('LittleWhiteBox_Tasks.json'); export const StoryOutlineStorage = new StorageFile('LittleWhiteBox_StoryOutline.json'); -export const NovelDrawStorage = new StorageFile('LittleWhiteBox_NovelDraw.json', { debounceMs: 800 }); \ No newline at end of file +export const NovelDrawStorage = new StorageFile('LittleWhiteBox_NovelDraw.json', { debounceMs: 800 });