Compare commits

...

15 Commits
0.7.0 ... 0.7.1

Author SHA1 Message Date
Book Pauk
2d5c549c83 Merge branch 'release/0.7.1' 2019-09-20 19:58:22 +07:00
Book Pauk
9f6072dfe1 Версия 0.7.1 2019-09-20 19:54:59 +07:00
Book Pauk
69c44fe1ab Откатил новые версии pkg и sqlite, новый pkg глючит 2019-09-20 19:53:55 +07:00
Book Pauk
4fa7b2443e Добавил дебаг-лог в periodicCleanDir 2019-09-20 19:35:22 +07:00
Book Pauk
25a69592bb Правка багов 2019-09-20 19:14:14 +07:00
Book Pauk
44e0b26990 Поправка бага 2019-09-20 18:58:36 +07:00
Book Pauk
c4496f8dc8 Улучшение механизма синхронизации 2019-09-20 18:53:21 +07:00
Book Pauk
9e296231d9 Поправки багов 2019-09-20 16:54:03 +07:00
Book Pauk
49b3f05d65 Поправки багов 2019-09-20 16:38:33 +07:00
Book Pauk
f124b9c050 Переделки синхронизации, замена diff на delta 2019-09-20 16:29:19 +07:00
Book Pauk
63a86f7c06 Версия 0.7.1 2019-09-20 14:04:17 +07:00
Book Pauk
fd0f523c64 Улучшение синхронизации 2019-09-19 20:39:01 +07:00
Book Pauk
487e605520 Поправлен баг 2019-09-19 18:19:14 +07:00
Book Pauk
9e169e1f4b Улучшение синхронизации 2019-09-19 17:51:04 +07:00
Book Pauk
9612e7ebcd Merge tag '0.7.0' into develop
0.7.0
2019-09-07 22:15:32 +07:00
9 changed files with 1388 additions and 1085 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

2167
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

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

View File

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