Ver Fonte

feat: sync positions

Gerald há 8 anos atrás
pai
commit
a8537b1551

+ 3 - 1
src/background/app.js

@@ -111,7 +111,8 @@ const commands = {
     return vmdb.getScriptInfos(ids);
   },
   Move(data) {
-    return vmdb.moveScript(data.id, data.offset);
+    return vmdb.moveScript(data.id, data.offset)
+    .then(() => { sync.sync(); });
   },
   Vacuum: vmdb.vacuum,
   ParseScript(data) {
@@ -191,6 +192,7 @@ const commands = {
     const items = Array.isArray(data) ? data : [data];
     items.forEach(item => { setOption(item.key, item.value); });
   },
+  CheckPosition: vmdb.checkPosition,
 };
 
 vmdb.initialized.then(() => {

+ 30 - 17
src/background/sync/base.js

@@ -1,7 +1,7 @@
 import { debounce, normalizeKeys, request, noop } from 'src/common';
 import getEventEmitter from '../utils/events';
 import { getOption, setOption, hookOptions } from '../utils/options';
-import { getScriptsByIndex, parseScript, removeScript } from '../utils/db';
+import { getScriptsByIndex, parseScript, removeScript, checkPosition } from '../utils/db';
 
 const serviceNames = [];
 const services = {};
@@ -295,30 +295,29 @@ export const BaseService = serviceFactory({
         || Object.keys(remoteMetaInfo).length !== remoteData.length;
       const now = Date.now();
       const remoteItemMap = {};
+      const localMeta = this.config.get('meta', {});
+      const firstSync = !localMeta.timestamp;
+      const outdated = !localMeta.timestamp || remoteMeta.timestamp > localMeta.timestamp;
+      this.log('First sync:', firstSync);
+      this.log('Outdated:', outdated, '(', 'local:', localMeta.timestamp, 'remote:', remoteMeta.timestamp, ')');
+      const getRemote = [];
+      const putRemote = [];
+      const delRemote = [];
+      const delLocal = [];
       remoteMeta.info = remoteData.reduce((info, item) => {
         remoteItemMap[item.uri] = item;
-        info[item.uri] = remoteMetaInfo[item.uri];
-        let itemInfo = info[item.uri];
+        let itemInfo = remoteMetaInfo[item.uri];
         if (!itemInfo) {
           itemInfo = {};
-          info[item.uri] = itemInfo;
           remoteChanged = true;
         }
+        info[item.uri] = itemInfo;
         if (!itemInfo.modified) {
           itemInfo.modified = now;
           remoteChanged = true;
         }
         return info;
       }, {});
-      const localMeta = this.config.get('meta', {});
-      const firstSync = !localMeta.timestamp;
-      const outdated = !localMeta.timestamp || remoteMeta.timestamp > localMeta.timestamp;
-      this.log('First sync:', firstSync);
-      this.log('Outdated:', outdated, '(', 'local:', localMeta.timestamp, 'remote:', remoteMeta.timestamp, ')');
-      const getRemote = [];
-      const putRemote = [];
-      const delRemote = [];
-      const delLocal = [];
       localData.forEach(item => {
         const remoteInfo = remoteMeta.info[item.uri];
         if (remoteInfo) {
@@ -348,17 +347,20 @@ export const BaseService = serviceFactory({
           this.log('Download script:', item.uri);
           return this.get(getFilename(item.uri))
           .then(raw => {
-            const data = {};
+            const data = { more: {} };
             try {
               const obj = JSON.parse(raw);
               if (obj.version === 1) {
                 data.code = obj.code;
-                data.more = obj.more;
+                if (obj.more) data.more = obj.more;
               }
             } catch (e) {
               data.code = raw;
             }
-            data.modified = remoteMeta.info[item.uri].modified;
+            const remoteInfo = remoteMeta.info[item.uri];
+            const { modified, position } = remoteInfo;
+            data.modified = modified;
+            if (position) data.more.position = position;
             if (!getOption('syncScriptStatus') && data.more) {
               delete data.more.enabled;
             }
@@ -377,7 +379,10 @@ export const BaseService = serviceFactory({
               update: item.update,
             },
           });
-          remoteMeta.info[item.uri] = { modified: item.custom.modified };
+          remoteMeta.info[item.uri] = {
+            modified: item.custom.modified,
+            position: item.position,
+          };
           remoteChanged = true;
           return this.put(getFilename(item.uri), data);
         }),
@@ -392,6 +397,14 @@ export const BaseService = serviceFactory({
           return removeScript(item.id);
         }),
       );
+      promiseQueue.push(Promise.all(promiseQueue).then(() => checkPosition()).then(changed => {
+        if (!changed) return;
+        remoteChanged = true;
+        return getScriptsByIndex('position', null, null, item => {
+          const remoteInfo = remoteMeta.info[item.uri];
+          if (remoteInfo) remoteInfo.position = item.position;
+        });
+      }));
       promiseQueue.push(Promise.all(promiseQueue).then(() => {
         const promises = [];
         if (remoteChanged) {

+ 77 - 13
src/background/utils/db.js

@@ -2,16 +2,23 @@ import Promise from 'sync-promise-lite';
 import { i18n, request } from 'src/common';
 import { getNameURI, getScriptInfo, isRemote, parseMeta, newScript } from './script';
 import { testScript, testBlacklist } from './tester';
-import {
-  initialize as initPosition,
-  check as checkPosition,
-  get as getPosition,
-  update as updatePosition,
-} from './position';
 
 let db;
 
-export const initialized = openDatabase().then(() => initPosition(db));
+const position = {
+  value: 0,
+  set(number) {
+    position.value = number;
+  },
+  get() {
+    return position + 1;
+  },
+  update(value) {
+    if (position.value < value) position.value = value;
+  },
+};
+
+export const initialized = openDatabase().then(initPosition);
 
 function openDatabase() {
   return new Promise((resolve, reject) => {
@@ -265,8 +272,8 @@ function saveRequire(uri, code, cTx) {
 export function saveScript(script, cTx) {
   script.enabled = script.enabled ? 1 : 0;
   script.update = script.update ? 1 : 0;
-  if (!script.position) script.position = getPosition();
-  updatePosition(script.position);
+  if (!script.position) script.position = position.get();
+  position.update(script.position);
   const tx = cTx || db.transaction('scripts', 'readwrite');
   const os = tx.objectStore('scripts');
   return new Promise((resolve, reject) => {
@@ -486,7 +493,6 @@ export function parseScript(data) {
       image.src = url;
     }));
   }
-  let needCheckPosition;
   return queryScript(data.id, meta, tx)
   .then(result => {
     let script;
@@ -495,11 +501,10 @@ export function parseScript(data) {
       script = result;
     } else {
       script = newScript();
-      script.position = getPosition();
+      script.position = position.get();
       res.cmd = 'AddScript';
       res.data.message = i18n('msgInstalled');
     }
-    needCheckPosition = data.more && data.more.position !== script.position;
     updateProps(script, data.more);
     updateProps(script.custom, data.custom);
     script.meta = meta;
@@ -514,8 +519,67 @@ export function parseScript(data) {
     return saveScript(script, tx);
   })
   .then(script => {
-    if (needCheckPosition) checkPosition(script.position);
     Object.assign(res.data, getScriptInfo(script));
     return res;
   });
 }
+
+function initPosition() {
+  const os = db.transaction('scripts', 'readwrite').objectStore('scripts');
+  return new Promise(resolve => {
+    os.index('position').openCursor(null, 'prev').onsuccess = e => {
+      const { result } = e.target;
+      if (result) position.set(result.key);
+      resolve();
+    };
+  });
+}
+
+export function checkPosition(start) {
+  const tx = db.transaction('scripts', 'readwrite');
+  const os = tx.objectStore('scripts');
+  let offset = Math.max(1, start || 0);
+  const updates = [];
+  let changed;
+  if (!position.checking) {
+    position.checking = new Promise(resolve => {
+      os.index('position').openCursor(start).onsuccess = e => {
+        const cursor = e.target.result;
+        if (cursor) {
+          const { value } = cursor;
+          if (value.position !== offset) updates.push({ id: value.id, position: offset });
+          position.update(offset);
+          offset += 1;
+          cursor.continue();
+        } else {
+          resolve();
+        }
+      };
+    })
+    .then(() => {
+      changed = updates.length;
+      return update();
+    })
+    .then(() => {
+      browser.runtime.sendMessage({
+        cmd: 'ScriptsUpdated',
+      });
+      position.checking = null;
+    })
+    .then(() => changed);
+  }
+  return position.checking;
+  function update() {
+    const item = updates.shift();
+    if (item) {
+      return new Promise(resolve => {
+        os.get(item.id).onsuccess = e => {
+          const { result } = e.target;
+          result.position = item.position;
+          os.put(result).onsuccess = () => { resolve(); };
+        };
+      })
+      .then(update);
+    }
+  }
+}

+ 0 - 74
src/background/utils/position.js

@@ -1,74 +0,0 @@
-import { debounce } from 'src/common';
-
-let position;
-let start = -1;
-let debouncedCheck;
-
-export function initialize(db) {
-  position = 0;
-  const os = db.transaction('scripts', 'readwrite').objectStore('scripts');
-  debouncedCheck = debounce(initCheck(db), 300);
-  return new Promise(resolve => {
-    os.index('position').openCursor(null, 'prev').onsuccess = e => {
-      const { result } = e.target;
-      if (result) position = result.key;
-      resolve();
-    };
-  });
-}
-
-function initCheck(db) {
-  return function doCheck() {
-    const tx = db.transaction('scripts', 'readwrite');
-    const os = tx.objectStore('scripts');
-    let offset = Math.max(1, start);
-    start = -1;
-    const updates = [];
-    return new Promise(resolve => {
-      os.index('position').openCursor(start).onsuccess = e => {
-        const cursor = e.target.result;
-        if (cursor) {
-          const { value } = cursor;
-          if (value.position !== offset) updates.push({ id: value.id, position: offset });
-          if (position < offset) position = offset;
-          offset += 1;
-          cursor.continue();
-        } else {
-          resolve();
-        }
-      };
-    })
-    .then(updatePosition)
-    .then(() => {
-      browser.runtime.sendMessage({
-        cmd: 'ScriptsUpdated',
-      });
-    });
-    function updatePosition() {
-      const item = updates.shift();
-      if (item) {
-        return new Promise(resolve => {
-          os.get(item.id).onsuccess = e => {
-            const { result } = e.target;
-            result.position = item.position;
-            os.put(result).onsuccess = () => { resolve(); };
-          };
-        })
-        .then(updatePosition);
-      }
-    }
-  };
-}
-
-export function check(startOffset = 0) {
-  if (start < 0 || start > startOffset) start = startOffset;
-  if (debouncedCheck) debouncedCheck();
-}
-
-export function get() {
-  return position + 1;
-}
-
-export function update(pos) {
-  if (position < pos) position = pos;
-}

+ 4 - 1
src/options/views/tab-settings/vm-import.vue

@@ -140,6 +140,9 @@ function importData(file) {
     return Promise.all(entries.map(entry => getVMFile(entry, vm)));
   })
   .then(res => res.filter(Boolean).length)
-  .then(count => { showMessage({ text: i18n('msgImported', [count]) }); });
+  .then(count => {
+    showMessage({ text: i18n('msgImported', [count]) });
+    sendMessage({ cmd: 'CheckPosition' });
+  });
 }
 </script>