Add: sync.js
This commit is contained in:
parent
1fa223c46d
commit
edb531026c
|
@ -1,6 +1,6 @@
|
||||||
/* eslint no-eq-null: 0, eqeqeq: [2, "smart"] */
|
/* eslint no-eq-null: 0, eqeqeq: [2, "smart"] */
|
||||||
/* global createCache db calcStyleDigest db tryRegExp styleCodeEmpty
|
/* global createCache db calcStyleDigest db tryRegExp styleCodeEmpty
|
||||||
getStyleWithNoCode msg sync uuidv4 */
|
getStyleWithNoCode msg sync uuid */
|
||||||
/* exported styleManager */
|
/* exported styleManager */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -63,11 +63,16 @@ const styleManager = (() => {
|
||||||
|
|
||||||
handleLivePreviewConnections();
|
handleLivePreviewConnections();
|
||||||
|
|
||||||
return ensurePrepared({
|
return Object.assign({
|
||||||
|
compareRevision
|
||||||
|
}, ensurePrepared({
|
||||||
get,
|
get,
|
||||||
|
getByUUID,
|
||||||
getSectionsByUrl,
|
getSectionsByUrl,
|
||||||
|
putByUUID,
|
||||||
installStyle,
|
installStyle,
|
||||||
deleteStyle,
|
deleteStyle,
|
||||||
|
deleteByUUID,
|
||||||
editSave,
|
editSave,
|
||||||
findStyle,
|
findStyle,
|
||||||
importStyle,
|
importStyle,
|
||||||
|
@ -80,7 +85,7 @@ const styleManager = (() => {
|
||||||
removeExclusion,
|
removeExclusion,
|
||||||
addInclusion,
|
addInclusion,
|
||||||
removeInclusion
|
removeInclusion
|
||||||
});
|
}));
|
||||||
|
|
||||||
function handleLivePreviewConnections() {
|
function handleLivePreviewConnections() {
|
||||||
chrome.runtime.onConnect.addListener(port => {
|
chrome.runtime.onConnect.addListener(port => {
|
||||||
|
@ -121,11 +126,48 @@ const styleManager = (() => {
|
||||||
return noCode ? getStyleWithNoCode(data) : data;
|
return noCode ? getStyleWithNoCode(data) : data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getByUUID(uuid) {
|
||||||
|
const id = uuidIndex.get(uuid);
|
||||||
|
if (id) {
|
||||||
|
return get(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getAllStyles(noCode = false) {
|
function getAllStyles(noCode = false) {
|
||||||
const datas = [...styles.values()].map(s => s.data);
|
const datas = [...styles.values()].map(s => s.data);
|
||||||
return noCode ? datas.map(getStyleWithNoCode) : datas;
|
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) {
|
function toggleStyle(id, enabled) {
|
||||||
const style = styles.get(id);
|
const style = styles.get(id);
|
||||||
const data = Object.assign({}, style.data, {enabled});
|
const data = Object.assign({}, style.data, {enabled});
|
||||||
|
@ -247,12 +289,14 @@ const styleManager = (() => {
|
||||||
return removeIncludeExclude(id, rule, 'inclusions');
|
return removeIncludeExclude(id, rule, 'inclusions');
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteStyle(id) {
|
function deleteStyle(id, reason) {
|
||||||
const style = styles.get(id);
|
const style = styles.get(id);
|
||||||
beforeSave(style);
|
const rev = Date.now();
|
||||||
return db.exec('delete', id)
|
return db.exec('delete', id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
sync.delete(style._id, style._rev);
|
if (reason !== 'sync') {
|
||||||
|
sync.delete(style.data._id, rev);
|
||||||
|
}
|
||||||
for (const url of style.appliesTo) {
|
for (const url of style.appliesTo) {
|
||||||
const cache = cachedStyleForUrl.get(url);
|
const cache = cachedStyleForUrl.get(url);
|
||||||
if (cache) {
|
if (cache) {
|
||||||
|
@ -260,6 +304,7 @@ const styleManager = (() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
styles.delete(id);
|
styles.delete(id);
|
||||||
|
uuidIndex.delete(style.data._id);
|
||||||
return msg.broadcast({
|
return msg.broadcast({
|
||||||
method: 'styleDeleted',
|
method: 'styleDeleted',
|
||||||
style: {id}
|
style: {id}
|
||||||
|
@ -268,6 +313,14 @@ const styleManager = (() => {
|
||||||
.then(() => id);
|
.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) {
|
function ensurePrepared(methods) {
|
||||||
const prepared = {};
|
const prepared = {};
|
||||||
for (const [name, fn] of Object.entries(methods)) {
|
for (const [name, fn] of Object.entries(methods)) {
|
||||||
|
@ -330,7 +383,7 @@ const styleManager = (() => {
|
||||||
delete style.id;
|
delete style.id;
|
||||||
}
|
}
|
||||||
if (!style._id) {
|
if (!style._id) {
|
||||||
style._id = uuidv4();
|
style._id = uuid();
|
||||||
}
|
}
|
||||||
style._rev = Date.now();
|
style._rev = Date.now();
|
||||||
fixUsoMd5Issue(style);
|
fixUsoMd5Issue(style);
|
||||||
|
@ -469,7 +522,7 @@ const styleManager = (() => {
|
||||||
function addMissingProperties(style) {
|
function addMissingProperties(style) {
|
||||||
let touched = false;
|
let touched = false;
|
||||||
if (!style._id) {
|
if (!style._id) {
|
||||||
style._id = uuidv4();
|
style._id = uuid();
|
||||||
touched = true;
|
touched = true;
|
||||||
}
|
}
|
||||||
if (!style._rev) {
|
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.openManage': '',
|
||||||
'hotkey.styleDisableAll': '',
|
'hotkey.styleDisableAll': '',
|
||||||
|
|
||||||
|
'sync.enabled': 'none',
|
||||||
|
|
||||||
'iconset': 0, // 0 = dark-themed icon
|
'iconset': 0, // 0 = dark-themed icon
|
||||||
// 1 = light-themed icon
|
// 1 = light-themed icon
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,11 @@
|
||||||
"js/script-loader.js",
|
"js/script-loader.js",
|
||||||
"js/usercss.js",
|
"js/usercss.js",
|
||||||
"js/cache.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/content-scripts.js",
|
||||||
"background/db.js",
|
"background/db.js",
|
||||||
"background/style-manager.js",
|
"background/style-manager.js",
|
||||||
|
@ -45,8 +50,7 @@
|
||||||
"background/style-via-api.js",
|
"background/style-via-api.js",
|
||||||
"background/search-db.js",
|
"background/search-db.js",
|
||||||
"background/update.js",
|
"background/update.js",
|
||||||
"background/openusercss-api.js",
|
"background/openusercss-api.js"
|
||||||
"vendor/semver-bundle/semver.js"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"archiver": "^3.1.1",
|
"archiver": "^3.1.1",
|
||||||
"codemirror": "^5.48.4",
|
"codemirror": "^5.48.4",
|
||||||
|
"db-to-cloud": "^0.1.0",
|
||||||
"dropbox": "^4.0.30",
|
"dropbox": "^4.0.30",
|
||||||
"endent": "^1.3.0",
|
"endent": "^1.3.0",
|
||||||
"eslint": "^6.3.0",
|
"eslint": "^6.3.0",
|
||||||
|
|
|
@ -40,6 +40,9 @@ const files = {
|
||||||
'vendor/inflate.js → inflate.js',
|
'vendor/inflate.js → inflate.js',
|
||||||
'vendor/z-worker.js → z-worker.js',
|
'vendor/z-worker.js → z-worker.js',
|
||||||
'vendor/zip.js → zip.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