From 7853a14ce685f087317ef91f2025fbd3f55ee598 Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Fri, 18 Oct 2019 13:53:44 +0700 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20=D0=BE?= =?UTF-8?q?=D1=87=D0=B5=D1=80=D0=B5=D0=B4=D0=BD=D0=BE=D0=B9=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=BA=D0=B8=20ServerStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Reader/ServerStorage/ServerStorage.vue | 255 ++++++++---------- client/components/Reader/share/bookManager.js | 13 - 2 files changed, 113 insertions(+), 155 deletions(-) diff --git a/client/components/Reader/ServerStorage/ServerStorage.vue b/client/components/Reader/ServerStorage/ServerStorage.vue index 9c55ec3b..768196e9 100644 --- a/client/components/Reader/ServerStorage/ServerStorage.vue +++ b/client/components/Reader/ServerStorage/ServerStorage.vue @@ -13,6 +13,11 @@ import readerApi from '../../../api/reader'; import * as utils from '../../../share/utils'; import * as cryptoUtils from '../../../share/cryptoUtils'; +import localForage from 'localforage'; +const ssCacheStore = localForage.createInstance({ + name: 'ssCacheStore' +}); + export default @Component({ watch: { serverSyncEnabled: function() { @@ -58,35 +63,52 @@ class ServerStorage extends Vue { async init() { try { + this.cachedRecent = await ssCacheStore.getItem('recent'); + if (!this.cachedRecent) + await this.setCachedRecent({rev: 0, data: {}}); + + this.cachedRecentPatch = await ssCacheStore.getItem('recent-patch'); + if (!this.cachedRecentPatch) + await this.setCachedRecentPatch({rev: 0, data: {}}); + + this.cachedRecentMod = await ssCacheStore.getItem('recent-mod'); + if (!this.cachedRecentMod) + await this.setCachedRecentMod({rev: 0, data: {}}); + if (!this.serverStorageKey) { //генерируем новый ключ await this.generateNewServerStorageKey(); } else { await this.serverStorageKeyChanged(); } + bookManager.addEventListener(this.bookManagerEvent); } finally { this.inited = true; } } + async setCachedRecent(value) { + await ssCacheStore.setItem('recent', value); + this.cachedRecent = value; + } + + async setCachedRecentPatch(value) { + await ssCacheStore.setItem('recent-patch', value); + this.cachedRecentPatch = value; + } + + async setCachedRecentMod(value) { + await ssCacheStore.setItem('recent-mod', value); + this.cachedRecentMod = value; + } + async bookManagerEvent(eventName, itemKey) { if (!this.serverSyncEnabled) return; if (eventName == 'recent-changed') { if (itemKey) { - if (!this.recentDeltaInited) { - await this.loadRecent(); - this.warning('Функции сохранения на сервер пока недоступны'); - return; - } - - if (!this.recentDelta) - this.recentDelta = {}; - - this.recentDelta[itemKey] = _.cloneDeep(bookManager.recent[itemKey]); - this.debouncedSaveRecent(itemKey); } } @@ -340,46 +362,26 @@ class ServerStorage extends Vue { } } - async initRecentDelta() { - let recentDelta = null; - try { - recentDelta = await this.storageGet({recentDelta: {}}); - } catch(e) { - this.error(`Ошибка соединения с сервером: ${e.message}`); - return; - } - - if (recentDelta.state == 'success') { - recentDelta = recentDelta.items.recentDelta; - - if (recentDelta.rev == 0) - recentDelta.data = {}; - - this.recentDelta = recentDelta.data; - this.recentDeltaInited = true; - } else { - this.warning(`Неверный ответ сервера: ${recentDelta.state}`); - } - } - async loadRecent(skipRevCheck = false, doNotifySuccess = true) { if (!this.keyInited || !this.serverSyncEnabled || this.loadingRecent) return; - this.loadingRecent = true; try { - const oldRecentRev = bookManager.recentRev; - const oldRecentDeltaRev = bookManager.recentDeltaRev; //проверим ревизию на сервере + let query = {recent: {}, recentPatch: {}, recentMod: {}}; let revs = null; if (!skipRevCheck) { try { - revs = await this.storageCheck({recent: {}, recentDelta: {}}); - if (revs.state == 'success' && revs.items.recent.rev == oldRecentRev && - revs.items.recentDelta.rev == oldRecentDeltaRev) { - if (!this.recentDeltaInited) - await this.initRecentDelta(); - return; + revs = await this.storageCheck(query); + if (revs.state == 'success') { + if (revs.items.recent.rev != this.cachedRecent.rev) { + //no changes + } else if (revs.items.recentPatch.rev != this.cachedRecentPatch.rev) { + query = {recentPatch: {}, recentMod: {}}; + } else if (revs.items.recentMod.rev != this.cachedRecentMod.rev) { + query = {recentMod: {}}; + } else + return; } } catch(e) { this.error(`Ошибка соединения с сервером: ${e.message}`); @@ -389,44 +391,45 @@ class ServerStorage extends Vue { let recent = null; try { - recent = await this.storageGet({recent: {}, recentDelta: {}}); + recent = await this.storageGet(query); } catch(e) { this.error(`Ошибка соединения с сервером: ${e.message}`); return; } if (recent.state == 'success') { - let recentDelta = recent.items.recentDelta; - recent = recent.items.recent; + let newRecent = recent.items.recent; + let newRecentPatch = recent.items.recentPatch; + let newRecentMod = recent.items.recentMod; - if (recent.rev == 0) - recent.data = {}; + if (!newRecent) + newRecent = _.cloneDeep(this.cachedRecent); + if (!newRecentPatch) + newRecentPatch = _.cloneDeep(this.cachedRecentPatch); + if (!newRecentMod) + newRecentMod = _.cloneDeep(this.cachedRecentMod); - let newRecent = {}; - if (recentDelta && recentDelta.data) { - if (recentDelta.data.diff) { - newRecent = recent.data; - const key = recentDelta.data.diff.key; - if (newRecent[key]) - newRecent[key] = utils.applyObjDiff(newRecent[key], recentDelta.data.diff); - } else { - newRecent = Object.assign(recent.data, recentDelta.data); - } - this.recentDelta = recentDelta.data; - } else { - newRecent = recent.data; - this.recentDelta = {}; - } + if (newRecent.rev == 0) newRecent.data = {}; + if (newRecentPatch.rev == 0) newRecentPatch.data = {}; + if (newRecentMod.rev == 0) newRecentMod.data = {}; - this.recentDeltaInited = true; + let result = Object.assign({}, newRecent.data, newRecentPatch.data); + if (newRecentMod.key && result[newRecentMod.key]) + result[newRecentMod.key] = utils.applyObjDiff(result[newRecentMod.key], newRecentMod.mod); + + if (newRecent.rev != this.cachedRecent.rev) + await this.setCachedRecent(newRecent); + if (newRecentPatch.rev != this.cachedRecentPatch.rev) + await this.setCachedRecentPatch(newRecentPatch); + if (newRecentMod.rev != this.cachedRecentMod.rev) + await this.setCachedRecentMod(newRecentMod); if (!bookManager.loaded) { this.warning('Ожидание загрузки списка книг перед синхронизацией'); while (!bookManager.loaded) await utils.sleep(100); } - await bookManager.setRecent(newRecent); - await bookManager.setRecentRev(recent.rev); - await bookManager.setRecentDeltaRev(recentDelta.rev); + + await bookManager.setRecent(result); } else { this.warning(`Неверный ответ сервера: ${recent.state}`); } @@ -444,91 +447,59 @@ class ServerStorage extends Vue { const bm = bookManager; - //вычисление критерия сохранения целиком - if (!this.sameKeyCount) - this.sameKeyCount = 0; - if (this.prevItemKey == itemKey) { - this.sameKeyCount++; + let needSaveRecent = false; + let needSaveRecentPatch = false; + let needSaveRecentMod = true; + + let newRecentMod = _.cloneDeep(this.cachedRecentPatch); + newRecentMod.rev++; + + let newRecentPatch = _.cloneDeep(this.cachedRecentPatch); + newRecentPatch.data[itemKey] = bm.recent[itemKey]; + newRecentPatch.rev++; + needSaveRecentPatch = true; + + let newRecent = {rev: this.cachedRecent.rev + 1, data: bm.recent}; + + let query = {}; + if (needSaveRecent) { + query = {recent: newRecent, recentPatch: newRecentPatch, recentMod: newRecentMod}; + } else if (needSaveRecentPatch) { + query = {recentPatch: newRecentPatch, recentMod: newRecentMod}; } else { - this.sameKeyCount = 0; - } - - const l = Object.keys(this.recentDelta).length - (1*(!!this.recentDelta.diff)); - this.makeDeltaDiff = (l == 1 && this.prevItemKey == itemKey ? this.makeDeltaDiff : false); - const forceSaveRecent = l > 20 || (this.sameKeyCount > 5 && (l > 1)) || (l == 1 && this.sameKeyCount > 10 && !this.makeDeltaDiff); - - this.sameKeyCount = (!forceSaveRecent ? this.sameKeyCount : 0); - this.prevItemKey = itemKey; - - //дифф от дельты для уменьшения размера передаваемых данных в частном случае - if (this.makeDeltaDiff) { - this.recentDelta.diff = utils.getObjDiff(this.prevSavedItem, bm.recent[itemKey]); - this.recentDelta.diff.key = itemKey; - delete this.recentDelta[itemKey]; - } else if (this.recentDelta.diff) { - const key = this.recentDelta.diff.key; - if (!this.prevSavedItem && bm.recent[key]) - this.prevSavedItem = _.cloneDeep(bm.recent[key]); - if (this.prevSavedItem) { - this.recentDelta[key] = utils.applyObjDiff(this.prevSavedItem, this.recentDelta.diff); - } - delete this.recentDelta.diff; + query = {recentMod: newRecentMod}; } //сохранение this.savingRecent = true; try { - if (forceSaveRecent) {//сохраняем recent целиком - let result = {state: ''}; + let result = {state: ''}; - try { - result = await this.storageSet({recent: {rev: bm.recentRev + 1, data: bm.recent}, recentDelta: {rev: bm.recentDeltaRev + 1, data: {}}}); - } catch(e) { - this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`); + try { + result = await this.storageSet(query); + } catch(e) { + this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`); + } + + if (result.state == 'reject') { + + await this.loadRecent(true, false); + + this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`); + if (!recurse) { + this.savingRecent = false; + this.saveRecent(itemKey, true); + return; } + } else if (result.state == 'success') { + //this.prevSavedItem = _.cloneDeep(bm.recent[itemKey]); - if (result.state == 'reject') { - - await this.loadRecent(true, false); - - this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`); - if (!recurse) { - this.savingRecent = false; - this.recentDelta[itemKey] = _.cloneDeep(bm.recent[itemKey]); - this.saveRecent(itemKey, true); - return; - } - } else if (result.state == 'success') { - this.makeDeltaDiff = true; - this.prevSavedItem = _.cloneDeep(bm.recent[itemKey]); - - this.recentDelta = {}; - await bm.setRecentRev(bm.recentRev + 1); - await bm.setRecentDeltaRev(bm.recentDeltaRev + 1); - } - } else {//сохраняем только дифф - let result = {state: ''}; - - try { - result = await this.storageSet({recentDelta: {rev: bm.recentDeltaRev + 1, data: this.recentDelta}}); - } catch(e) { - this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`); - } - - if (result.state == 'reject') { - - await this.loadRecent(true, false); - - this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`); - if (!recurse) { - this.savingRecent = false; - this.recentDelta[itemKey] = _.cloneDeep(bm.recent[itemKey]); - this.saveRecent(itemKey, true); - return; - } - } else if (result.state == 'success') { - await bm.setRecentDeltaRev(bm.recentDeltaRev + 1); - } + if (needSaveRecent) + await this.setCachedRecent(newRecent); + if (needSaveRecentPatch) + await this.setCachedRecentPatch(newRecentPatch); + if (needSaveRecentMod) + await this.setCachedRecentMod(newRecentMod); } } finally { this.savingRecent = false; diff --git a/client/components/Reader/share/bookManager.js b/client/components/Reader/share/bookManager.js index e58a2e0b..b8405574 100644 --- a/client/components/Reader/share/bookManager.js +++ b/client/components/Reader/share/bookManager.js @@ -36,9 +36,6 @@ class BookManager { } } - this.recentRev = await bmRecentStore.getItem('recent-rev') || 0; - this.recentDeltaRev = await bmRecentStore.getItem('recent-delta-rev') || 0; - this.recentChanged = true; this.loadStored();//no await @@ -466,16 +463,6 @@ class BookManager { this.emit('recent-changed'); } - async setRecentRev(value) { - await bmRecentStore.setItem('recent-rev', value); - this.recentRev = value; - } - - async setRecentDeltaRev(value) { - await bmRecentStore.setItem('recent-delta-rev', value); - this.recentDeltaRev = value; - } - addEventListener(listener) { if (this.eventListeners.indexOf(listener) < 0) this.eventListeners.push(listener);