Procházet zdrojové kódy

Начало переделки ServerStorage

Book Pauk před 5 roky
rodič
revize
96945dfc4a

+ 4 - 29
client/components/Reader/Reader.vue

@@ -73,7 +73,7 @@
             <SettingsPage v-if="settingsActive" ref="settingsPage" @settings-toggle="settingsToggle"></SettingsPage>
             <SettingsPage v-if="settingsActive" ref="settingsPage" @settings-toggle="settingsToggle"></SettingsPage>
             <HelpPage v-if="helpActive" ref="helpPage" @help-toggle="helpToggle"></HelpPage>
             <HelpPage v-if="helpActive" ref="helpPage" @help-toggle="helpToggle"></HelpPage>
             <ClickMapPage v-show="clickMapActive" ref="clickMapPage"></ClickMapPage>
             <ClickMapPage v-show="clickMapActive" ref="clickMapPage"></ClickMapPage>
-            <!--ServerStorage v-show="hidden" ref="serverStorage"></ServerStorage-->
+            <ServerStorage v-show="hidden" ref="serverStorage"></ServerStorage>
 
 
             <el-dialog
             <el-dialog
                 title="Что нового:"
                 title="Что нового:"
@@ -191,7 +191,7 @@ import RecentBooksPage from './RecentBooksPage/RecentBooksPage.vue';
 import SettingsPage from './SettingsPage/SettingsPage.vue';
 import SettingsPage from './SettingsPage/SettingsPage.vue';
 import HelpPage from './HelpPage/HelpPage.vue';
 import HelpPage from './HelpPage/HelpPage.vue';
 import ClickMapPage from './ClickMapPage/ClickMapPage.vue';
 import ClickMapPage from './ClickMapPage/ClickMapPage.vue';
-//import ServerStorage from './ServerStorage/ServerStorage.vue';
+import ServerStorage from './ServerStorage/ServerStorage.vue';
 
 
 import bookManager from './share/bookManager';
 import bookManager from './share/bookManager';
 import readerApi from '../../api/reader';
 import readerApi from '../../api/reader';
@@ -211,7 +211,7 @@ export default @Component({
         SettingsPage,
         SettingsPage,
         HelpPage,
         HelpPage,
         ClickMapPage,
         ClickMapPage,
-        //ServerStorage,
+        ServerStorage,
     },
     },
     watch: {
     watch: {
         bookPos: function(newValue) {
         bookPos: function(newValue) {
@@ -301,18 +301,6 @@ class Reader extends Vue {
             }
             }
         }, 500);
         }, 500);
 
 
-        /*this.debouncedSaveRecent = _.debounce(async() => {
-            const serverStorage = this.$refs.serverStorage;
-            while (!serverStorage.inited) await utils.sleep(1000);
-            await serverStorage.saveRecent();
-        }, 1000);
-
-        this.debouncedSaveRecentLast = _.debounce(async() => {
-            const serverStorage = this.$refs.serverStorage;
-            while (!serverStorage.inited) await utils.sleep(1000);
-            await serverStorage.saveRecentLast();
-        }, 1000);*/
-
         document.addEventListener('fullscreenchange', () => {
         document.addEventListener('fullscreenchange', () => {
             this.fullScreenActive = (document.fullscreenElement !== null);
             this.fullScreenActive = (document.fullscreenElement !== null);
         });
         });
@@ -347,6 +335,7 @@ class Reader extends Vue {
             this.checkActivateDonateHelpPage();
             this.checkActivateDonateHelpPage();
             this.loading = false;
             this.loading = false;
 
 
+            await this.$refs.serverStorage.init();
             await this.showWhatsNew();
             await this.showWhatsNew();
             await this.showMigration();
             await this.showMigration();
         })();
         })();
@@ -516,14 +505,6 @@ class Reader extends Vue {
     }
     }
 
 
     async bookManagerEvent(eventName) {
     async bookManagerEvent(eventName) {
-        /*const serverStorage = this.$refs.serverStorage;
-        if (eventName == '') {
-            serverStorage.init();
-            const result = await bookManager.cleanRecentBooks();
-            if (result)
-                this.debouncedSaveRecent();
-        }*/
-
         if (eventName == 'recent-changed') {
         if (eventName == 'recent-changed') {
             if (this.recentBooksActive) {
             if (this.recentBooksActive) {
                 await this.$refs.recentBooksPage.updateTableData();
                 await this.$refs.recentBooksPage.updateTableData();
@@ -545,12 +526,6 @@ class Reader extends Vue {
                     this.bookPosChanged({bookPos: newBook.bookPos});
                     this.bookPosChanged({bookPos: newBook.bookPos});
                 }
                 }
             }
             }
-
-            /*if (eventName == 'recent-changed') {
-                this.debouncedSaveRecentLast();
-            } else {
-                this.debouncedSaveRecent();
-            }*/
         }
         }
     }
     }
 
 

+ 97 - 244
client/components/Reader/ServerStorage/ServerStorage.vue

@@ -13,8 +13,6 @@ 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';
 
 
-const maxSetTries = 5;
-
 export default @Component({
 export default @Component({
     watch: {
     watch: {
         serverSyncEnabled: function() {
         serverSyncEnabled: function() {
@@ -46,11 +44,18 @@ class ServerStorage extends Vue {
             this.saveSettings();
             this.saveSettings();
         }, 500);
         }, 500);
 
 
+        this.debouncedSaveRecent = _.debounce(() => {
+            this.saveRecent();
+        }, 1000);
+
+        this.debouncedNotifySuccess = _.debounce(() => {
+            this.success('Данные синхронизированы с сервером');
+        }, 1000);
+
         this.oldProfiles = {};
         this.oldProfiles = {};
         this.oldSettings = {};
         this.oldSettings = {};
         this.oldRecent = {};
         this.oldRecent = {};
-        this.oldRecentLast = {};
-        this.oldRecentLastDiff = {};
+        this.oldRecentDiff = {};
     }
     }
 
 
     async init() {
     async init() {
@@ -61,13 +66,27 @@ class ServerStorage extends Vue {
             } else {
             } else {
                 await this.serverStorageKeyChanged();
                 await this.serverStorageKeyChanged();
             }
             }
-            this.oldRecent = _.cloneDeep(bookManager.recent);
-            this.oldRecentLast = _.cloneDeep(bookManager.recentLast) || {};
+            bookManager.addEventListener(this.bookManagerEvent);
         } finally {
         } finally {
             this.inited = true;
             this.inited = true;
         }
         }
     }
     }
 
 
+    async bookManagerEvent(eventName) {
+        if (eventName == 'load-stored-finish') {
+            this.oldRecent = _.cloneDeep(bookManager.recent);
+            this.oldRecentLast = _.cloneDeep(bookManager.recentLast) || {};
+        }
+
+        if (eventName == 'recent-changed') {
+            let i = 0;
+            while (!bookManager.loaded && i++ < 1000) await utils.sleep(100);
+            i = 0;
+            while (!this.inited && i++ < 1000) await utils.sleep(100);
+            this.debouncedSaveRecent();
+        }
+    }
+
     async generateNewServerStorageKey() {
     async generateNewServerStorageKey() {
         const key = utils.toBase58(utils.randomArray(32));
         const key = utils.toBase58(utils.randomArray(32));
         this.commit('reader/setServerStorageKey', key);
         this.commit('reader/setServerStorageKey', key);
@@ -146,10 +165,6 @@ class ServerStorage extends Vue {
         }
         }
     }
     }
 
 
-    notifySuccess() {
-        this.success('Данные синхронизированы с сервером');
-    }
-
     success(message) {
     success(message) {
         if (this.showServerStorageMessages)
         if (this.showServerStorageMessages)
             this.$notify.success({message});
             this.$notify.success({message});
@@ -165,7 +180,7 @@ class ServerStorage extends Vue {
             this.$notify.error({message});
             this.$notify.error({message});
     }
     }
 
 
-    async loadSettings(force) {
+    async loadSettings(force = false, doNotifySuccess = true) {
         if (!this.keyInited || !this.serverSyncEnabled || !this.currentProfile)
         if (!this.keyInited || !this.serverSyncEnabled || !this.currentProfile)
             return;
             return;
 
 
@@ -202,7 +217,8 @@ class ServerStorage extends Vue {
             this.commit('reader/setSettings', sets.data);
             this.commit('reader/setSettings', sets.data);
             this.commit('reader/setSettingsRev', {[setsId]: sets.rev});
             this.commit('reader/setSettingsRev', {[setsId]: sets.rev});
 
 
-            this.notifySuccess();
+            if (doNotifySuccess)
+                this.debouncedNotifySuccess();
         } else {
         } else {
             this.warning(`Неверный ответ сервера: ${sets.state}`);
             this.warning(`Неверный ответ сервера: ${sets.state}`);
         }
         }
@@ -220,32 +236,18 @@ class ServerStorage extends Vue {
         try {
         try {
             const setsId = `settings-${this.currentProfile}`;
             const setsId = `settings-${this.currentProfile}`;
             let result = {state: ''};
             let result = {state: ''};
-            let tries = 0;
-            while (result.state != 'success' && tries < maxSetTries) {
-                const oldRev = this.settingsRev[setsId] || 0;
-                try {
-                    result = await this.storageSet({[setsId]: {rev: oldRev + 1, data: this.settings}});
-                } catch(e) {
-                    this.savingSettings = false;
-                    this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
-                    return;
-                }
-
-                if (result.state == 'reject') {
-                    await this.loadSettings(true);
-                    const newSettings = utils.applyObjDiff(this.settings, diff);
-                    this.commit('reader/setSettings', newSettings);
-                }
 
 
-                tries++;
+            const oldRev = this.settingsRev[setsId] || 0;
+            try {
+                result = await this.storageSet({[setsId]: {rev: oldRev + 1, data: this.settings}});
+            } catch(e) {
+                this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
             }
             }
 
 
-            if (tries >= maxSetTries) {
-                //отменять изменения не будем, просто предупредим
-                //this.commit('reader/setSettings', this.oldSettings);
-                console.error(result);
-                this.error('Не удалось отправить настройки на сервер. Данные не сохранены и могут быть перезаписаны.');
-            } else {
+            if (result.state == 'reject') {
+                await this.loadSettings(true, false);
+                this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`);
+            } else if (result.state == 'success') {
                 this.oldSettings = _.cloneDeep(this.settings);
                 this.oldSettings = _.cloneDeep(this.settings);
                 this.commit('reader/setSettingsRev', {[setsId]: this.settingsRev[setsId] + 1});
                 this.commit('reader/setSettingsRev', {[setsId]: this.settingsRev[setsId] + 1});
             }
             }
@@ -254,7 +256,7 @@ class ServerStorage extends Vue {
         }
         }
     }
     }
 
 
-    async loadProfiles(force) {
+    async loadProfiles(force = false, doNotifySuccess = true) {
         if (!this.keyInited || !this.serverSyncEnabled)
         if (!this.keyInited || !this.serverSyncEnabled)
             return;
             return;
 
 
@@ -289,8 +291,10 @@ class ServerStorage extends Vue {
             this.oldProfiles = _.cloneDeep(prof.data);
             this.oldProfiles = _.cloneDeep(prof.data);
             this.commit('reader/setProfiles', prof.data);
             this.commit('reader/setProfiles', prof.data);
             this.commit('reader/setProfilesRev', prof.rev);
             this.commit('reader/setProfilesRev', prof.rev);
+            this.checkCurrentProfile();
 
 
-            this.notifySuccess();
+            if (doNotifySuccess)
+                this.debouncedNotifySuccess();
         } else {
         } else {
             this.warning(`Неверный ответ сервера: ${prof.state}`);
             this.warning(`Неверный ответ сервера: ${prof.state}`);
         }
         }
@@ -304,7 +308,7 @@ class ServerStorage extends Vue {
         if (utils.isEmptyObjDiff(diff))
         if (utils.isEmptyObjDiff(diff))
             return;
             return;
 
 
-        //обнуляются профили во время разработки, подстраховка
+        //обнуляются профили во время разработки при hotReload, подстраховка
         if (!this.$store.state.reader.allowProfilesSave) {
         if (!this.$store.state.reader.allowProfilesSave) {
             console.error('Сохранение профилей не санкционировано');
             console.error('Сохранение профилей не санкционировано');
             return;
             return;
@@ -313,33 +317,16 @@ class ServerStorage extends Vue {
         this.savingProfiles = true;
         this.savingProfiles = true;
         try {
         try {
             let result = {state: ''};
             let result = {state: ''};
-            let tries = 0;
-            while (result.state != 'success' && tries < maxSetTries) {
-                try {
-                    result = await this.storageSet({profiles: {rev: this.profilesRev + 1, data: this.profiles}});
-                } catch(e) {
-                    this.savingProfiles = false;
-                    this.commit('reader/setProfiles', this.oldProfiles);
-                    this.checkCurrentProfile();
-                    this.error(`Ошибка соединения с сервером: (${e.message}). Изменения отменены.`);
-                    return;
-                }
-
-                if (result.state == 'reject') {
-                    await this.loadProfiles(true);
-                    const newProfiles = utils.applyObjDiff(this.profiles, diff);
-                    this.commit('reader/setProfiles', newProfiles);
-                }
-
-                tries++;
+            try {
+                result = await this.storageSet({profiles: {rev: this.profilesRev + 1, data: this.profiles}});
+            } catch(e) {
+                this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
             }
             }
 
 
-            if (tries >= maxSetTries) {
-                this.commit('reader/setProfiles', this.oldProfiles);
-                this.checkCurrentProfile();
-                console.error(result);
-                this.error('Не удалось отправить данные на сервер. Изменения отменены.');
-            } else {
+            if (result.state == 'reject') {
+                await this.loadProfiles(true, false);
+                this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`);
+            } else if (result.state == 'success') {
                 this.oldProfiles = _.cloneDeep(this.profiles);
                 this.oldProfiles = _.cloneDeep(this.profiles);
                 this.commit('reader/setProfilesRev', this.profilesRev + 1);        
                 this.commit('reader/setProfilesRev', this.profilesRev + 1);        
             }
             }
@@ -348,21 +335,19 @@ class ServerStorage extends Vue {
         }
         }
     }
     }
 
 
-    async loadRecent(force) {
+    async loadRecent(force = false, doNotifySuccess = true) {
         if (!this.keyInited || !this.serverSyncEnabled)
         if (!this.keyInited || !this.serverSyncEnabled)
             return;
             return;
 
 
-        const oldRev = bookManager.recentRev;
-        const oldLastRev = bookManager.recentLastRev;
-        const oldLastDiffRev = bookManager.recentLastDiffRev;
+        const oldRecentRev = bookManager.recentRev;
+        const oldRecentDiffRev = bookManager.recentDiffRev;
         //проверим ревизию на сервере
         //проверим ревизию на сервере
         let revs = null;
         let revs = null;
         if (!force) {
         if (!force) {
             try {
             try {
-                revs = await this.storageCheck({recent: {}, recentLast: {}, recentLastDiff: {}});
-                if (revs.state == 'success' && revs.items.recent.rev == oldRev &&
-                    revs.items.recentLast.rev == oldLastRev &&
-                    revs.items.recentLastDiff.rev == oldLastDiffRev) {
+                revs = await this.storageCheck({recent: {}, recentDiff: {}});
+                if (revs.state == 'success' && revs.items.recent.rev == oldRecentRev &&
+                    revs.items.recentDiff.rev == oldRecentDiffRev) {
                     return;
                     return;
                 }
                 }
             } catch(e) {
             } catch(e) {
@@ -371,61 +356,63 @@ class ServerStorage extends Vue {
             }
             }
         }
         }
 
 
-        if (force || revs.items.recent.rev != oldRev) {
-            let recent = null;
+console.log('load');
+        let recentDiff = null;
+        if (force || revs.items.recentDiff.rev != oldRecentDiffRev) {
             try {
             try {
-                recent = await this.storageGet({recent: {}});
+                recentDiff = await this.storageGet({recentDiff: {}});
             } catch(e) {
             } catch(e) {
                 this.error(`Ошибка соединения с сервером: ${e.message}`);
                 this.error(`Ошибка соединения с сервером: ${e.message}`);
                 return;
                 return;
             }
             }
 
 
-            if (recent.state == 'success') {
-                recent = recent.items.recent;
+            if (recentDiff.state == 'success') {
+                recentDiff = recentDiff.items.recentDiff;
 
 
-                if (recent.rev == 0)
-                    recent.data = {};
+                if (recentDiff.rev == 0)
+                    recentDiff.data = {};
 
 
-                this.oldRecent = _.cloneDeep(recent.data);
-                await bookManager.setRecent(recent.data);
-                await bookManager.setRecentRev(recent.rev);
+                this.oldRecentDiff = _.cloneDeep(recentDiff.data);
+
+                await bookManager.setRecentDiffRev(recentDiff.rev);
             } else {
             } else {
-                this.warning(`Неверный ответ сервера: ${recent.state}`);
+                this.warning(`Неверный ответ сервера: ${recentDiff.state}`);
+                recentDiff = null;
             }
             }
         }
         }
 
 
-        if (force || revs.items.recentLast.rev != oldLastRev || revs.items.recentLastDiff.rev != oldLastDiffRev) {
-            let recentLast = null;
+        if (force || revs.items.recent.rev != oldRecentRev) {
+            let recent = null;
             try {
             try {
-                recentLast = await this.storageGet({recentLast: {}, recentLastDiff: {}});
+                recent = await this.storageGet({recent: {}});
             } catch(e) {
             } catch(e) {
                 this.error(`Ошибка соединения с сервером: ${e.message}`);
                 this.error(`Ошибка соединения с сервером: ${e.message}`);
                 return;
                 return;
             }
             }
 
 
-            if (recentLast.state == 'success') {
-                const recentLastDiff = recentLast.items.recentLastDiff;
-                recentLast = recentLast.items.recentLast;
-
-                if (recentLast.rev == 0)
-                    recentLast.data = {};
-                if (recentLastDiff.rev == 0)
-                    recentLastDiff.data = {};
+            if (recent.state == 'success') {
+                recent = recent.items.recent;
 
 
-                this.oldRecentLastDiff = _.cloneDeep(recentLastDiff.data);
-                this.oldRecentLast = _.cloneDeep(recentLast.data);
+                if (recent.rev == 0)
+                    recent.data = {};
 
 
-                recentLast.data = utils.applyObjDiff(recentLast.data, recentLastDiff.data);
+                let newRecent = {};
+                if (recentDiff && recentDiff.data) {
+                    newRecent = utils.applyObjDiff(recent.data, recentDiff.data);
+                } else {
+                    newRecent = recent.data;
+                }
 
 
-                await bookManager.setRecentLast(recentLast.data);
-                await bookManager.setRecentLastRev(recentLast.rev);
-                await bookManager.setRecentLastDiffRev(recentLastDiff.rev);
+                this.oldRecent = _.cloneDeep(newRecent);
+                await bookManager.setRecent(newRecent);
+                await bookManager.setRecentRev(recent.rev);
             } else {
             } else {
-                this.warning(`Неверный ответ сервера: ${recentLast.state}`);
+                this.warning(`Неверный ответ сервера: ${recent.state}`);
             }
             }
         }
         }
 
 
-        this.notifySuccess();
+        if (doNotifySuccess)
+            this.debouncedNotifySuccess();
     }
     }
 
 
     async saveRecent() {
     async saveRecent() {
@@ -437,163 +424,29 @@ class ServerStorage extends Vue {
         const diff = utils.getObjDiff(this.oldRecent, bm.recent);
         const diff = utils.getObjDiff(this.oldRecent, bm.recent);
         if (utils.isEmptyObjDiff(diff))
         if (utils.isEmptyObjDiff(diff))
             return;
             return;
-
+console.log('save');
         this.savingRecent = true;
         this.savingRecent = true;
         try {
         try {
             let result = {state: ''};
             let result = {state: ''};
-            let tries = 0;
-            while (result.state != 'success' && tries < maxSetTries) {
-                try {
-                    result = await this.storageSet({recent: {rev: bm.recentRev + 1, data: bm.recent}});
-                } catch(e) {
-                    this.savingRecent = false;
-                    this.error(`Ошибка соединения с сервером: (${e.message}). Изменения не сохранены.`);
-                    return;
-                }
 
 
-                if (result.state == 'reject') {
-                    await this.loadRecent(true);
-                    //похоже это лишнее
-                    /*const newRecent = utils.applyObjDiff(bm.recent, diff);
-                    await bm.setRecent(newRecent);*/
-                }
-
-                tries++;
+            try {
+                result = await this.storageSet({recent: {rev: bm.recentRev + 1, data: bm.recent}});
+            } catch(e) {
+                this.error(`Ошибка соединения с сервером (${e.message}). Данные не сохранены и могут быть перезаписаны.`);
             }
             }
 
 
-            if (tries >= maxSetTries) {
-                console.error(result);
-                this.error('Не удалось отправить данные на сервер. Данные не сохранены и могут быть перезаписаны.');
-            } else {
+            if (result.state == 'reject') {
+                await this.loadRecent(true, false);
+                this.warning(`Последние изменения отменены. Данные синхронизированы с сервером.`);
+            } else if (result.state == 'success') {
                 this.oldRecent = _.cloneDeep(bm.recent);
                 this.oldRecent = _.cloneDeep(bm.recent);
                 await bm.setRecentRev(bm.recentRev + 1);
                 await bm.setRecentRev(bm.recentRev + 1);
-                await this.saveRecentLast(true);
             }
             }
         } finally {
         } finally {
             this.savingRecent = false;
             this.savingRecent = false;
         }
         }
     }
     }
 
 
-    async saveRecentLast(force = false) {
-        if (!this.keyInited || !this.serverSyncEnabled || this.savingRecentLast)
-            return;
-
-        const bm = bookManager;
-        let recentLast = bm.recentLast;
-        recentLast = (recentLast ? recentLast : {});
-        let lastRev = bm.recentLastRev;
-
-        const diff = utils.getObjDiff(this.oldRecentLast, recentLast);
-        if (utils.isEmptyObjDiff(diff))
-            return;
-
-        if (this.oldRecentLast.key == recentLast.key && JSON.stringify(recentLast) > JSON.stringify(diff)) {
-            await this.saveRecentLastDiff(diff, force);
-            return;
-        }
-
-        this.savingRecentLast = true;
-        try {
-            let result = {state: ''};
-            let tries = 0;
-            while (result.state != 'success' && tries < maxSetTries) {
-                if (force) {
-                    try {
-                        const revs = await this.storageCheck({recentLast: {}});
-                        if (revs.items.recentLast.rev)
-                            lastRev = revs.items.recentLast.rev;
-                    } catch(e) {
-                        this.error(`Ошибка соединения с сервером: ${e.message}`);
-                        return;
-                    }
-                }
-
-                try {
-                    result = await this.storageSet({recentLast: {rev: lastRev + 1, data: recentLast}}, force);
-                } catch(e) {
-                    this.savingRecentLast = false;
-                    this.error(`Ошибка соединения с сервером: (${e.message}). Изменения не сохранены.`);
-                    return;
-                }
-
-                if (result.state == 'reject') {
-                    await this.loadRecent(false);
-                    this.savingRecentLast = false;//!!!
-                    return;//!!!
-                }
-
-                tries++;
-            }
-
-            if (tries >= maxSetTries) {
-                console.error(result);
-                this.error('Не удалось отправить данные на сервер. Данные не сохранены и могут быть перезаписаны.');
-            } else {
-                this.oldRecentLast = _.cloneDeep(recentLast);
-                await bm.setRecentLastRev(lastRev + 1);
-                await this.saveRecentLastDiff({}, true);
-            }
-        } finally {
-            this.savingRecentLast = false;
-        }
-    }
-
-    async saveRecentLastDiff(diff, force = false) {
-        if (!this.keyInited || !this.serverSyncEnabled || this.savingRecentLastDiff)
-            return;
-
-        const bm = bookManager;
-        let lastRev = bm.recentLastDiffRev;
-
-        const d = utils.getObjDiff(this.oldRecentLastDiff, diff);
-        if (utils.isEmptyObjDiff(d))
-            return;
-
-        this.savingRecentLastDiff = true;
-        try {
-            let result = {state: ''};
-            let tries = 0;
-            while (result.state != 'success' && tries < maxSetTries) {
-                if (force) {
-                    try {
-                        const revs = await this.storageCheck({recentLastDiff: {}});
-                        if (revs.items.recentLastDiff.rev)
-                            lastRev = revs.items.recentLastDiff.rev;
-                    } catch(e) {
-                        this.error(`Ошибка соединения с сервером: ${e.message}`);
-                        return;
-                    }
-                }
-
-                try {
-                    result = await this.storageSet({recentLastDiff: {rev: lastRev + 1, data: diff}}, force);
-                } catch(e) {
-                    this.savingRecentLastDiff = false;
-                    this.error(`Ошибка соединения с сервером: (${e.message}). Изменения не сохранены.`);
-                    return;
-                }
-
-                if (result.state == 'reject') {
-                    await this.loadRecent(false);
-                    this.savingRecentLastDiff = false;
-                    return;
-                }
-
-                tries++;
-            }
-
-            if (tries >= maxSetTries) {
-                console.error(result);
-                this.error('Не удалось отправить данные на сервер. Данные не сохранены и могут быть перезаписаны.');
-            } else {
-                this.oldRecentLastDiff = _.cloneDeep(diff);
-                await bm.setRecentLastDiffRev(lastRev + 1);
-            }
-        } finally {
-            this.savingRecentLastDiff = false;
-        }
-    }
-
     async storageCheck(items) {
     async storageCheck(items) {
         return await this.storageApi('check', items);
         return await this.storageApi('check', items);
     }
     }

+ 4 - 2
client/components/Reader/SettingsPage/SettingsPage.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-    <Window ref="window" height="70%" width="600px" @close="close">
+    <Window ref="window" height="95%" width="600px" @close="close">
         <template slot="header">
         <template slot="header">
             Настройки
             Настройки
         </template>
         </template>
@@ -537,7 +537,8 @@ export default @Component({
             this.settingsChanged();
             this.settingsChanged();
         },
         },
         form: function(newValue) {
         form: function(newValue) {
-            this.commit('reader/setSettings', newValue);
+            if (this.inited)
+                this.commit('reader/setSettings', newValue);
         },
         },
         fontBold: function(newValue) {
         fontBold: function(newValue) {
             this.fontWeight = (newValue ? 'bold' : '');
             this.fontWeight = (newValue ? 'bold' : '');
@@ -588,6 +589,7 @@ class SettingsPage extends Vue {
 
 
     init() {
     init() {
         this.$refs.window.init();
         this.$refs.window.init();
+        this.inited = true;
     }
     }
 
 
     settingsChanged() {
     settingsChanged() {

+ 39 - 1
client/components/Reader/share/bookManager.js

@@ -31,6 +31,9 @@ class BookManager {
         if (this.recentLast)
         if (this.recentLast)
             this.recent[this.recentLast.key] = this.recentLast;
             this.recent[this.recentLast.key] = this.recentLast;
 
 
+        this.recentRev = await bmRecentStore.getItem('recent-rev') || 0;
+        this.recentDiffRev = await bmRecentStore.getItem('recent-diff-rev') || 0;
+
         this.recentChanged = true;
         this.recentChanged = true;
 
 
         this.loadStored();//no await
         this.loadStored();//no await
@@ -419,6 +422,41 @@ class BookManager {
         return result;
         return result;
     }
     }
 
 
+    async setRecent(value) {
+        const mergedRecent = _.cloneDeep(this.recent);
+
+        Object.assign(mergedRecent, value);
+        
+        //"ленивое" обновление хранилища
+        (async() => {
+            for (const rec of Object.values(mergedRecent)) {
+                if (rec.key) {
+                    await bmRecentStore.setItem(rec.key, rec);
+                    await utils.sleep(1);
+                }
+            }
+        })();
+
+        this.recent = mergedRecent;
+
+        this.recentLast = null;
+        await bmRecentStore.setItem('recent-last', this.recentLast);
+
+        this.recentChanged = true;
+        this.emit('recent-changed');
+    }
+
+    async setRecentRev(value) {
+        await bmRecentStore.setItem('recent-rev', value);
+        this.recentRev = value;
+    }
+
+    async setRecentDiffRev(value) {
+        await bmRecentStore.setItem('recent-diff-rev', value);
+        this.recentDiffRev = 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);        
@@ -433,7 +471,7 @@ class BookManager {
     emit(eventName, value) {
     emit(eventName, value) {
         if (this.eventListeners) {
         if (this.eventListeners) {
             (async() => {
             (async() => {
-                await utils.sleep(1);
+                await utils.sleep(1);//неблокирующая рассылка сообщений
                 for (const listener of this.eventListeners) {
                 for (const listener of this.eventListeners) {
                     //console.log(eventName);
                     //console.log(eventName);
                     listener(eventName, value);
                     listener(eventName, value);

+ 2 - 2
client/components/Reader/versionHistory.js

@@ -6,10 +6,10 @@ export const versionHistory = [
 `
 `
 <ul>
 <ul>
     <li>налажена работа https-версии сайта, рекомендуется плавный переход</li>
     <li>налажена работа https-версии сайта, рекомендуется плавный переход</li>
-    <li>добавлена возможность загрузки и работы читалки в оффлайн-режиме (при отсутствии интернета)</li>
+    <li>добавлена возможность загрузки и работы https-версии читалки в оффлайн-режиме (при отсутствии интернета)</li>
     <li>упрощение механизма серверной синхронизации с целью повышения надежности и избавления от багов</li>
     <li>упрощение механизма серверной синхронизации с целью повышения надежности и избавления от багов</li>
     <li>окна теперь можно перемещать за заголовок</li>
     <li>окна теперь можно перемещать за заголовок</li>
-    <li>улучшен внешний вид и управление на смартфонах</li>
+    <li>немного улучшен внешний вид и управление на смартфонах</li>
     <li>добавлен параметр "Компактность" в раздел "Вид"->"Текст" в настройках</li>
     <li>добавлен параметр "Компактность" в раздел "Вид"->"Текст" в настройках</li>
 </ul>
 </ul>
 `
 `