Skip to content

Commit

Permalink
sync feature (gorhill#80): draft
Browse files Browse the repository at this point in the history
  • Loading branch information
gorhill committed Aug 11, 2015
1 parent a771211 commit 690421a
Show file tree
Hide file tree
Showing 18 changed files with 620 additions and 93 deletions.
200 changes: 200 additions & 0 deletions platform/chromium/vapi-background.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,14 @@ vAPI.app.restart = function() {
chrome.runtime.reload();
};

/******************************************************************************/
/******************************************************************************/

// chrome.storage.local.get(null, function(bin){ console.debug('%o', bin); });

vAPI.storage = chrome.storage.local;

/******************************************************************************/
/******************************************************************************/

// https://github.com/gorhill/uMatrix/issues/234
Expand Down Expand Up @@ -101,6 +103,7 @@ vAPI.browserSettings = {
}
};

/******************************************************************************/
/******************************************************************************/

vAPI.tabs = {};
Expand Down Expand Up @@ -499,6 +502,7 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
}
};

/******************************************************************************/
/******************************************************************************/

// Must read: https://code.google.com/p/chromium/issues/detail?id=410868#c8
Expand Down Expand Up @@ -534,6 +538,7 @@ vAPI.setIcon = function(tabId, iconStatus, badge) {
chrome.browserAction.setIcon({ tabId: tabId, path: iconPaths }, onIconReady);
};

/******************************************************************************/
/******************************************************************************/

vAPI.messaging = {
Expand Down Expand Up @@ -751,6 +756,7 @@ vAPI.messaging.broadcast = function(message) {
}
};

/******************************************************************************/
/******************************************************************************/

vAPI.net = {};
Expand Down Expand Up @@ -875,6 +881,7 @@ vAPI.net.registerListeners = function() {
);
};

/******************************************************************************/
/******************************************************************************/

vAPI.contextMenu = {
Expand All @@ -890,12 +897,14 @@ vAPI.contextMenu = {
}
};

/******************************************************************************/
/******************************************************************************/

vAPI.lastError = function() {
return chrome.runtime.lastError;
};

/******************************************************************************/
/******************************************************************************/

// This is called only once, when everything has been loaded in memory after
Expand Down Expand Up @@ -947,6 +956,7 @@ vAPI.onLoadAllCompleted = function() {
chrome.tabs.query({ url: '<all_urls>' }, bindToTabs);
};

/******************************************************************************/
/******************************************************************************/

vAPI.punycodeHostname = function(hostname) {
Expand All @@ -957,6 +967,196 @@ vAPI.punycodeURL = function(url) {
return url;
};

/******************************************************************************/
/******************************************************************************/

vAPI.cloud = (function() {
var chunkCountPerFetch = 16; // Must be a power of 2

// Mind chrome.storage.sync.MAX_ITEMS (512 at time of writing)
var maxChunkCountPerItem = Math.floor(512 * 0.75) & ~(chunkCountPerFetch - 1);

// Mind chrome.storage.sync.QUOTA_BYTES_PER_ITEM (8192 at time of writing)
var maxChunkSize = Math.floor(chrome.storage.sync.QUOTA_BYTES_PER_ITEM * 0.75);

// Mind chrome.storage.sync.QUOTA_BYTES_PER_ITEM (8192 at time of writing)
var maxStorageSize = chrome.storage.sync.QUOTA_BYTES;

var options = {
deviceName: ''
};

var getDeviceName = function() {
// Assign a permanent user-friendly id to this uBlock instance if one does
// not exist. This will allow to have some sort of identifier for a user
// to possibly identify the source of cloud data.
var name = window.localStorage.getItem('deviceName') || '';
if ( name !== '' ) {
return name;
}

return window.navigator.platform;
};

// This is used to find out a rough count of how many chunks exists:
// We "poll" at specific index in order to get a rough idea of how
// large is the stored string.
// This allows reading a single item with only 2 sync operations -- a
// good thing given chrome.storage.syncMAX_WRITE_OPERATIONS_PER_MINUTE
// and chrome.storage.syncMAX_WRITE_OPERATIONS_PER_HOUR.
var getCoarseChunkCount = function(dataKey, callback) {
var bin = {};
for ( var i = 0; i < maxChunkCountPerItem; i += 16 ) {
bin[dataKey + i.toString()] = '';
}

chrome.storage.sync.get(bin, function(bin) {
if ( chrome.runtime.lastError ) {
callback(0, chrome.runtime.lastError.message);
return;
}

// Could loop backward... let's assume for now
// maxChunkCountPerItem could be something else than a
// multiple of 16.
var chunkCount = 0;
for ( var i = 0; i < maxChunkCountPerItem; i += 16 ) {
if ( bin[dataKey + i.toString()] === '' ) {
break;
}
chunkCount = i + 16;
}

callback(chunkCount);
});
};

var deleteChunks = function(dataKey, start) {
var keys = [];

// No point in deleting more than:
// - The max number of chunks per item
// - The max number of chunks per storage limit
var n = Math.min(
maxChunkCountPerItem,
Math.ceil(maxStorageSize / maxChunkSize)
);
for ( var i = start; i < n; i++ ) {
keys.push(dataKey + i.toString());
}
chrome.storage.sync.remove(keys);
};

var start = function(/* dataKeys */) {
};

var push = function(dataKey, data, callback) {
var item = JSON.stringify({
'source': getDeviceName(),
'tstamp': Date.now(),
'data': data
});

// Chunkify taking into account QUOTA_BYTES_PER_ITEM:
// https://developer.chrome.com/extensions/storage#property-sync
// "The maximum size (in bytes) of each individual item in sync
// "storage, as measured by the JSON stringification of its value
// "plus its key length."
var bin = {};
var chunkCount = Math.ceil(item.length / maxChunkSize);
for ( var i = 0; i < chunkCount; i++ ) {
bin[dataKey + i.toString()] = item.substr(i * maxChunkSize, maxChunkSize);
}
bin[dataKey + i.toString()] = ''; // Sentinel

chrome.storage.sync.set(bin, function() {
var errorStr;
if ( chrome.runtime.lastError ) {
errorStr = chrome.runtime.lastError.message;
}
callback(errorStr);

// Remove potentially unused trailing chunks
deleteChunks(dataKey, chunkCount);
});
};

var pull = function(dataKey, callback) {
var assembleChunks = function(bin) {
if ( chrome.runtime.lastError ) {
callback(null, chrome.runtime.lastError.message);
return;
}

// Assemble chunks into a single string.
var json = [], jsonSlice;
var i = 0;
for (;;) {
jsonSlice = bin[dataKey + i.toString()];
if ( jsonSlice === '' ) {
break;
}
json.push(jsonSlice);
i += 1;
}

var entry = null;
try {
entry = JSON.parse(json.join(''));
} catch(ex) {
}
callback(entry);
};

var fetchChunks = function(coarseCount, errorStr) {
if ( coarseCount === 0 || typeof errorStr === 'string' ) {
callback(null, errorStr);
return;
}

var bin = {};
for ( var i = 0; i < coarseCount; i++ ) {
bin[dataKey + i.toString()] = '';
}

chrome.storage.sync.get(bin, assembleChunks);
};

getCoarseChunkCount(dataKey, fetchChunks);
};

var getOptions = function(callback) {
if ( typeof callback !== 'function' ) {
return;
}

callback(options);
};

var setOptions = function(details, callback) {
if ( typeof details !== 'object' || details === null ) {
return;
}

if ( typeof details.deviceName === 'string' ) {
window.localStorage.setItem('deviceName', details.deviceName);
}

if ( typeof callback === 'function' ) {
callback(options);
}
};

return {
start: start,
push: push,
pull: pull,
getOptions: getOptions,
setOptions: setOptions
};
})();

/******************************************************************************/
/******************************************************************************/

})();
Expand Down
Loading

0 comments on commit 690421a

Please sign in to comment.