瀏覽代碼

Работа над ServerStorage - профили

Book Pauk 6 年之前
父節點
當前提交
2ff94c1458
共有 3 個文件被更改,包括 196 次插入47 次删除
  1. 75 3
      client/components/Reader/ServerStorage/ServerStorage.vue
  2. 65 0
      client/share/utils.js
  3. 56 44
      client/store/modules/reader.js

+ 75 - 3
client/components/Reader/ServerStorage/ServerStorage.vue

@@ -13,7 +13,14 @@ 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: {
+        profiles: function() {
+            this.saveProfiles();
+        },
+    },
 })
 })
 class ServerStorage extends Vue {
 class ServerStorage extends Vue {
     created() {
     created() {
@@ -27,9 +34,7 @@ class ServerStorage extends Vue {
         }
         }
         this.hashedStorageKey = utils.toBase58(await cryptoUtils.sha256(this.serverStorageKey));
         this.hashedStorageKey = utils.toBase58(await cryptoUtils.sha256(this.serverStorageKey));
         
         
-        //console.log(await this.storageSet({'id1': {rev: 1, data: {test: 123}}}));
-        //console.log(await this.storageGet({'id1': {}}));
-        //console.log(await this.storageCheck({'id1': {rev: 1, data: {test: 123}}}));
+        await this.loadProfiles();
     }
     }
 
 
     get settings() {
     get settings() {
@@ -40,6 +45,73 @@ class ServerStorage extends Vue {
         return this.$store.state.reader.serverStorageKey;
         return this.$store.state.reader.serverStorageKey;
     }
     }
 
 
+    get profiles() {
+        return this.$store.state.reader.profiles;
+    }
+
+    get profilesRev() {
+        return this.$store.state.reader.profilesRev;
+    }
+
+    notifySuccessIfNeeded(rev1, rev2) {
+        if (rev1 != rev2)
+            this.$notify.success({message: 'Данные синхронизированы с сервером'});
+    }
+
+    warning(message) {
+        this.$notify.warning({message});
+    }
+
+    error(message) {
+        this.$notify.error({message});
+    }
+
+    async loadProfiles() {
+        let prof = await this.storageGet({'profiles': {}});
+
+        if (prof.state == 'success') {
+            const oldRev = this.profilesRev;
+            prof = prof.items.profiles;
+            this.commit('reader/setProfiles', prof.data);
+            this.commit('reader/setProfilesRev', prof.rev);
+
+            this.oldProfiles = this.profiles;
+            this.notifySuccessIfNeeded(oldRev, prof.rev);
+        } else {
+            this.warning(`Неверный ответ сервера: ${prof.state}`);
+        }
+    }
+
+    async saveProfiles() {
+        if (!this.savingProfiles) {
+            this.savingProfiles = true;
+
+            const diff = utils.getObjDiff(this.oldProfiles, this.profiles);
+            let result = {state: ''};
+            let tries = 0;
+            while (result.state != 'success' && tries < maxSetTries) {
+                result = await this.storageSet({'profiles': {rev: this.profilesRev + 1, data: this.profiles}});
+
+                if (result.state == 'reject') {
+                    await this.loadProfiles();
+                    const newProfiles = utils.applyObjDiff(this.profiles, diff);
+                    this.commit('reader/setProfiles', newProfiles);
+                    this.commit('reader/setProfilesRev', result.items.profiles.rev);
+                }
+
+                tries++;
+            }
+
+            this.commit('reader/setProfilesRev', this.profilesRev + 1);
+
+            if (tries >= maxSetTries) {
+                throw new Error('Не удалось отправить данные на сервер');
+            }
+
+            this.savingProfiles = false;
+        }
+    }
+
     generateNewServerStorageKey() {
     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);

+ 65 - 0
client/share/utils.js

@@ -1,3 +1,4 @@
+import _ from 'lodash';
 import baseX from 'base-x';
 import baseX from 'base-x';
 import PAKO from 'pako';
 import PAKO from 'pako';
 import {Buffer} from 'safe-buffer';
 import {Buffer} from 'safe-buffer';
@@ -92,3 +93,67 @@ export function toBase64(data) {
 export function fromBase64(data) {
 export function fromBase64(data) {
     return bs64.decode(data);
     return bs64.decode(data);
 }
 }
+
+export function getObjDiff(oldObj, newObj) {
+    const result = {__isDiff: true, change: {}, add: {}, del: []};
+
+    for (const key of Object.keys(oldObj)) {
+        if (newObj.hasOwnProperty(key)) {
+            if (!_.isEqual(oldObj[key], newObj[key])) {
+                if (_.isObject(oldObj[key]) && _.isObject(newObj[key])) {
+                    result.change[key] = getObjDiff(oldObj[key], newObj[key]);
+                } else {
+                    result.change[key] = _.cloneDeep(newObj[key]);
+                }
+            }
+        } else {
+            result.del.push(key);
+        }
+    }
+
+    for (const key of Object.keys(newObj)) {
+        if (!oldObj.hasOwnProperty(key)) {
+            result.add[key] = _.cloneDeep(newObj[key]);
+        }
+    }
+
+    return result;
+}
+
+export function isEmptyObjDiff(diff) {
+    return (!_.isObject(diff) || !diff.__isDiff ||
+        (!Object.keys(diff.change).length &&
+            !Object.keys(diff.add).length &&
+            !diff.del.length
+        )
+    );
+}
+
+export function applyObjDiff(obj, diff, isAddChanged) {
+    const result = _.cloneDeep(obj);
+    if (!diff.__isDiff)
+        return result;
+
+    const change = diff.change;
+    for (const key of Object.keys(change)) {
+        if (result.hasOwnProperty(key)) {
+            if (_.isObject(change[key])) {
+                result[key] = applyObjDiff(result[key], change[key], isAddChanged);
+            } else {
+                result[key] = _.cloneDeep(change[key]);
+            }
+        } else if (isAddChanged) {
+            result[key] = _.cloneDeep(change[key]);
+        }
+    }
+
+    for (const key of Object.keys(diff.add)) {
+        result[key] = _.cloneDeep(diff.add[key]);
+    }
+
+    for (const key of diff.del) {
+        delete result[key];
+    }
+
+    return result;
+}

+ 56 - 44
client/store/modules/reader.js

@@ -123,50 +123,50 @@ const webFonts = [
 ];
 ];
 
 
 const settingDefaults = {
 const settingDefaults = {
-        textColor: '#000000',
-        backgroundColor: '#EBE2C9',
-        wallpaper: '',
-        fontStyle: '',// 'italic'
-        fontWeight: '',// 'bold'
-        fontSize: 20,// px
-        fontName: 'ReaderDefault',
-        webFontName: '',
-        fontVertShift: 0,
-        textVertShift: -20,
-
-        lineInterval: 3,// px, межстрочный интервал
-        textAlignJustify: true,// выравнивание по ширине
-        p: 25,// px, отступ параграфа
-        indentLR: 15,// px, отступ всего текста слева и справа
-        indentTB: 0,// px, отступ всего текста сверху и снизу
-        wordWrap: true,//перенос по слогам
-        keepLastToFirst: true,// перенос последней строки в первую при листании
-
-        showStatusBar: true,
-        statusBarTop: false,// top, bottom
-        statusBarHeight: 19,// px
-        statusBarColorAlpha: 0.4,
-
-        scrollingDelay: 3000,// замедление, ms
-        scrollingType: 'ease-in-out', //linear, ease, ease-in, ease-out, ease-in-out
-
-        pageChangeAnimation: 'blink',// '' - нет, downShift, rightShift, thaw - протаивание, blink - мерцание
-        pageChangeAnimationSpeed: 80, //0-100%
-
-        allowUrlParamBookPos: false,
-        lazyParseEnabled: false,
-        copyFullText: false,
-        showClickMapPage: true,
-        clickControl: true,
-        cutEmptyParagraphs: false,
-        addEmptyParagraphs: 0,
-        blinkCachedLoad: true,
-        showImages: true,
-        showInlineImagesInCenter: true,
-        imageHeightLines: 100,
-        imageFitWidth: true,
-
-        fontShifts: {},
+    textColor: '#000000',
+    backgroundColor: '#EBE2C9',
+    wallpaper: '',
+    fontStyle: '',// 'italic'
+    fontWeight: '',// 'bold'
+    fontSize: 20,// px
+    fontName: 'ReaderDefault',
+    webFontName: '',
+    fontVertShift: 0,
+    textVertShift: -20,
+
+    lineInterval: 3,// px, межстрочный интервал
+    textAlignJustify: true,// выравнивание по ширине
+    p: 25,// px, отступ параграфа
+    indentLR: 15,// px, отступ всего текста слева и справа
+    indentTB: 0,// px, отступ всего текста сверху и снизу
+    wordWrap: true,//перенос по слогам
+    keepLastToFirst: true,// перенос последней строки в первую при листании
+
+    showStatusBar: true,
+    statusBarTop: false,// top, bottom
+    statusBarHeight: 19,// px
+    statusBarColorAlpha: 0.4,
+
+    scrollingDelay: 3000,// замедление, ms
+    scrollingType: 'ease-in-out', //linear, ease, ease-in, ease-out, ease-in-out
+
+    pageChangeAnimation: 'blink',// '' - нет, downShift, rightShift, thaw - протаивание, blink - мерцание
+    pageChangeAnimationSpeed: 80, //0-100%
+
+    allowUrlParamBookPos: false,
+    lazyParseEnabled: false,
+    copyFullText: false,
+    showClickMapPage: true,
+    clickControl: true,
+    cutEmptyParagraphs: false,
+    addEmptyParagraphs: 0,
+    blinkCachedLoad: true,
+    showImages: true,
+    showInlineImagesInCenter: true,
+    imageHeightLines: 100,
+    imageFitWidth: true,
+
+    fontShifts: {},
 };
 };
 
 
 for (const font of fonts)
 for (const font of fonts)
@@ -178,6 +178,9 @@ for (const font of webFonts)
 const state = {
 const state = {
     toolBarActive: true,
     toolBarActive: true,
     serverStorageKey: '',
     serverStorageKey: '',
+    profiles: [],
+    profilesRev: 0,
+    currentProfile: '',
     settings: Object.assign({}, settingDefaults),
     settings: Object.assign({}, settingDefaults),
 };
 };
 
 
@@ -195,6 +198,15 @@ const mutations = {
     setServerStorageKey(state, value) {
     setServerStorageKey(state, value) {
         state.serverStorageKey = value;
         state.serverStorageKey = value;
     },
     },
+    setProfiles(state, value) {
+        state.profiles = value;
+    },
+    setProfilesRev(state, value) {
+        state.profilesRev = value;
+    },
+    setCurrentProfile(state, value) {
+        state.currentProfile = value;
+    },
     setSettings(state, value) {
     setSettings(state, value) {
         state.settings = Object.assign({}, state.settings, value);
         state.settings = Object.assign({}, state.settings, value);
     }
     }