diff --git a/client/components/Reader/Reader.vue b/client/components/Reader/Reader.vue
index 7692db73..5123211b 100644
--- a/client/components/Reader/Reader.vue
+++ b/client/components/Reader/Reader.vue
@@ -73,7 +73,7 @@
-
+
{
- 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', () => {
this.fullScreenActive = (document.fullscreenElement !== null);
});
@@ -347,6 +335,7 @@ class Reader extends Vue {
this.checkActivateDonateHelpPage();
this.loading = false;
+ await this.$refs.serverStorage.init();
await this.showWhatsNew();
await this.showMigration();
})();
@@ -516,14 +505,6 @@ class Reader extends Vue {
}
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 (this.recentBooksActive) {
await this.$refs.recentBooksPage.updateTableData();
@@ -545,12 +526,6 @@ class Reader extends Vue {
this.bookPosChanged({bookPos: newBook.bookPos});
}
}
-
- /*if (eventName == 'recent-changed') {
- this.debouncedSaveRecentLast();
- } else {
- this.debouncedSaveRecent();
- }*/
}
}
diff --git a/client/components/Reader/ServerStorage/ServerStorage.vue b/client/components/Reader/ServerStorage/ServerStorage.vue
index 3f27f755..1fc9f5d2 100644
--- a/client/components/Reader/ServerStorage/ServerStorage.vue
+++ b/client/components/Reader/ServerStorage/ServerStorage.vue
@@ -13,8 +13,6 @@ import readerApi from '../../../api/reader';
import * as utils from '../../../share/utils';
import * as cryptoUtils from '../../../share/cryptoUtils';
-const maxSetTries = 5;
-
export default @Component({
watch: {
serverSyncEnabled: function() {
@@ -46,11 +44,18 @@ class ServerStorage extends Vue {
this.saveSettings();
}, 500);
+ this.debouncedSaveRecent = _.debounce(() => {
+ this.saveRecent();
+ }, 1000);
+
+ this.debouncedNotifySuccess = _.debounce(() => {
+ this.success('Данные синхронизированы с сервером');
+ }, 1000);
+
this.oldProfiles = {};
this.oldSettings = {};
this.oldRecent = {};
- this.oldRecentLast = {};
- this.oldRecentLastDiff = {};
+ this.oldRecentDiff = {};
}
async init() {
@@ -61,13 +66,27 @@ class ServerStorage extends Vue {
} else {
await this.serverStorageKeyChanged();
}
- this.oldRecent = _.cloneDeep(bookManager.recent);
- this.oldRecentLast = _.cloneDeep(bookManager.recentLast) || {};
+ bookManager.addEventListener(this.bookManagerEvent);
} finally {
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() {
const key = utils.toBase58(utils.randomArray(32));
this.commit('reader/setServerStorageKey', key);
@@ -146,10 +165,6 @@ class ServerStorage extends Vue {
}
}
- notifySuccess() {
- this.success('Данные синхронизированы с сервером');
- }
-
success(message) {
if (this.showServerStorageMessages)
this.$notify.success({message});
@@ -165,7 +180,7 @@ class ServerStorage extends Vue {
this.$notify.error({message});
}
- async loadSettings(force) {
+ async loadSettings(force = false, doNotifySuccess = true) {
if (!this.keyInited || !this.serverSyncEnabled || !this.currentProfile)
return;
@@ -202,7 +217,8 @@ class ServerStorage extends Vue {
this.commit('reader/setSettings', sets.data);
this.commit('reader/setSettingsRev', {[setsId]: sets.rev});
- this.notifySuccess();
+ if (doNotifySuccess)
+ this.debouncedNotifySuccess();
} else {
this.warning(`Неверный ответ сервера: ${sets.state}`);
}
@@ -220,32 +236,18 @@ class ServerStorage extends Vue {
try {
const setsId = `settings-${this.currentProfile}`;
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.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)
return;
@@ -289,8 +291,10 @@ class ServerStorage extends Vue {
this.oldProfiles = _.cloneDeep(prof.data);
this.commit('reader/setProfiles', prof.data);
this.commit('reader/setProfilesRev', prof.rev);
+ this.checkCurrentProfile();
- this.notifySuccess();
+ if (doNotifySuccess)
+ this.debouncedNotifySuccess();
} else {
this.warning(`Неверный ответ сервера: ${prof.state}`);
}
@@ -304,7 +308,7 @@ class ServerStorage extends Vue {
if (utils.isEmptyObjDiff(diff))
return;
- //обнуляются профили во время разработки, подстраховка
+ //обнуляются профили во время разработки при hotReload, подстраховка
if (!this.$store.state.reader.allowProfilesSave) {
console.error('Сохранение профилей не санкционировано');
return;
@@ -313,33 +317,16 @@ class ServerStorage extends Vue {
this.savingProfiles = true;
try {
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.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)
return;
- const oldRev = bookManager.recentRev;
- const oldLastRev = bookManager.recentLastRev;
- const oldLastDiffRev = bookManager.recentLastDiffRev;
+ const oldRecentRev = bookManager.recentRev;
+ const oldRecentDiffRev = bookManager.recentDiffRev;
//проверим ревизию на сервере
let revs = null;
if (!force) {
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;
}
} catch(e) {
@@ -371,7 +356,32 @@ class ServerStorage extends Vue {
}
}
- if (force || revs.items.recent.rev != oldRev) {
+console.log('load');
+ let recentDiff = null;
+ if (force || revs.items.recentDiff.rev != oldRecentDiffRev) {
+ try {
+ recentDiff = await this.storageGet({recentDiff: {}});
+ } catch(e) {
+ this.error(`Ошибка соединения с сервером: ${e.message}`);
+ return;
+ }
+
+ if (recentDiff.state == 'success') {
+ recentDiff = recentDiff.items.recentDiff;
+
+ if (recentDiff.rev == 0)
+ recentDiff.data = {};
+
+ this.oldRecentDiff = _.cloneDeep(recentDiff.data);
+
+ await bookManager.setRecentDiffRev(recentDiff.rev);
+ } else {
+ this.warning(`Неверный ответ сервера: ${recentDiff.state}`);
+ recentDiff = null;
+ }
+ }
+
+ if (force || revs.items.recent.rev != oldRecentRev) {
let recent = null;
try {
recent = await this.storageGet({recent: {}});
@@ -386,46 +396,23 @@ class ServerStorage extends Vue {
if (recent.rev == 0)
recent.data = {};
- this.oldRecent = _.cloneDeep(recent.data);
- await bookManager.setRecent(recent.data);
+ let newRecent = {};
+ if (recentDiff && recentDiff.data) {
+ newRecent = utils.applyObjDiff(recent.data, recentDiff.data);
+ } else {
+ newRecent = recent.data;
+ }
+
+ this.oldRecent = _.cloneDeep(newRecent);
+ await bookManager.setRecent(newRecent);
await bookManager.setRecentRev(recent.rev);
} else {
this.warning(`Неверный ответ сервера: ${recent.state}`);
}
}
- if (force || revs.items.recentLast.rev != oldLastRev || revs.items.recentLastDiff.rev != oldLastDiffRev) {
- let recentLast = null;
- try {
- recentLast = await this.storageGet({recentLast: {}, recentLastDiff: {}});
- } catch(e) {
- this.error(`Ошибка соединения с сервером: ${e.message}`);
- 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 = {};
-
- this.oldRecentLastDiff = _.cloneDeep(recentLastDiff.data);
- this.oldRecentLast = _.cloneDeep(recentLast.data);
-
- recentLast.data = utils.applyObjDiff(recentLast.data, recentLastDiff.data);
-
- await bookManager.setRecentLast(recentLast.data);
- await bookManager.setRecentLastRev(recentLast.rev);
- await bookManager.setRecentLastDiffRev(recentLastDiff.rev);
- } else {
- this.warning(`Неверный ответ сервера: ${recentLast.state}`);
- }
- }
-
- this.notifySuccess();
+ if (doNotifySuccess)
+ this.debouncedNotifySuccess();
}
async saveRecent() {
@@ -437,163 +424,29 @@ class ServerStorage extends Vue {
const diff = utils.getObjDiff(this.oldRecent, bm.recent);
if (utils.isEmptyObjDiff(diff))
return;
-
+console.log('save');
this.savingRecent = true;
try {
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);
await bm.setRecentRev(bm.recentRev + 1);
- await this.saveRecentLast(true);
}
} finally {
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) {
return await this.storageApi('check', items);
}
diff --git a/client/components/Reader/SettingsPage/SettingsPage.vue b/client/components/Reader/SettingsPage/SettingsPage.vue
index 64edc202..231b7820 100644
--- a/client/components/Reader/SettingsPage/SettingsPage.vue
+++ b/client/components/Reader/SettingsPage/SettingsPage.vue
@@ -1,5 +1,5 @@
-
+
Настройки
@@ -537,7 +537,8 @@ export default @Component({
this.settingsChanged();
},
form: function(newValue) {
- this.commit('reader/setSettings', newValue);
+ if (this.inited)
+ this.commit('reader/setSettings', newValue);
},
fontBold: function(newValue) {
this.fontWeight = (newValue ? 'bold' : '');
@@ -588,6 +589,7 @@ class SettingsPage extends Vue {
init() {
this.$refs.window.init();
+ this.inited = true;
}
settingsChanged() {
diff --git a/client/components/Reader/share/bookManager.js b/client/components/Reader/share/bookManager.js
index a4fc8f63..ba12c17f 100644
--- a/client/components/Reader/share/bookManager.js
+++ b/client/components/Reader/share/bookManager.js
@@ -31,6 +31,9 @@ class BookManager {
if (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.loadStored();//no await
@@ -419,6 +422,41 @@ class BookManager {
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) {
if (this.eventListeners.indexOf(listener) < 0)
this.eventListeners.push(listener);
@@ -433,7 +471,7 @@ class BookManager {
emit(eventName, value) {
if (this.eventListeners) {
(async() => {
- await utils.sleep(1);
+ await utils.sleep(1);//неблокирующая рассылка сообщений
for (const listener of this.eventListeners) {
//console.log(eventName);
listener(eventName, value);
diff --git a/client/components/Reader/versionHistory.js b/client/components/Reader/versionHistory.js
index b7cbbd41..e57f569d 100644
--- a/client/components/Reader/versionHistory.js
+++ b/client/components/Reader/versionHistory.js
@@ -6,10 +6,10 @@ export const versionHistory = [
`
- налажена работа https-версии сайта, рекомендуется плавный переход
- - добавлена возможность загрузки и работы читалки в оффлайн-режиме (при отсутствии интернета)
+ - добавлена возможность загрузки и работы https-версии читалки в оффлайн-режиме (при отсутствии интернета)
- упрощение механизма серверной синхронизации с целью повышения надежности и избавления от багов
- окна теперь можно перемещать за заголовок
- - улучшен внешний вид и управление на смартфонах
+ - немного улучшен внешний вид и управление на смартфонах
- добавлен параметр "Компактность" в раздел "Вид"->"Текст" в настройках
`