Add: sync.js
This commit is contained in:
parent
1fa223c46d
commit
edb531026c
|
@ -1,6 +1,6 @@
|
|||
/* eslint no-eq-null: 0, eqeqeq: [2, "smart"] */
|
||||
/* global createCache db calcStyleDigest db tryRegExp styleCodeEmpty
|
||||
getStyleWithNoCode msg sync uuidv4 */
|
||||
getStyleWithNoCode msg sync uuid */
|
||||
/* exported styleManager */
|
||||
'use strict';
|
||||
|
||||
|
@ -63,11 +63,16 @@ const styleManager = (() => {
|
|||
|
||||
handleLivePreviewConnections();
|
||||
|
||||
return ensurePrepared({
|
||||
return Object.assign({
|
||||
compareRevision
|
||||
}, ensurePrepared({
|
||||
get,
|
||||
getByUUID,
|
||||
getSectionsByUrl,
|
||||
putByUUID,
|
||||
installStyle,
|
||||
deleteStyle,
|
||||
deleteByUUID,
|
||||
editSave,
|
||||
findStyle,
|
||||
importStyle,
|
||||
|
@ -80,7 +85,7 @@ const styleManager = (() => {
|
|||
removeExclusion,
|
||||
addInclusion,
|
||||
removeInclusion
|
||||
});
|
||||
}));
|
||||
|
||||
function handleLivePreviewConnections() {
|
||||
chrome.runtime.onConnect.addListener(port => {
|
||||
|
@ -121,11 +126,48 @@ const styleManager = (() => {
|
|||
return noCode ? getStyleWithNoCode(data) : data;
|
||||
}
|
||||
|
||||
function getByUUID(uuid) {
|
||||
const id = uuidIndex.get(uuid);
|
||||
if (id) {
|
||||
return get(id);
|
||||
}
|
||||
}
|
||||
|
||||
function getAllStyles(noCode = false) {
|
||||
const datas = [...styles.values()].map(s => s.data);
|
||||
return noCode ? datas.map(getStyleWithNoCode) : datas;
|
||||
}
|
||||
|
||||
function compareRevision(rev1, rev2) {
|
||||
return rev1 - rev2;
|
||||
}
|
||||
|
||||
function putByUUID(doc) {
|
||||
const id = uuidIndex.get(doc._id);
|
||||
if (id) {
|
||||
doc.id = id;
|
||||
} else {
|
||||
delete doc.id;
|
||||
}
|
||||
const oldDoc = id && styles.has(id) && styles.get(id).data;
|
||||
let diff = -1;
|
||||
if (oldDoc) {
|
||||
diff = compareRevision(oldDoc._rev, doc._rev);
|
||||
if (diff > 0) {
|
||||
sync.put(oldDoc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (diff < 0) {
|
||||
return db.exec('put', doc)
|
||||
.then(event => {
|
||||
doc.id = event.target.result;
|
||||
uuidIndex.set(doc._id, doc.id);
|
||||
return handleSave(doc, 'sync');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleStyle(id, enabled) {
|
||||
const style = styles.get(id);
|
||||
const data = Object.assign({}, style.data, {enabled});
|
||||
|
@ -247,12 +289,14 @@ const styleManager = (() => {
|
|||
return removeIncludeExclude(id, rule, 'inclusions');
|
||||
}
|
||||
|
||||
function deleteStyle(id) {
|
||||
function deleteStyle(id, reason) {
|
||||
const style = styles.get(id);
|
||||
beforeSave(style);
|
||||
const rev = Date.now();
|
||||
return db.exec('delete', id)
|
||||
.then(() => {
|
||||
sync.delete(style._id, style._rev);
|
||||
if (reason !== 'sync') {
|
||||
sync.delete(style.data._id, rev);
|
||||
}
|
||||
for (const url of style.appliesTo) {
|
||||
const cache = cachedStyleForUrl.get(url);
|
||||
if (cache) {
|
||||
|
@ -260,6 +304,7 @@ const styleManager = (() => {
|
|||
}
|
||||
}
|
||||
styles.delete(id);
|
||||
uuidIndex.delete(style.data._id);
|
||||
return msg.broadcast({
|
||||
method: 'styleDeleted',
|
||||
style: {id}
|
||||
|
@ -268,6 +313,14 @@ const styleManager = (() => {
|
|||
.then(() => id);
|
||||
}
|
||||
|
||||
function deleteByUUID(_id, rev) {
|
||||
const id = uuidIndex.get(_id);
|
||||
const oldDoc = id && styles.has(id) && styles.get(id).data;
|
||||
if (oldDoc && compareRevision(oldDoc._rev, rev) <= 0) {
|
||||
return deleteStyle(id, 'sync');
|
||||
}
|
||||
}
|
||||
|
||||
function ensurePrepared(methods) {
|
||||
const prepared = {};
|
||||
for (const [name, fn] of Object.entries(methods)) {
|
||||
|
@ -330,7 +383,7 @@ const styleManager = (() => {
|
|||
delete style.id;
|
||||
}
|
||||
if (!style._id) {
|
||||
style._id = uuidv4();
|
||||
style._id = uuid();
|
||||
}
|
||||
style._rev = Date.now();
|
||||
fixUsoMd5Issue(style);
|
||||
|
@ -469,7 +522,7 @@ const styleManager = (() => {
|
|||
function addMissingProperties(style) {
|
||||
let touched = false;
|
||||
if (!style._id) {
|
||||
style._id = uuidv4();
|
||||
style._id = uuid();
|
||||
touched = true;
|
||||
}
|
||||
if (!style._rev) {
|
||||
|
|
97
background/sync.js
Normal file
97
background/sync.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
/* global dbToCloud styleManager chromeLocal prefs tokenManager loadScript */
|
||||
/* exported sync */
|
||||
|
||||
'use strict';
|
||||
|
||||
const sync = (() => {
|
||||
let currentDrive;
|
||||
const ctrl = dbToCloud.dbToCloud({
|
||||
onGet(id) {
|
||||
return styleManager.getByUUID(id);
|
||||
},
|
||||
onPut(doc) {
|
||||
return styleManager.putByUUID(doc);
|
||||
},
|
||||
onDelete(id, rev) {
|
||||
return styleManager.deleteByUUID(id, rev);
|
||||
},
|
||||
onFirstSync() {
|
||||
return styleManager.getAllStyles()
|
||||
.then(styles => {
|
||||
styles.forEach(i => ctrl.put(i._id, i._rev));
|
||||
});
|
||||
},
|
||||
compareRevision(a, b) {
|
||||
return styleManager.compareRevision(a, b);
|
||||
},
|
||||
getState(drive) {
|
||||
const key = `sync/state/${drive.name}`;
|
||||
return chromeLocal.get(key)
|
||||
.then(obj => obj[key]);
|
||||
},
|
||||
setState(drive, state) {
|
||||
const key = `sync/state/${drive.name}`;
|
||||
return chromeLocal.set({
|
||||
[key]: state
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
prefs.initializing
|
||||
.then(() => {
|
||||
const provider = prefs.get('sync.enabled');
|
||||
if (provider === 'none') {
|
||||
return;
|
||||
}
|
||||
return start(provider);
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
chrome.alarms.onAlarm.addListener(info => {
|
||||
if (info.name === 'syncNow') {
|
||||
ctrl.syncNow().catch(console.error);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
start,
|
||||
stop,
|
||||
put: ctrl.put,
|
||||
delete: ctrl.delete
|
||||
};
|
||||
|
||||
function start(name) {
|
||||
return (currentDrive ? stop() : Promise.resolve())
|
||||
.then(() => {
|
||||
if (currentDrive) {
|
||||
return chromeLocal.remove(`sync/state/${currentDrive.name}`);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
currentDrive = getDrive(name);
|
||||
ctrl.use(currentDrive);
|
||||
return ctrl.start();
|
||||
})
|
||||
.then(() => {
|
||||
chrome.alarms.create('syncNow', {periodInMinutes: 30});
|
||||
});
|
||||
}
|
||||
|
||||
function getDrive(name) {
|
||||
if (name === 'dropbox') {
|
||||
return dbToCloud.drive.dropbox({
|
||||
getAccessToken: () => tokenManager.getToken(name),
|
||||
getDropbox: () => loadScript('/vendor/dropbox/dropbox-sdk.js')
|
||||
.then(() => Dropbox.Dropbox), // eslint-disable-line no-undef
|
||||
clientId: 'zg52vphuapvpng9'
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error(`unknown cloud name: ${name}`);
|
||||
}
|
||||
|
||||
function stop() {
|
||||
chrome.alarms.clear('syncNow');
|
||||
return ctrl.stop();
|
||||
}
|
||||
})();
|
0
background/token-manager.js
Normal file
0
background/token-manager.js
Normal file
|
@ -88,6 +88,8 @@ const prefs = (() => {
|
|||
'hotkey.openManage': '',
|
||||
'hotkey.styleDisableAll': '',
|
||||
|
||||
'sync.enabled': 'none',
|
||||
|
||||
'iconset': 0, // 0 = dark-themed icon
|
||||
// 1 = light-themed icon
|
||||
|
||||
|
|
|
@ -35,6 +35,11 @@
|
|||
"js/script-loader.js",
|
||||
"js/usercss.js",
|
||||
"js/cache.js",
|
||||
"vendor/semver-bundle/semver.js",
|
||||
"vendor/db-to-cloud/db-to-cloud.min.js",
|
||||
"vendor/uuid/uuid.min.js",
|
||||
"background/token-manager.js",
|
||||
"background/sync.js",
|
||||
"background/content-scripts.js",
|
||||
"background/db.js",
|
||||
"background/style-manager.js",
|
||||
|
@ -45,8 +50,7 @@
|
|||
"background/style-via-api.js",
|
||||
"background/search-db.js",
|
||||
"background/update.js",
|
||||
"background/openusercss-api.js",
|
||||
"vendor/semver-bundle/semver.js"
|
||||
"background/openusercss-api.js"
|
||||
]
|
||||
},
|
||||
"commands": {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"devDependencies": {
|
||||
"archiver": "^3.1.1",
|
||||
"codemirror": "^5.48.4",
|
||||
"db-to-cloud": "^0.1.0",
|
||||
"dropbox": "^4.0.30",
|
||||
"endent": "^1.3.0",
|
||||
"eslint": "^6.3.0",
|
||||
|
|
|
@ -40,6 +40,9 @@ const files = {
|
|||
'vendor/inflate.js → inflate.js',
|
||||
'vendor/z-worker.js → z-worker.js',
|
||||
'vendor/zip.js → zip.js'
|
||||
],
|
||||
'db-to-cloud': [
|
||||
'dist/db-to-cloud.min.js → db-to-cloud.min.js'
|
||||
]
|
||||
};
|
||||
|
||||
|
|
20
vendor/db-to-cloud/LICENSE
vendored
Normal file
20
vendor/db-to-cloud/LICENSE
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2016 Dropbox Inc., http://www.dropbox.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
9
vendor/db-to-cloud/README.md
vendored
Normal file
9
vendor/db-to-cloud/README.md
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
## db-to-cloud v0.1.0
|
||||
|
||||
Installed via npm - source code:
|
||||
|
||||
https://github.com/eight04/db-to-cloud/tree/v0.1.0
|
||||
|
||||
Bundled code:
|
||||
|
||||
https://unpkg.com/db-to-cloud@0.1.0/dist/db-to-cloud.min.js
|
1
vendor/db-to-cloud/db-to-cloud.min.js
vendored
Normal file
1
vendor/db-to-cloud/db-to-cloud.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
21
vendor/uuid/LICENSE
vendored
Normal file
21
vendor/uuid/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2010-2016 Robert Kieffer and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
9
vendor/uuid/README.md
vendored
Normal file
9
vendor/uuid/README.md
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
## uuid v3.3.3
|
||||
|
||||
Installed via npm - source code:
|
||||
|
||||
https://github.com/kelektiv/node-uuid/tree/v3.3.3
|
||||
|
||||
Bundled code:
|
||||
|
||||
https://bundle.run/uuid@3.3.3/v4.js
|
1
vendor/uuid/uuid.min.js
vendored
Normal file
1
vendor/uuid/uuid.min.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(n){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=n();else if("function"==typeof define&&define.amd)define([],n);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).uuid=n()}}(function(){return function(){return function n(e,r,t){function o(f,u){if(!r[f]){if(!e[f]){var d="function"==typeof require&&require;if(!u&&d)return d(f,!0);if(i)return i(f,!0);var a=new Error("Cannot find module '"+f+"'");throw a.code="MODULE_NOT_FOUND",a}var p=r[f]={exports:{}};e[f][0].call(p.exports,function(n){return o(e[f][1][n]||n)},p,p.exports,n,e,r,t)}return r[f].exports}for(var i="function"==typeof require&&require,f=0;f<t.length;f++)o(t[f]);return o}}()({1:[function(n,e,r){for(var t=[],o=0;o<256;++o)t[o]=(o+256).toString(16).substr(1);e.exports=function(n,e){var r=e||0,o=t;return[o[n[r++]],o[n[r++]],o[n[r++]],o[n[r++]],"-",o[n[r++]],o[n[r++]],"-",o[n[r++]],o[n[r++]],"-",o[n[r++]],o[n[r++]],"-",o[n[r++]],o[n[r++]],o[n[r++]],o[n[r++]],o[n[r++]],o[n[r++]]].join("")}},{}],2:[function(n,e,r){var t="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof window.msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto);if(t){var o=new Uint8Array(16);e.exports=function(){return t(o),o}}else{var i=new Array(16);e.exports=function(){for(var n,e=0;e<16;e++)0==(3&e)&&(n=4294967296*Math.random()),i[e]=n>>>((3&e)<<3)&255;return i}}},{}],3:[function(n,e,r){var t=n("./lib/rng"),o=n("./lib/bytesToUuid");e.exports=function(n,e,r){var i=e&&r||0;"string"==typeof n&&(e="binary"===n?new Array(16):null,n=null);var f=(n=n||{}).random||(n.rng||t)();if(f[6]=15&f[6]|64,f[8]=63&f[8]|128,e)for(var u=0;u<16;++u)e[i+u]=f[u];return e||o(f)}},{"./lib/bytesToUuid":1,"./lib/rng":2}]},{},[3])(3)});
|
Loading…
Reference in New Issue
Block a user