ソースを参照

Merge branch 'release/0.7.1'

Book Pauk 5 年 前
コミット
2d5c549c83

+ 2 - 2
build/linux.js

@@ -24,8 +24,8 @@ async function main() {
     await fs.ensureDir(tempDownloadDir);
 
     //sqlite3
-    const sqliteRemoteUrl = 'https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v4.1.0/node-v72-linux-x64.tar.gz';
-    const sqliteDecompressedFilename = `${tempDownloadDir}/node-v72-linux-x64/node_sqlite3.node`;
+    const sqliteRemoteUrl = 'https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v4.0.4/node-v64-linux-x64.tar.gz';
+    const sqliteDecompressedFilename = `${tempDownloadDir}/node-v64-linux-x64/node_sqlite3.node`;
 
     if (!await fs.pathExists(sqliteDecompressedFilename)) {
         // Скачиваем node_sqlite3.node для винды, т.к. pkg не включает его в сборку

+ 2 - 2
build/win.js

@@ -24,8 +24,8 @@ async function main() {
     await fs.ensureDir(tempDownloadDir);
 
     //sqlite3
-    const sqliteRemoteUrl = 'https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v4.1.0/node-v72-win32-x64.tar.gz';
-    const sqliteDecompressedFilename = `${tempDownloadDir}/node-v72-win32-x64/node_sqlite3.node`;
+    const sqliteRemoteUrl = 'https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v4.0.4/node-v64-win32-x64.tar.gz';
+    const sqliteDecompressedFilename = `${tempDownloadDir}/node-v64-win32-x64/node_sqlite3.node`;
 
     if (!await fs.pathExists(sqliteDecompressedFilename)) {
         // Скачиваем node_sqlite3.node для винды, т.к. pkg не включает его в сборку

+ 2 - 1
client/components/Reader/Reader.vue

@@ -510,7 +510,9 @@ class Reader extends Vue {
             if (this.recentBooksActive) {
                 await this.$refs.recentBooksPage.updateTableData();
             }
+        }
 
+        if (eventName == 'set-recent' || eventName == 'recent-deleted') {
             const oldBook = this.mostRecentBookReactive;
             const newBook = bookManager.mostRecentBook();
             if (oldBook && newBook) {
@@ -975,7 +977,6 @@ class Reader extends Vue {
             }
 
             progress.setState({totalSteps: 5});
-
             // не удалось, скачиваем книгу полностью с конвертацией
             let loadCached = true;
             if (!book) {

+ 134 - 104
client/components/Reader/ServerStorage/ServerStorage.vue

@@ -72,7 +72,19 @@ class ServerStorage extends Vue {
 
     async bookManagerEvent(eventName, itemKey) {
         if (eventName == 'recent-changed') {
-            this.debouncedSaveRecent(itemKey);
+            if (itemKey) {
+                if (!this.recentDeltaInited) {
+                    this.warning('Функции сохранения на сервер пока недоступны');
+                    return;
+                }
+
+                if (!this.recentDelta)
+                    this.recentDelta = {};
+
+                this.recentDelta[itemKey] = _.cloneDeep(bookManager.recent[itemKey]);
+
+                this.debouncedSaveRecent(itemKey);
+            }
         }
     }
 
@@ -103,7 +115,7 @@ class ServerStorage extends Vue {
             await this.loadProfiles(force);
             this.checkCurrentProfile();
             await this.currentProfileChanged(force);
-            await this.loadRecent(force);
+            await this.loadRecent();
             if (force)
                 await this.saveRecent();
         }
@@ -324,170 +336,188 @@ class ServerStorage extends Vue {
         }
     }
 
-    async loadRecent(force = false, doNotifySuccess = true) {
+    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(doNotifySuccess = true) {
         if (!this.keyInited || !this.serverSyncEnabled)
             return;
 
         const oldRecentRev = bookManager.recentRev;
-        const oldRecentDiffRev = bookManager.recentDiffRev;
+        const oldRecentDeltaRev = bookManager.recentDeltaRev;
         //проверим ревизию на сервере
         let revs = null;
-        if (!force) {
-            try {
-                revs = await this.storageCheck({recent: {}, recentDiff: {}});
-                if (revs.state == 'success' && revs.items.recent.rev == oldRecentRev &&
-                    revs.items.recentDiff.rev == oldRecentDiffRev) {
-                    return;
-                }
-            } catch(e) {
-                this.error(`Ошибка соединения с сервером: ${e.message}`);
+        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;
             }
+        } catch(e) {
+            this.error(`Ошибка соединения с сервером: ${e.message}`);
+            return;
         }
 
         let recent = null;
-        if (force || revs.items.recent.rev != oldRecentRev || revs.items.recentDiff.rev != oldRecentDiffRev) {
-            try {
-                recent = await this.storageGet({recent: {}, recentDiff: {}});
-            } catch(e) {
-                this.error(`Ошибка соединения с сервером: ${e.message}`);
-                return;
+        try {
+            if (revs.items.recent.rev != oldRecentRev) {
+                recent = await this.storageGet({recent: {}, recentDelta: {}});
+            } else {
+                recent = await this.storageGet({recentDelta: {}});
+                recent.items.recent = {data: _.cloneDeep(bookManager.recent), rev: oldRecentRev};
             }
+        } catch(e) {
+            this.error(`Ошибка соединения с сервером: ${e.message}`);
+            return;
+        }
 
-            if (recent.state == 'success') {
-                let recentDiff = recent.items.recentDiff;
-                recent = recent.items.recent;
+        if (recent.state == 'success') {
+            let recentDelta = recent.items.recentDelta;
+            recent = recent.items.recent;
 
-                if (recent.rev == 0)
-                    recent.data = {};
+            if (recent.rev == 0)
+                recent.data = {};
 
-                this.oldRecent = _.cloneDeep(recent.data);
-                let newRecent = {};
-                if (recentDiff && recentDiff.data) {
-                    newRecent = utils.applyObjDiff(recent.data, recentDiff.data);
-                    this.recentDiff = _.cloneDeep(recentDiff.data);
-                    if (!utils.isObjDiff(this.recentDiff))
-                        this.recentDiff = null;
-                } else {
+            let newRecent = {};
+            if (recentDelta && recentDelta.data) {
+                if (recentDelta.data.diff) {
                     newRecent = recent.data;
-                    this.recentDiff = null;
+                    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 = {};
+            }
 
+            this.recentDeltaInited = true;
 
-                if (!bookManager.loaded) {
-                    this.warning('Ожидание загрузки списка книг перед синхронизацией');
-                    while (!bookManager.loaded) await utils.sleep(100);
-                }
-                await bookManager.setRecent(newRecent);
-                await bookManager.setRecentRev(recent.rev);
-                await bookManager.setRecentDiffRev(recentDiff.rev);
-            } else {
-                this.warning(`Неверный ответ сервера: ${recent.state}`);
+            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);
+        } else {
+            this.warning(`Неверный ответ сервера: ${recent.state}`);
         }
 
         if (doNotifySuccess)
             this.debouncedNotifySuccess();
     }
 
-    async saveRecent(itemKey) {
+    async saveRecent(itemKey, recurse) {
         if (!this.keyInited || !this.serverSyncEnabled || this.savingRecent)
             return;
 
         const bm = bookManager;
 
-        /*if (!bookManager.loaded) {
-            this.warning('Функции сохранения на сервер пока недоступны');
-            return;
-        }*/
-
-        //несколько замудреная инициализация oldRecent
-        if (!this.oldRecent) {
-            this.oldRecent = _.cloneDeep(bookManager.recent);
-        }
-
-        if (bookManager.loaded && !this.oldRecentInited) {
-            this.oldRecent = _.cloneDeep(bookManager.recent);
-            this.oldRecentInited = true;
+        //вычисление критерия сохранения целиком
+        if (!this.sameKeyCount)
+            this.sameKeyCount = 0;
+        if (this.prevItemKey == itemKey) {
+            this.sameKeyCount++;
+        } else {
+            this.sameKeyCount = 0;
         }
 
-        //вычисляем дифф
-        let diff = null;
-        if (itemKey) {//ускоренное вычисления диффа
-            let itemDiff;
-            if (this.oldRecent[itemKey]) {
-                itemDiff = utils.getObjDiff({[itemKey]: (this.oldRecentInited ? this.oldRecent[itemKey] : {})}, {[itemKey]: bm.recent[itemKey]});
-            } else {
-                itemDiff = utils.getObjDiff({}, {[itemKey]: bm.recent[itemKey]});
-            }
-            if (this.recentDiff) {
-                diff = this.recentDiff;
-                if (itemDiff.change[itemKey])
-                    diff.change[itemKey] = itemDiff.change[itemKey];
-                if (itemDiff.add[itemKey])
-                    diff.add[itemKey] = itemDiff.add[itemKey];
-            } else {
-                diff = itemDiff;
+        const l = Object.keys(this.recentDelta).length - (1*(!!this.recentDelta.diff));
+        this.makeDeltaDiff = (l == 1 && this.prevItemKey == itemKey ? this.makeDeltaDiff : false);
+        const forceSaveRecent =  l > 10 || (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);
             }
-        } else {//медленное вычисление диффа
-            if (this.oldRecentInited) {
-                diff = utils.getObjDiff(this.oldRecent, bm.recent);
-            } else
-                return;
-        }
-
-        if (utils.isEmptyObjDiff(diff))
-            return;
-
-        //вычисление критерия сохранения целиком
-        let forceSaveRecent = JSON.stringify(diff).length > 2000;
-        if (!forceSaveRecent && itemKey) {
-            if (!this.sameKeyCount)
-                this.sameKeyCount = 0;
-            if (this.prevItemKey == itemKey)
-                this.sameKeyCount++;
-
-            forceSaveRecent = this.sameKeyCount > 5 && (Object.keys(diff.change).length > 1);
-
-            this.sameKeyCount = (!forceSaveRecent ? this.sameKeyCount : 0);
-            this.prevItemKey = itemKey;
+            delete this.recentDelta.diff;
         }
 
-        this.recentDiff = diff;
+        //сохранение
         this.savingRecent = true;        
         try {
             if (forceSaveRecent) {//сохраняем recent целиком
                 let result = {state: ''};
 
                 try {
-                    result = await this.storageSet({recent: {rev: bm.recentRev + 1, data: bm.recent}, recentDiff: {rev: bm.recentDiffRev + 1, data: {}}});
+                    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') {
-                    await this.loadRecent(true, false);
+                    await this.loadRecent(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.oldRecent = _.cloneDeep(bm.recent);
-                    this.recentDiff = null;
+                    this.makeDeltaDiff = true;
+                    this.prevSavedItem = _.cloneDeep(bm.recent[itemKey]);
+
+                    this.recentDelta = {};
                     await bm.setRecentRev(bm.recentRev + 1);
-                    await bm.setRecentDiffRev(bm.recentDiffRev + 1);
+                    await bm.setRecentDeltaRev(bm.recentDeltaRev + 1);
                 }
             } else {//сохраняем только дифф
                 let result = {state: ''};
 
                 try {
-                    result = await this.storageSet({recentDiff: {rev: bm.recentDiffRev + 1, data: this.recentDiff}});
+                    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);
+                    await this.loadRecent(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.setRecentDiffRev(bm.recentDiffRev + 1);
+                    await bm.setRecentDeltaRev(bm.recentDeltaRev + 1);
                 }
             }
         } finally {

+ 9 - 6
client/components/Reader/share/bookManager.js

@@ -37,7 +37,7 @@ class BookManager {
         }
 
         this.recentRev = await bmRecentStore.getItem('recent-rev') || 0;
-        this.recentDiffRev = await bmRecentStore.getItem('recent-diff-rev') || 0;
+        this.recentDeltaRev = await bmRecentStore.getItem('recent-delta-rev') || 0;
 
         this.recentChanged = true;
 
@@ -356,7 +356,8 @@ class BookManager {
         let result = this.recent[value.key];
         if (!result) {
             result = await bmRecentStore.getItem(value.key);
-            this.recent[value.key] = result;
+            if (result)
+                this.recent[value.key] = result;
         }
         return result;
     }
@@ -369,6 +370,7 @@ class BookManager {
             this.recentLast = null;
             await bmRecentStore.setItem('recent-last', this.recentLast);
         }
+        this.emit('recent-deleted', value.key);
         this.emit('recent-changed', value.key);
     }
 
@@ -410,6 +412,7 @@ class BookManager {
 
         if (this.recentLast !== oldRecentLast)
             this.emit('recent-changed');
+
         return result;
     }
 
@@ -448,6 +451,7 @@ class BookManager {
         await bmRecentStore.setItem('recent-last', this.recentLast);
 
         this.recentChanged = true;
+        this.emit('set-recent');
         this.emit('recent-changed');
     }
 
@@ -456,12 +460,11 @@ class BookManager {
         this.recentRev = value;
     }
 
-    async setRecentDiffRev(value) {
-        await bmRecentStore.setItem('recent-diff-rev', value);
-        this.recentDiffRev = 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);        

+ 11 - 0
client/components/Reader/versionHistory.js

@@ -1,4 +1,15 @@
 export const versionHistory = [
+{
+    showUntil: '2019-09-19',
+    header: '0.7.1 (2019-09-20)',
+    content:
+`
+<ul>
+    <li>исправления багов</li>
+</ul>
+`
+},
+
 {
     showUntil: '2019-10-01',
     header: '0.7.0 (2019-09-07)',

ファイルの差分が大きいため隠しています
+ 324 - 312
package-lock.json


+ 3 - 3
package.json

@@ -1,6 +1,6 @@
 {
   "name": "Liberama",
-  "version": "0.7.0",
+  "version": "0.7.1",
   "engines": {
     "node": ">=10.0.0"
   },
@@ -41,7 +41,7 @@
     "mini-css-extract-plugin": "^0.5.0",
     "null-loader": "^0.1.1",
     "optimize-css-assets-webpack-plugin": "^5.0.3",
-    "pkg": "^4.4.0",
+    "pkg": "4.3.7",
     "terser-webpack-plugin": "^1.4.1",
     "url-loader": "^1.1.2",
     "vue-class-component": "^6.3.2",
@@ -77,7 +77,7 @@
     "safe-buffer": "^5.2.0",
     "sjcl": "^1.0.8",
     "sql-template-strings": "^2.2.2",
-    "sqlite": "^3.0.3",
+    "sqlite": "3.0.0",
     "tar-fs": "^2.0.0",
     "unbzip2-stream": "^1.3.3",
     "vue": "^2.6.10",

+ 7 - 0
server/core/ReaderWorker.js

@@ -7,6 +7,7 @@ const FileDownloader = require('./FileDownloader');
 const FileDecompressor = require('./FileDecompressor');
 const BookConverter = require('./BookConverter');
 const utils = require('./utils');
+const log = require('./getLogger').getLog();
 
 let singleCleanExecute = false;
 
@@ -133,6 +134,7 @@ class ReaderWorker {
 
     async periodicCleanDir(dir, maxSize, timeout) {
         try {
+            log(`Start clean dir: ${dir}, maxSize=${maxSize}`);
             const list = await fs.readdir(dir);
 
             let size = 0;
@@ -144,16 +146,21 @@ class ReaderWorker {
                     files.push({name, stat});
                 }
             }
+            log(`found ${files.length} files in dir ${dir}`);
 
             files.sort((a, b) => a.stat.mtimeMs - b.stat.mtimeMs);
 
             let i = 0;
             while (i < files.length && size > maxSize) {
                 const file = files[i];
+                log(`rm ${dir}/${file.name}`);
                 await fs.remove(`${dir}/${file.name}`);
                 size -= file.stat.size;
                 i++;
             }
+            log(`removed ${i} files`);
+        } catch(e) {
+            log(LM_ERR, e.message);
         } finally {
             setTimeout(() => {
                 this.periodicCleanDir(dir, maxSize, timeout);

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません