Browse Source

Рефакторинг, упрощение, начало переделки ServerStorage

Book Pauk 5 years ago
parent
commit
a2c393b06b

+ 40 - 6
client/components/Reader/HistoryPage/HistoryPage.vue

@@ -3,7 +3,8 @@
         <div class="mainWindow" @click.stop>
             <Window @close="close">
                 <template slot="header">
-                    Последние 100 открытых книг
+                    <span v-show="!loading">Последние {{tableData ? tableData.length : 0}} открытых книг</span>
+                    <span v-show="loading"><i class="el-icon-loading"></i> Список загружается</span>
                 </template>
 
                 <el-table
@@ -104,7 +105,7 @@ import Component from 'vue-class-component';
 import path from 'path';
 import _ from 'lodash';
 
-import {formatDate} from '../../../share/utils';
+import * as utils from '../../../share/utils';
 import Window from '../../share/Window.vue';
 import bookManager from '../share/bookManager';
 
@@ -119,6 +120,7 @@ export default @Component({
     },
 })
 class HistoryPage extends Vue {
+    loading = false;
     search = null;
     tableData = null;
 
@@ -126,28 +128,60 @@ class HistoryPage extends Vue {
     }
 
     init() {
-        this.updateTableData();
+        bookManager.addEventListener(this.bookManagerEvent);
+        this.updateTableData(5);
         this.$nextTick(() => {
-            this.$refs.input.focus();
+            //this.$refs.input.focus();
         });
+        (async() => {//отбражение подгрузки списка
+            await utils.sleep(1000);
+            if (this.bookManagerLoaded)
+                this.updateTableData();
+            else {
+                let i = 0;
+                let j = 5;
+                while (i < 500 && !this.bookManagerLoaded) {
+                    if (i % j == 0) {
+                        bookManager.sortedRecentCached = null;
+                        this.updateTableData(100);
+                        j *= 2;
+                    }
+
+                    await utils.sleep(100);
+                    i++;
+                }
+            }
+        })();
+    }
+
+    bookManagerEvent(eventName) {
+        if (eventName == 'load-stored-finish') {
+            this.updateTableData();
+            this.bookManagerLoaded = true;
+        }
     }
 
     rowKey(row) {
         return row.key;
     }
 
-    updateTableData() {
+    updateTableData(limit) {
         let result = [];
 
+        this.loading = !!limit;
         const sorted = bookManager.getSortedRecent();
+
         for (let i = 0; i < sorted.length; i++) {
             const book = sorted[i];
             if (book.deleted)
                 continue;
 
+            if (limit && result.length >= limit)
+                break;
+
             let d = new Date();
             d.setTime(book.touchTime);
-            const t = formatDate(d).split(' ');
+            const t = utils.formatDate(d).split(' ');
 
             let perc = '';
             let textLen = '';

+ 17 - 14
client/components/Reader/Reader.vue

@@ -73,7 +73,7 @@
             <SettingsPage v-if="settingsActive" ref="settingsPage" @settings-toggle="settingsToggle"></SettingsPage>
             <HelpPage v-if="helpActive" ref="helpPage" @help-toggle="helpToggle"></HelpPage>
             <ClickMapPage v-show="clickMapActive" ref="clickMapPage"></ClickMapPage>
-            <ServerStorage v-show="hidden" ref="serverStorage"></ServerStorage>
+            <!--ServerStorage v-show="hidden" ref="serverStorage"></ServerStorage-->
 
             <el-dialog
                 title="Что нового:"
@@ -110,7 +110,7 @@ import HistoryPage from './HistoryPage/HistoryPage.vue';
 import SettingsPage from './SettingsPage/SettingsPage.vue';
 import HelpPage from './HelpPage/HelpPage.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 readerApi from '../../api/reader';
@@ -130,7 +130,7 @@ export default @Component({
         SettingsPage,
         HelpPage,
         ClickMapPage,
-        ServerStorage,
+        //ServerStorage,
     },
     watch: {
         bookPos: function(newValue) {
@@ -157,10 +157,12 @@ export default @Component({
             this.updateRoute();
         },
         loaderActive: function(newValue) {
-            const recent = this.mostRecentBook();
-            if (!newValue && !this.loading && recent && !bookManager.hasBookParsed(recent)) {
-                this.loadBook(recent);
-            }
+            (async() => {
+                const recent = this.mostRecentBook();
+                if (!newValue && !this.loading && recent && !await bookManager.hasBookParsed(recent)) {
+                    this.loadBook(recent);
+                }
+            })();
         },
     },
 })
@@ -216,7 +218,7 @@ class Reader extends Vue {
             }
         }, 500);
 
-        this.debouncedSaveRecent = _.debounce(async() => {
+        /*this.debouncedSaveRecent = _.debounce(async() => {
             const serverStorage = this.$refs.serverStorage;
             while (!serverStorage.inited) await utils.sleep(1000);
             await serverStorage.saveRecent();
@@ -226,7 +228,7 @@ class Reader extends Vue {
             const serverStorage = this.$refs.serverStorage;
             while (!serverStorage.inited) await utils.sleep(1000);
             await serverStorage.saveRecentLast();
-        }, 1000);
+        }, 1000);*/
 
         document.addEventListener('fullscreenchange', () => {
             this.fullScreenActive = (document.fullscreenElement !== null);
@@ -379,8 +381,8 @@ class Reader extends Vue {
         this.debouncedUpdateRoute();
     }
 
-    async bookManagerEvent(eventName) {
-        const serverStorage = this.$refs.serverStorage;
+    async bookManagerEvent(/*eventName*/) {
+        /*const serverStorage = this.$refs.serverStorage;
         if (eventName == 'load-meta-finish') {
             serverStorage.init();
             const result = await bookManager.cleanRecentBooks();
@@ -415,7 +417,7 @@ class Reader extends Vue {
             } else {
                 this.debouncedSaveRecent();
             }
-        }
+        }*/
     }
 
     get toolBarActive() {
@@ -759,7 +761,8 @@ class Reader extends Vue {
             //акивируем страницу с текстом
             this.$nextTick(async() => {
                 const last = this.mostRecentBookReactive;
-                const isParsed = bookManager.hasBookParsed(last);
+                const isParsed = await bookManager.hasBookParsed(last);
+
                 if (!isParsed) {
                     this.$root.$emit('set-app-title');
                     return;
@@ -793,7 +796,7 @@ class Reader extends Vue {
 
         // уже просматривается сейчас
         const lastBook = (this.$refs.page ? this.$refs.page.lastBook : null);
-        if (!opts.force && lastBook && lastBook.url == url && bookManager.hasBookParsed(lastBook)) {
+        if (!opts.force && lastBook && lastBook.url == url && await bookManager.hasBookParsed(lastBook)) {
             this.loaderActive = false;
             return;
         }

+ 68 - 180
client/components/Reader/share/bookManager.js

@@ -18,46 +18,30 @@ const bmRecentStore = localForage.createInstance({
     name: 'bmRecentStore'
 });
 
-const bmCacheStore = localForage.createInstance({
-    name: 'bmCacheStore'
-});
-
 class BookManager {
     async init(settings) {
+        this.loaded = false;
         this.settings = settings;
 
         this.eventListeners = [];
+        this.books = {};
+        this.recent = {};
 
-        //bmCacheStore нужен только для ускорения загрузки читалки
-        this.booksCached = await bmCacheStore.getItem('books');
-        if (!this.booksCached)
-            this.booksCached = {};
-        this.recent = await bmCacheStore.getItem('recent');
-        this.recentLast = await bmCacheStore.getItem('recent-last');
+        this.recentLast = await bmRecentStore.getItem('recent-last');
         if (this.recentLast)
             this.recent[this.recentLast.key] = this.recentLast;
-        this.recentRev = await bmRecentStore.getItem('recent-rev') || 0;
-        this.recentLastRev = await bmRecentStore.getItem('recent-last-rev') || 0;
-        this.recentLastDiffRev = await bmRecentStore.getItem('recent-last-diff-rev') || 0;
-        this.books = Object.assign({}, this.booksCached);
-
-        this.recentChanged2 = true;
-
-        if (!this.books || !this.recent) {
-            this.books = {};
-            this.recent = {};
-            await this.loadMeta(true);
-        } else {
-            this.loadMeta(false);
-        }
+
+        this.recentChanged = true;
+
+        this.loadStored();//no await
     }
 
-    //долгая загрузка из хранилища,
-    //хранение в отдельных записях дает относительно
-    //нормальное поведение при нескольких вкладках с читалкой в браузере
-    async loadMeta(immediate) {
-        if (!immediate)
-            await utils.sleep(2000);
+    //Долгая асинхронная загрузка из хранилища.
+    //Хранение в отдельных записях дает относительно
+    //нормальное поведение при нескольких вкладках с читалкой в браузере.
+    async loadStored() {
+        //даем время для загрузки последней читаемой книги, чтобы не блокировать приложение
+        await utils.sleep(2000);
 
         let len = await bmMetaStore.length();
         for (let i = 0; i < len; i++) {
@@ -68,6 +52,7 @@ class BookManager {
                 let meta = await bmMetaStore.getItem(key);
 
                 if (_.isObject(meta)) {
+                    //уже может быть распарсена книга
                     const oldBook = this.books[meta.key];
                     this.books[meta.key] = meta;
 
@@ -80,22 +65,19 @@ class BookManager {
             }
         }
 
-        //"ленивая" загрузка
-        (async() => {
-            let key = null;
-            len = await bmRecentStore.length();
-            for (let i = 0; i < len; i++) {
-                key = await bmRecentStore.key(i);
-                if (key) {
-                    let r = await bmRecentStore.getItem(key);
-                    if (_.isObject(r) && r.key) {
-                        this.recent[r.key] = r;
-                    }
-                } else  {
-                    await bmRecentStore.removeItem(key);
+        let key = null;
+        len = await bmRecentStore.length();
+        for (let i = 0; i < len; i++) {
+            key = await bmRecentStore.key(i);
+            if (key) {
+                let r = await bmRecentStore.getItem(key);
+                if (_.isObject(r) && r.key) {
+                    this.recent[r.key] = r;
                 }
+            } else  {
+                await bmRecentStore.removeItem(key);
             }
-        })();
+        }
 
         //размножение для дебага
         /*if (key) {
@@ -106,17 +88,10 @@ class BookManager {
         }*/
         
         await this.cleanBooks();
+        await this.cleanRecentBooks();
 
-        //очистка позже
-        //await this.cleanRecentBooks();
-
-        this.booksCached = {};
-        for (const key in this.books) {
-            this.booksCached[key] = this.metaOnly(this.books[key]);
-        }
-        await bmCacheStore.setItem('books', this.booksCached);
-        await bmCacheStore.setItem('recent', this.recent);
-        this.emit('load-meta-finish');
+        this.loaded = true;
+        this.emit('load-stored-finish');
     }
 
     async cleanBooks() {
@@ -136,7 +111,7 @@ class BookManager {
             }
 
             if (size > maxDataSize && toDel) {
-                await this._delBook(toDel);
+                await this.delBook(toDel);
             } else {
                 break;
             }
@@ -211,9 +186,7 @@ class BookManager {
         return inflator.result;
     }
 
-    async addBook(newBook, callback) {
-        if (!this.books) 
-            await this.init();
+    async addBook(newBook, callback) {        
         let meta = {url: newBook.url, path: newBook.path};
         meta.key = this.keyFromUrl(meta.url);
         meta.addTime = Date.now();
@@ -233,43 +206,53 @@ class BookManager {
 
         let data = newBook.data;
         if (result.dataCompressed) {
-            //data = utils.pako.deflate(data, {level: 9});
+            //data = utils.pako.deflate(data, {level: 5});
             data = await this.deflateWithProgress(data, cb2);
             result.dataCompressedLength = data.byteLength;
         }
         callback(95);
 
         this.books[meta.key] = result;
-        this.booksCached[meta.key] = this.metaOnly(result);
 
         await bmMetaStore.setItem(`bmMeta-${meta.key}`, this.metaOnly(result));
         await bmDataStore.setItem(`bmData-${meta.key}`, data);
-        await bmCacheStore.setItem('books', this.booksCached);
 
         callback(100);
         return result;
     }
 
-    hasBookParsed(meta) {
+    async hasBookParsed(meta) {
         if (!this.books) 
             return false;
         if (!meta.url)
             return false;
         if (!meta.key)
             meta.key = this.keyFromUrl(meta.url);
+
         let book = this.books[meta.key];
+
+        if (!book && !this.loaded) {
+            book = await bmDataStore.getItem(`bmMeta-${meta.key}`);
+            if (book)
+                this.books[meta.key] = book;
+        }
+
         return !!(book && book.parsed);
     }
 
     async getBook(meta, callback) {
-        if (!this.books) 
-            await this.init();
         let result = undefined;
         if (!meta.key)
             meta.key = this.keyFromUrl(meta.url);
 
         result = this.books[meta.key];
 
+        if (!result) {
+            result = await bmDataStore.getItem(`bmMeta-${meta.key}`);
+            if (result)
+                this.books[meta.key] = result;
+        }
+
         if (result && !result.parsed) {
             let data = await bmDataStore.getItem(`bmData-${meta.key}`);
             callback(5);
@@ -303,27 +286,14 @@ class BookManager {
         return result;
     }
 
-    async _delBook(meta) {
+    async delBook(meta) {
         await bmMetaStore.removeItem(`bmMeta-${meta.key}`);
         await bmDataStore.removeItem(`bmData-${meta.key}`);
 
         delete this.books[meta.key];
-        delete this.booksCached[meta.key];
-    }
-
-    async delBook(meta) {
-        if (!this.books) 
-            await this.init();
-
-        await this._delBook(meta);
-
-        await bmCacheStore.setItem('books', this.booksCached);
     }
 
     async parseBook(meta, data, callback) {
-        if (!this.books) 
-            await this.init();
-
         const parsed = new BookParser(this.settings);
 
         const parsedMeta = await parsed.parse(data, callback);
@@ -347,9 +317,8 @@ class BookManager {
         return utils.stringToHex(url);
     }
 
+    //-- recent --------------------------------------------------------------
     async setRecentBook(value) {
-        if (!this.recent) 
-            await this.init();
         const result = this.metaOnly(value);
         result.touchTime = Date.now();
         result.deleted = 0;
@@ -366,66 +335,51 @@ class BookManager {
 
         await bmRecentStore.setItem(result.key, result);
 
-        //кэшируем, аккуратно
-        let saveRecent = false;
-        if (!(this.recentLast && this.recentLast.key == result.key)) {
-            await bmCacheStore.setItem('recent', this.recent);
-            saveRecent = true;
-        }
         this.recentLast = result;
-        await bmCacheStore.setItem('recent-last', this.recentLast);
-
-        this.mostRecentCached = result;
-        this.recentChanged2 = true;
+        await bmRecentStore.setItem('recent-last', this.recentLast);
 
-        if (saveRecent)
-            this.emit('save-recent');
-        this.emit('recent-changed');
+        this.recentChanged = true;
         return result;
     }
 
     async getRecentBook(value) {
-        if (!this.recent) 
-            await this.init();
-        return this.recent[value.key];
+        let result = this.recent[value.key];
+        if (!result) {
+            result = await bmRecentStore.getItem(value.key);
+            this.recent[value.key] = result;
+        }
+        return result;
     }
 
     async delRecentBook(value) {
-        if (!this.recent) 
-            await this.init();
-
         this.recent[value.key].deleted = 1;
         await bmRecentStore.setItem(value.key, this.recent[value.key]);
-        await bmCacheStore.setItem('recent', this.recent);
 
-        this.mostRecentCached = null;
-        this.recentChanged2 = true;
+        this.recentLast = null;
+        await bmRecentStore.setItem('recent-last', this.recentLast);
 
-        this.emit('save-recent');
+        this.recentChanged = true;
     }
 
     async cleanRecentBooks() {
-        if (!this.recent) 
-            await this.init();
-
         const sorted = this.getSortedRecent();
 
         let isDel = false;
         for (let i = 1000; i < sorted.length; i++) {
             await bmRecentStore.removeItem(sorted[i].key);
             delete this.recent[sorted[i].key];
+            await bmRecentStore.removeItem(sorted[i].key);
             isDel = true;
         }
 
         this.sortedRecentCached = null;
-        await bmCacheStore.setItem('recent', this.recent);
 
         return isDel;
     }
 
     mostRecentBook() {
-        if (this.mostRecentCached) {
-            return this.mostRecentCached;
+        if (this.recentLast) {
+            return this.recentLast;
         }
 
         let max = 0;
@@ -437,12 +391,14 @@ class BookManager {
                 result = book;
             }
         }
-        this.mostRecentCached = result;
+        this.recentLast = result;
+        bmRecentStore.setItem('recent-last', this.recentLast);//no await
+
         return result;
     }
 
     getSortedRecent() {
-        if (!this.recentChanged2 && this.sortedRecentCached) {
+        if (!this.recentChanged && this.sortedRecentCached) {
             return this.sortedRecentCached;
         }
 
@@ -451,78 +407,10 @@ class BookManager {
         result.sort((a, b) => b.touchTime - a.touchTime);
 
         this.sortedRecentCached = result;
-        this.recentChanged2 = false;
+        this.recentChanged = false;
         return result;
     }
 
-    async setRecent(value) {
-        const mergedRecent = _.cloneDeep(this.recent);
-
-        Object.assign(mergedRecent, value);
-        const newRecent = {};
-        
-        //"ленивое" обновление хранилища
-        (async() => {
-            for (const rec of Object.values(mergedRecent)) {
-                if (rec.key) {
-                    await bmRecentStore.setItem(rec.key, rec);
-                    await utils.sleep(1);
-                }
-            }
-        })();
-
-        for (const rec of Object.values(mergedRecent)) {
-            if (rec.key) {
-                newRecent[rec.key] = rec;
-            }
-        }
-
-        this.recent = newRecent;
-        await bmCacheStore.setItem('recent', this.recent);
-
-        this.recentLast = null;
-        await bmCacheStore.setItem('recent-last', this.recentLast);
-
-        this.mostRecentCached = null;
-        this.emit('recent-changed');
-    }
-
-    async setRecentRev(value) {
-        await bmRecentStore.setItem('recent-rev', value);
-        this.recentRev = value;
-    }
-
-    async setRecentLast(value) {
-        if (!value.key)
-            value = null;
-
-        this.recentLast = value;
-        await bmCacheStore.setItem('recent-last', this.recentLast);
-        if (value && value.key) {
-            //гарантия переключения книги
-            const mostRecent = this.mostRecentBook();
-            if (mostRecent)
-                this.recent[mostRecent.key].touchTime = value.touchTime - 1;
-
-            this.recent[value.key] = value;
-            await bmRecentStore.setItem(value.key, value);
-            await bmCacheStore.setItem('recent', this.recent);
-        }
-
-        this.mostRecentCached = null;
-        this.emit('recent-changed');
-    }
-
-    async setRecentLastRev(value) {
-        await bmRecentStore.setItem('recent-last-rev', value);
-        this.recentLastRev = value;
-    }
-
-    async setRecentLastDiffRev(value) {
-        await bmRecentStore.setItem('recent-last-diff-rev', value);
-        this.recentLastDiffRev = value;
-    }
-
     addEventListener(listener) {
         if (this.eventListeners.indexOf(listener) < 0)
             this.eventListeners.push(listener);