Переглянути джерело

Merge branch 'feature/ss_fix2' into develop

Book Pauk 5 роки тому
батько
коміт
259f9baa59

+ 150 - 140
client/components/Reader/ServerStorage/ServerStorage.vue

@@ -13,6 +13,11 @@ import readerApi from '../../../api/reader';
 import * as utils from '../../../share/utils';
 import * as utils from '../../../share/utils';
 import * as cryptoUtils from '../../../share/cryptoUtils';
 import * as cryptoUtils from '../../../share/cryptoUtils';
 
 
+import localForage from 'localforage';
+const ssCacheStore = localForage.createInstance({
+    name: 'ssCacheStore'
+});
+
 export default @Component({
 export default @Component({
     watch: {
     watch: {
         serverSyncEnabled: function() {
         serverSyncEnabled: function() {
@@ -58,35 +63,52 @@ class ServerStorage extends Vue {
 
 
     async init() {
     async init() {
         try {
         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) {
             if (!this.serverStorageKey) {
                 //генерируем новый ключ
                 //генерируем новый ключ
                 await this.generateNewServerStorageKey();
                 await this.generateNewServerStorageKey();
             } else {
             } else {
                 await this.serverStorageKeyChanged();
                 await this.serverStorageKeyChanged();
             }
             }
+
             bookManager.addEventListener(this.bookManagerEvent);
             bookManager.addEventListener(this.bookManagerEvent);
         } finally {
         } finally {
             this.inited = true;
             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) {
     async bookManagerEvent(eventName, itemKey) {
         if (!this.serverSyncEnabled)
         if (!this.serverSyncEnabled)
             return;
             return;
 
 
         if (eventName == 'recent-changed') {            
         if (eventName == 'recent-changed') {            
             if (itemKey) {
             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);
                 this.debouncedSaveRecent(itemKey);
             }
             }
         }
         }
@@ -119,8 +141,8 @@ class ServerStorage extends Vue {
             await this.loadProfiles(force);
             await this.loadProfiles(force);
             this.checkCurrentProfile();
             this.checkCurrentProfile();
             await this.currentProfileChanged(force);
             await this.currentProfileChanged(force);
-            await this.loadRecent();
-            if (force)
+            const loadSuccess = await this.loadRecent();
+            if (loadSuccess && force)
                 await this.saveRecent();
                 await this.saveRecent();
         }
         }
     }
     }
@@ -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) {
     async loadRecent(skipRevCheck = false, doNotifySuccess = true) {
         if (!this.keyInited || !this.serverSyncEnabled || this.loadingRecent)
         if (!this.keyInited || !this.serverSyncEnabled || this.loadingRecent)
             return;
             return;
-
         this.loadingRecent = true;
         this.loadingRecent = true;
         try {
         try {
-            const oldRecentRev = bookManager.recentRev;
-            const oldRecentDeltaRev = bookManager.recentDeltaRev;
             //проверим ревизию на сервере
             //проверим ревизию на сервере
+            let query = {recent: {}, recentPatch: {}, recentMod: {}};
             let revs = null;
             let revs = null;
             if (!skipRevCheck) {
             if (!skipRevCheck) {
                 try {
                 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 true;
                     }
                     }
                 } catch(e) {
                 } catch(e) {
                     this.error(`Ошибка соединения с сервером: ${e.message}`);
                     this.error(`Ошибка соединения с сервером: ${e.message}`);
@@ -389,46 +391,53 @@ class ServerStorage extends Vue {
 
 
             let recent = null;
             let recent = null;
             try {
             try {
-                recent = await this.storageGet({recent: {}, recentDelta: {}});
+                recent = await this.storageGet(query);
             } catch(e) {
             } catch(e) {
                 this.error(`Ошибка соединения с сервером: ${e.message}`);
                 this.error(`Ошибка соединения с сервером: ${e.message}`);
                 return;
                 return;
             }
             }
 
 
             if (recent.state == 'success') {
             if (recent.state == 'success') {
-                let recentDelta = recent.items.recentDelta;
-                recent = recent.items.recent;
-
-                if (recent.rev == 0)
-                    recent.data = {};
-
-                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 = {};
+                let newRecent = recent.items.recent;
+                let newRecentPatch = recent.items.recentPatch;
+                let newRecentMod = recent.items.recentMod;
+
+                if (!newRecent) {
+                    newRecent = _.cloneDeep(this.cachedRecent);
+                }
+                if (!newRecentPatch) {
+                    newRecentPatch = _.cloneDeep(this.cachedRecentPatch);
+                }
+                if (!newRecentMod) {
+                    newRecentMod = _.cloneDeep(this.cachedRecentMod);
                 }
                 }
 
 
-                this.recentDeltaInited = true;
+                if (newRecent.rev == 0) newRecent.data = {};
+                if (newRecentPatch.rev == 0) newRecentPatch.data = {};
+                if (newRecentMod.rev == 0) newRecentMod.data = {};
+
+                let result = Object.assign({}, newRecent.data, newRecentPatch.data);
+
+                const md = newRecentMod.data;
+                if (md.key && result[md.key])
+                    result[md.key] = utils.applyObjDiff(result[md.key], md.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) {
                 if (!bookManager.loaded) {
                     this.warning('Ожидание загрузки списка книг перед синхронизацией');
                     this.warning('Ожидание загрузки списка книг перед синхронизацией');
                     while (!bookManager.loaded) await utils.sleep(100);
                     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 {
             } else {
                 this.warning(`Неверный ответ сервера: ${recent.state}`);
                 this.warning(`Неверный ответ сервера: ${recent.state}`);
+                return;
             }
             }
 
 
             if (doNotifySuccess)
             if (doNotifySuccess)
@@ -436,6 +445,7 @@ class ServerStorage extends Vue {
         } finally {
         } finally {
             this.loadingRecent = false;
             this.loadingRecent = false;
         }
         }
+        return true;
     }
     }
 
 
     async saveRecent(itemKey, recurse) {
     async saveRecent(itemKey, recurse) {
@@ -444,91 +454,91 @@ class ServerStorage extends Vue {
 
 
         const bm = bookManager;
         const bm = bookManager;
 
 
-        //вычисление критерия сохранения целиком
-        if (!this.sameKeyCount)
-            this.sameKeyCount = 0;
-        if (this.prevItemKey == itemKey) {
-            this.sameKeyCount++;
-        } else {
-            this.sameKeyCount = 0;
-        }
+        let needSaveRecent = false;
+        let needSaveRecentPatch = false;
+        let needSaveRecentMod = false;
 
 
-        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);
+        let applyMod = null;
 
 
-        this.sameKeyCount = (!forceSaveRecent ? this.sameKeyCount : 0);
-        this.prevItemKey = itemKey;
+        //newRecentMod
+        let newRecentMod = {};
+
+        if (itemKey && this.cachedRecentPatch.data[itemKey]) {            
+            if (this.prevItemKey == itemKey) {//сохраняем только дифф
+                newRecentMod = _.cloneDeep(this.cachedRecentMod);
+                newRecentMod.rev++;
 
 
-        //дифф от дельты для уменьшения размера передаваемых данных в частном случае
-        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);
+                newRecentMod.data.key = itemKey;
+                newRecentMod.data.mod = utils.getObjDiff(this.cachedRecentPatch.data[itemKey], bm.recent[itemKey]);
+                needSaveRecentMod = true;
+            } else {//ключ не совпадает, надо сохранять патч
+                applyMod = newRecentMod.data;
             }
             }
-            delete this.recentDelta.diff;
         }
         }
+        this.prevItemKey = itemKey;
 
 
-        //сохранение
-        this.savingRecent = true;        
-        try {
-            if (forceSaveRecent) {//сохраняем recent целиком
-                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}). Данные не сохранены и могут быть перезаписаны.`);
-                }
-
-                if (result.state == 'reject') {
+        //newRecentPatch
+        let newRecentPatch = {};
+        if (itemKey && !needSaveRecentMod) {
+            newRecentPatch = _.cloneDeep(this.cachedRecentPatch);
+            newRecentPatch.rev++;
+            newRecentPatch.data[itemKey] = bm.recent[itemKey];
+            if (applyMod && applyMod.key && newRecentPatch.data[applyMod.key])
+                newRecentPatch.data[applyMod.key] = utils.applyObjDiff(newRecentPatch.data[applyMod.key], applyMod.mod);
+            newRecentMod = {rev: this.cachedRecentMod.rev + 1, data: {}};
+            needSaveRecentPatch = true;
+            needSaveRecentMod = true;
+        }
 
 
-                    await this.loadRecent(true, false);
+        //newRecent
+        let newRecent = {};
+        if (!itemKey || (needSaveRecentPatch && Object.keys(newRecentPatch.data).length > 2)) {
+            newRecent = {rev: this.cachedRecent.rev + 1, data: bm.recent};
+            newRecentPatch = {rev: this.cachedRecentPatch.rev + 1, data: {}};
+            newRecentMod = {rev: this.cachedRecentMod.rev + 1, data: {}};
+            needSaveRecent = true;
+            needSaveRecentPatch = true;
+            needSaveRecentMod = true;
+        }
 
 
-                    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]);
+        //query
+        let query = {};
+        if (needSaveRecent) {
+            query = {recent: newRecent, recentPatch: newRecentPatch, recentMod: newRecentMod};
+        } else if (needSaveRecentPatch) {
+            query = {recentPatch: newRecentPatch, recentMod: newRecentMod};
+        } else {
+            query = {recentMod: newRecentMod};
+        }
 
 
-                    this.recentDelta = {};
-                    await bm.setRecentRev(bm.recentRev + 1);
-                    await bm.setRecentDeltaRev(bm.recentDeltaRev + 1);
-                }
-            } else {//сохраняем только дифф
-                let result = {state: ''};
+        //сохранение
+        this.savingRecent = true;        
+        try {
+            let result = {state: ''};
 
 
-                try {
-                    result = await this.storageSet({recentDelta: {rev: bm.recentDeltaRev + 1, data: this.recentDelta}});
-                } catch(e) {
-                    this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
-                }
+            try {
+                result = await this.storageSet(query);
+            } catch(e) {
+                this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
+            }
 
 
-                if (result.state == 'reject') {
+            if (result.state == 'reject') {
 
 
-                    await this.loadRecent(true, false);
+                await this.loadRecent(false, 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);
+                this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`);
+                if (!recurse && itemKey) {
+                    this.savingRecent = false;
+                    this.saveRecent(itemKey, true);
+                    return;
                 }
                 }
+            } else if (result.state == 'success') {
+                if (needSaveRecent && newRecent.rev)
+                    await this.setCachedRecent(newRecent);
+                if (needSaveRecentPatch && newRecentPatch.rev)
+                    await this.setCachedRecentPatch(newRecentPatch);
+                if (needSaveRecentMod && newRecentMod.rev)
+                    await this.setCachedRecentMod(newRecentMod);
             }
             }
         } finally {
         } finally {
             this.savingRecent = false;
             this.savingRecent = false;

+ 1 - 14
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.recentChanged = true;
 
 
         this.loadStored();//no await
         this.loadStored();//no await
@@ -440,7 +437,7 @@ class BookManager {
 
 
         Object.assign(mergedRecent, value);
         Object.assign(mergedRecent, value);
 
 
-        //подстраховка
+        //подстраховка от hotReload
         for (let i of Object.keys(mergedRecent)) {
         for (let i of Object.keys(mergedRecent)) {
             if (!mergedRecent[i].key || mergedRecent[i].key !== i)
             if (!mergedRecent[i].key || mergedRecent[i].key !== i)
                 delete mergedRecent[i];
                 delete mergedRecent[i];
@@ -466,16 +463,6 @@ class BookManager {
         this.emit('recent-changed');
         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) {
     addEventListener(listener) {
         if (this.eventListeners.indexOf(listener) < 0)
         if (this.eventListeners.indexOf(listener) < 0)
             this.eventListeners.push(listener);        
             this.eventListeners.push(listener);        

+ 1 - 1
server/dev.js

@@ -20,7 +20,7 @@ function webpackDevMiddleware(app) {
 function logQueries(app) {
 function logQueries(app) {
     app.use(function(req, res, next) {
     app.use(function(req, res, next) {
         const start = Date.now();
         const start = Date.now();
-        log(`${req.method} ${req.originalUrl} ${JSON.stringify(req.body).substr(0, 2000)}`);
+        log(`${req.method} ${req.originalUrl} ${JSON.stringify(req.body).substr(0, 4000)}`);
         //log(`${JSON.stringify(req.headers, null, 2)}`)
         //log(`${JSON.stringify(req.headers, null, 2)}`)
         res.once('finish', () => {
         res.once('finish', () => {
             log(`${Date.now() - start}ms`);
             log(`${Date.now() - start}ms`);