Gerald 8 年之前
父节点
当前提交
a2e2ff0e6b
共有 4 个文件被更改,包括 49 次插入45 次删除
  1. 34 30
      src/background/sync/base.js
  2. 6 6
      src/background/sync/dropbox.js
  3. 8 8
      src/background/sync/onedrive.js
  4. 1 1
      src/common/index.js

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

@@ -1,4 +1,4 @@
-import { debounce, normalizeKeys, noop, request } from 'src/common';
+import { debounce, normalizeKeys, request, noop } from 'src/common';
 import getEventEmitter from '../utils/events';
 import getEventEmitter from '../utils/events';
 import { getOption, setOption, hookOptions } from '../utils/options';
 import { getOption, setOption, hookOptions } from '../utils/options';
 import { getScriptsByIndex, parseScript, saveScript, removeScript } from '../utils/db';
 import { getScriptsByIndex, parseScript, saveScript, removeScript } from '../utils/db';
@@ -108,25 +108,32 @@ export function getStates() {
 }
 }
 
 
 function serviceFactory(base) {
 function serviceFactory(base) {
-  const initService = (...args) => {
-    const service = Object.create(base);
-    service.initialize(...args);
-    return service;
+  const Service = function constructor(...args) {
+    if (!(this instanceof Service)) return new Service(...args);
+    this.initialize(...args);
   };
   };
-  initService.extend = options => serviceFactory(Object.assign(Object.create(base), options));
-  return initService;
+  Service.prototype = base;
+  Service.extend = extendService;
+  return Service;
 }
 }
+function extendService(options) {
+  return serviceFactory(Object.assign(Object.create(this.prototype), options));
+}
+
+const onStateChange = debounce(() => {
+  browser.runtime.sendMessage({
+    cmd: 'UpdateSync',
+    data: getStates(),
+  });
+});
+
 export const BaseService = serviceFactory({
 export const BaseService = serviceFactory({
   name: 'base',
   name: 'base',
   displayName: 'BaseService',
   displayName: 'BaseService',
   delayTime: 1000,
   delayTime: 1000,
   urlPrefix: '',
   urlPrefix: '',
   metaFile: 'Violentmonkey',
   metaFile: 'Violentmonkey',
-  delay(time) {
-    return new Promise(resolve => { setTimeout(resolve, time); });
-  },
   initialize(name) {
   initialize(name) {
-    this.onStateChange = debounce(this.onStateChange.bind(this));
     if (name) this.name = name;
     if (name) this.name = name;
     this.progress = {
     this.progress = {
       finished: 0,
       finished: 0,
@@ -140,13 +147,13 @@ export const BaseService = serviceFactory({
       'authorized',
       'authorized',
       'unauthorized',
       'unauthorized',
       'error',
       'error',
-    ], null, this.onStateChange);
+    ], null, onStateChange);
     this.syncState = serviceState([
     this.syncState = serviceState([
       'idle',
       'idle',
       'ready',
       'ready',
       'syncing',
       'syncing',
       'error',
       'error',
-    ], null, this.onStateChange);
+    ], null, onStateChange);
     // this.initToken();
     // this.initToken();
     this.lastFetch = Promise.resolve();
     this.lastFetch = Promise.resolve();
     this.startSync = this.syncFactory();
     this.startSync = this.syncFactory();
@@ -156,12 +163,6 @@ export const BaseService = serviceFactory({
       this[key] = (...args) => { events[key](...args); };
       this[key] = (...args) => { events[key](...args); };
     });
     });
   },
   },
-  onStateChange() {
-    browser.runtime.sendMessage({
-      cmd: 'UpdateSync',
-      data: getStates(),
-    });
-  },
   log(...args) {
   log(...args) {
     console.log(...args);  // eslint-disable-line no-console
     console.log(...args);  // eslint-disable-line no-console
   },
   },
@@ -232,7 +233,7 @@ export const BaseService = serviceFactory({
     this.headers.Authorization = token ? `Bearer ${token}` : null;
     this.headers.Authorization = token ? `Bearer ${token}` : null;
     return !!token;
     return !!token;
   },
   },
-  request(options) {
+  loadData(options) {
     const { progress } = this;
     const { progress } = this;
     let lastFetch;
     let lastFetch;
     if (options.delay == null) {
     if (options.delay == null) {
@@ -253,23 +254,26 @@ export const BaseService = serviceFactory({
     }
     }
     this.lastFetch = lastFetch;
     this.lastFetch = lastFetch;
     progress.total += 1;
     progress.total += 1;
-    this.onStateChange();
+    onStateChange();
     return lastFetch.then(() => {
     return lastFetch.then(() => {
       let { prefix } = options;
       let { prefix } = options;
       if (prefix == null) prefix = this.urlPrefix;
       if (prefix == null) prefix = this.urlPrefix;
       const headers = Object.assign({}, this.headers, options.headers);
       const headers = Object.assign({}, this.headers, options.headers);
-      return request(prefix + options.url, {
+      let { url } = options;
+      if (url.startsWith('/')) url = prefix + url;
+      return request(url, {
         headers,
         headers,
         method: options.method,
         method: options.method,
         body: options.body,
         body: options.body,
-      })
-      .then(data => ({ data }), error => ({ error }))
-      .then(({ data, error }) => {
-        progress.finished += 1;
-        this.onStateChange();
-        if (error) return Promise.reject(error);
-        return data;
+        responseType: options.responseType,
       });
       });
+    })
+    .then(({ data }) => ({ data }), error => ({ error }))
+    .then(({ data, error }) => {
+      progress.finished += 1;
+      onStateChange();
+      if (error) return Promise.reject(error);
+      return data;
     });
     });
   },
   },
   sync() {
   sync() {
@@ -399,7 +403,7 @@ export const BaseService = serviceFactory({
         return Promise.all(promises);
         return Promise.all(promises);
       }));
       }));
       // ignore errors to ensure all promises are fulfilled
       // ignore errors to ensure all promises are fulfilled
-      return Promise.all(promiseQueue.map(promise => promise.catch(err => err || true)))
+      return Promise.all(promiseQueue.map(promise => promise.then(noop, err => err || true)))
       .then(errors => errors.filter(Boolean))
       .then(errors => errors.filter(Boolean))
       .then(errors => { if (errors.length) throw errors; });
       .then(errors => { if (errors.length) throw errors; });
     })
     })

+ 6 - 6
src/background/sync/dropbox.js

@@ -10,7 +10,7 @@ const Dropbox = BaseService.extend({
   name: 'dropbox',
   name: 'dropbox',
   displayName: 'Dropbox',
   displayName: 'Dropbox',
   user() {
   user() {
-    return this.request({
+    return this.loadData({
       method: 'POST',
       method: 'POST',
       url: 'https://api.dropboxapi.com/2/users/get_current_account',
       url: 'https://api.dropboxapi.com/2/users/get_current_account',
     })
     })
@@ -27,14 +27,14 @@ const Dropbox = BaseService.extend({
     });
     });
   },
   },
   getMeta() {
   getMeta() {
-    return BaseService.getMeta.call(this)
+    return BaseService.prototype.getMeta.call(this)
     .catch(res => {
     .catch(res => {
       if (res.status === 409) return {};
       if (res.status === 409) return {};
       throw res;
       throw res;
     });
     });
   },
   },
   list() {
   list() {
-    return this.request({
+    return this.loadData({
       method: 'POST',
       method: 'POST',
       url: 'https://api.dropboxapi.com/2/files/list_folder',
       url: 'https://api.dropboxapi.com/2/files/list_folder',
       body: {
       body: {
@@ -47,7 +47,7 @@ const Dropbox = BaseService.extend({
     ));
     ));
   },
   },
   get(path) {
   get(path) {
-    return this.request({
+    return this.loadData({
       method: 'POST',
       method: 'POST',
       url: 'https://content.dropboxapi.com/2/files/download',
       url: 'https://content.dropboxapi.com/2/files/download',
       headers: {
       headers: {
@@ -58,7 +58,7 @@ const Dropbox = BaseService.extend({
     });
     });
   },
   },
   put(path, data) {
   put(path, data) {
-    return this.request({
+    return this.loadData({
       method: 'POST',
       method: 'POST',
       url: 'https://content.dropboxapi.com/2/files/upload',
       url: 'https://content.dropboxapi.com/2/files/upload',
       headers: {
       headers: {
@@ -74,7 +74,7 @@ const Dropbox = BaseService.extend({
     .then(normalize);
     .then(normalize);
   },
   },
   remove(path) {
   remove(path) {
-    return this.request({
+    return this.loadData({
       method: 'POST',
       method: 'POST',
       url: 'https://api.dropboxapi.com/2/files/delete',
       url: 'https://api.dropboxapi.com/2/files/delete',
       body: {
       body: {

+ 8 - 8
src/background/sync/onedrive.js

@@ -24,7 +24,7 @@ const OneDrive = BaseService.extend({
     .then(() => this.prepare());
     .then(() => this.prepare());
   },
   },
   user() {
   user() {
-    const requestUser = () => this.request({
+    const requestUser = () => this.loadData({
       url: '/drive',
       url: '/drive',
       responseType: 'json',
       responseType: 'json',
     });
     });
@@ -48,7 +48,7 @@ const OneDrive = BaseService.extend({
     });
     });
   },
   },
   getMeta() {
   getMeta() {
-    const getMeta = () => BaseService.getMeta.call(this);
+    const getMeta = () => BaseService.prototype.getMeta.call(this);
     return getMeta()
     return getMeta()
     .catch(res => {
     .catch(res => {
       if (res.status === 404) {
       if (res.status === 404) {
@@ -62,24 +62,24 @@ const OneDrive = BaseService.extend({
     });
     });
   },
   },
   list() {
   list() {
-    return this.request({
+    return this.loadData({
       url: '/drive/special/approot/children',
       url: '/drive/special/approot/children',
       responseType: 'json',
       responseType: 'json',
     })
     })
     .then(data => data.value.filter(item => item.file && isScriptFile(item.name)).map(normalize));
     .then(data => data.value.filter(item => item.file && isScriptFile(item.name)).map(normalize));
   },
   },
   get(path) {
   get(path) {
-    return this.request({
+    return this.loadData({
       url: `/drive/special/approot:/${encodeURIComponent(path)}`,
       url: `/drive/special/approot:/${encodeURIComponent(path)}`,
       responseType: 'json',
       responseType: 'json',
     })
     })
-    .then(data => this.request({
+    .then(data => this.loadData({
       url: data['@content.downloadUrl'],
       url: data['@content.downloadUrl'],
       delay: 0,
       delay: 0,
     }));
     }));
   },
   },
   put(path, data) {
   put(path, data) {
-    return this.request({
+    return this.loadData({
       method: 'PUT',
       method: 'PUT',
       url: `/drive/special/approot:/${encodeURIComponent(path)}:/content`,
       url: `/drive/special/approot:/${encodeURIComponent(path)}:/content`,
       headers: {
       headers: {
@@ -92,7 +92,7 @@ const OneDrive = BaseService.extend({
   },
   },
   remove(path) {
   remove(path) {
     // return 204
     // return 204
-    return this.request({
+    return this.loadData({
       method: 'DELETE',
       method: 'DELETE',
       url: `/drive/special/approot:/${encodeURIComponent(path)}`,
       url: `/drive/special/approot:/${encodeURIComponent(path)}`,
     })
     })
@@ -128,7 +128,7 @@ const OneDrive = BaseService.extend({
     return this.prepare();
     return this.prepare();
   },
   },
   authorized(params) {
   authorized(params) {
-    return this.request({
+    return this.loadData({
       method: 'POST',
       method: 'POST',
       url: 'https://login.live.com/oauth20_token.srf',
       url: 'https://login.live.com/oauth20_token.srf',
       prefix: '',
       prefix: '',

+ 1 - 1
src/common/index.js

@@ -118,7 +118,7 @@ export function request(url, options = {}) {
     const xhr = new XMLHttpRequest();
     const xhr = new XMLHttpRequest();
     const { responseType } = options;
     const { responseType } = options;
     xhr.open(options.method || 'GET', url, true);
     xhr.open(options.method || 'GET', url, true);
-    if (responseType) xhr.responseType = responseType;
+    if (['blob'].includes(responseType)) xhr.responseType = responseType;
     const headers = Object.assign({}, options.headers);
     const headers = Object.assign({}, options.headers);
     let { body } = options;
     let { body } = options;
     if (body && typeof body === 'object') {
     if (body && typeof body === 'object') {