Stackedit/public/res/synchronizer.js

372 lines
14 KiB
JavaScript
Raw Permalink Normal View History

2013-05-26 22:59:03 +00:00
define([
"jquery",
2013-05-27 19:45:33 +00:00
"underscore",
2013-05-26 22:59:03 +00:00
"utils",
2013-11-05 23:03:38 +00:00
"storage",
2013-07-30 08:46:36 +00:00
"eventMgr",
2013-06-10 21:22:32 +00:00
"fileSystem",
"fileMgr",
2013-06-22 23:48:57 +00:00
"classes/Provider",
2013-06-10 21:22:32 +00:00
"providers/dropboxProvider",
2013-12-16 00:31:40 +00:00
"providers/gdriveProvider",
2013-12-23 22:40:13 +00:00
"providers/gdrivesecProvider",
"providers/gdriveterProvider"
2013-11-05 23:03:38 +00:00
], function($, _, utils, storage, eventMgr, fileSystem, fileMgr, Provider) {
2013-04-01 16:46:48 +00:00
2013-05-29 19:55:23 +00:00
var synchronizer = {};
2013-04-01 16:46:48 +00:00
2013-05-29 19:55:23 +00:00
// Create a map with providerId: providerModule
var providerMap = _.chain(arguments).map(function(argument) {
2013-06-22 23:48:57 +00:00
return argument instanceof Provider && [
2013-05-29 19:55:23 +00:00
argument.providerId,
argument
];
}).compact().object().value();
2013-04-01 16:46:48 +00:00
2013-11-05 23:03:38 +00:00
// Retrieve sync locations from storage
(function() {
var syncIndexMap = {};
_.each(fileSystem, function(fileDesc) {
utils.retrieveIndexArray(fileDesc.fileIndex + ".sync").forEach(function(syncIndex) {
try {
var syncAttributes = JSON.parse(storage[syncIndex]);
// Store syncIndex
syncAttributes.syncIndex = syncIndex;
// Replace provider ID by provider module in attributes
var provider = providerMap[syncAttributes.provider];
if(!provider) {
throw new Error("Invalid provider ID: " + syncAttributes.provider);
}
syncAttributes.provider = provider;
fileDesc.syncLocations[syncIndex] = syncAttributes;
syncIndexMap[syncIndex] = syncAttributes;
}
catch(e) {
// storage can be corrupted
eventMgr.onError(e);
// Remove sync location
utils.removeIndexFromArray(fileDesc.fileIndex + ".sync", syncIndex);
}
});
});
// Clean fields from deleted files in local storage
Object.keys(storage).forEach(function(key) {
2014-04-12 22:30:18 +00:00
var match = key.match(/sync\.\S+/);
if(match && !syncIndexMap.hasOwnProperty(match[0])) {
storage.removeItem(key);
2013-06-03 22:19:52 +00:00
}
2013-05-29 19:55:23 +00:00
});
})();
2014-03-28 00:49:49 +00:00
// AutoSync configuration
_.each(providerMap, function(provider) {
provider.autosyncConfig = utils.retrieveIgnoreError(provider.providerId + ".autosyncConfig") || {};
});
2014-03-28 00:49:49 +00:00
2013-07-21 14:38:53 +00:00
// Returns true if at least one file has synchronized location
2013-07-30 08:46:36 +00:00
synchronizer.hasSync = function(provider) {
return _.some(fileSystem, function(fileDesc) {
return _.some(fileDesc.syncLocations, function(syncAttributes) {
return provider === undefined || syncAttributes.provider === provider;
});
2013-07-21 14:38:53 +00:00
});
};
2013-04-01 16:46:48 +00:00
2013-07-20 01:08:17 +00:00
/***************************************************************************
2014-04-20 01:13:43 +00:00
* Synchronization
2013-07-20 01:08:17 +00:00
**************************************************************************/
2014-04-20 01:13:43 +00:00
// Entry point for up synchronization (upload changes)
var uploadCycle = false;
function syncUp(callback) {
var uploadFileList = [];
2014-04-20 01:13:43 +00:00
// Recursive function to upload multiple files
function fileUp() {
// No more fileDesc to synchronize
if(uploadFileList.length === 0) {
return syncUp(callback);
2013-05-29 19:55:23 +00:00
}
2013-04-10 18:14:59 +00:00
2014-04-20 01:13:43 +00:00
// Dequeue a fileDesc to synchronize
var fileDesc = uploadFileList.pop();
var uploadSyncAttributesList = _.values(fileDesc.syncLocations);
if(uploadSyncAttributesList.length === 0) {
return fileUp();
}
2013-05-29 19:55:23 +00:00
2014-04-20 01:13:43 +00:00
var uploadContent = fileDesc.content;
var uploadContentCRC = utils.crc32(uploadContent);
var uploadTitle = fileDesc.title;
var uploadTitleCRC = utils.crc32(uploadTitle);
var uploadDiscussionList = fileDesc.discussionListJSON;
var uploadDiscussionListCRC = utils.crc32(uploadDiscussionList);
2013-05-29 19:55:23 +00:00
2014-04-20 01:13:43 +00:00
// Recursive function to upload a single file on multiple locations
function locationUp() {
2013-05-29 19:55:23 +00:00
2014-04-20 01:13:43 +00:00
// No more synchronized location for this document
if(uploadSyncAttributesList.length === 0) {
return fileUp();
}
// Dequeue a synchronized location
var syncAttributes = uploadSyncAttributesList.pop();
syncAttributes.provider.syncUp(
uploadContent,
uploadContentCRC,
uploadTitle,
uploadTitleCRC,
uploadDiscussionList,
uploadDiscussionListCRC,
syncAttributes,
function(error, uploadFlag) {
if(uploadFlag === true) {
// If uploadFlag is true, request another upload cycle
uploadCycle = true;
}
if(error) {
return callback(error);
}
if(uploadFlag) {
// Update syncAttributes in storage
utils.storeAttributes(syncAttributes);
}
locationUp();
}
);
}
locationUp();
}
2013-05-29 19:55:23 +00:00
if(uploadCycle === true) {
// New upload cycle
uploadCycle = false;
uploadFileList = _.values(fileSystem);
2014-04-20 01:13:43 +00:00
fileUp();
2013-05-29 19:55:23 +00:00
}
else {
callback();
}
}
2014-04-20 01:13:43 +00:00
// Entry point for down synchronization (download changes)
function syncDown(callback) {
var providerList = _.values(providerMap);
2013-05-29 19:55:23 +00:00
2014-04-20 01:13:43 +00:00
// Recursive function to download changes from multiple providers
function providerDown() {
if(providerList.length === 0) {
return callback();
}
var provider = providerList.pop();
2013-05-29 19:55:23 +00:00
2014-04-20 01:13:43 +00:00
// Check that provider has files to sync
if(!synchronizer.hasSync(provider)) {
return providerDown();
2013-05-29 19:55:23 +00:00
}
2014-04-20 01:13:43 +00:00
// Perform provider's syncDown
provider.syncDown(function(error) {
if(error) {
return callback(error);
}
providerDown();
});
}
providerDown();
2013-05-29 19:55:23 +00:00
}
2014-04-20 01:13:43 +00:00
// Entry point for the autosync feature
function autosyncAll(callback) {
var autosyncFileList = _.filter(fileSystem, function(fileDesc) {
return _.size(fileDesc.syncLocations) === 0;
});
// Recursive function to autosync multiple files
function fileAutosync() {
// No more fileDesc to synchronize
if(autosyncFileList.length === 0) {
return callback();
}
var fileDesc = autosyncFileList.pop();
var providerList = _.filter(providerMap, function(provider) {
return provider.autosyncConfig.mode == 'all';
});
function providerAutosync() {
// No more provider
if(providerList.length === 0) {
return fileAutosync();
}
var provider = providerList.pop();
provider.autosyncFile(fileDesc.title, fileDesc.content, fileDesc.discussionListJSON, provider.autosyncConfig, function(error, syncAttributes) {
if(error) {
return callback(error);
}
fileDesc.addSyncLocation(syncAttributes);
eventMgr.onSyncExportSuccess(fileDesc, syncAttributes);
providerAutosync();
});
}
providerAutosync();
}
fileAutosync();
2013-05-29 19:55:23 +00:00
}
2013-08-04 00:53:46 +00:00
// Listen to offline status changes
var isOffline = false;
eventMgr.addListener("onOfflineChanged", function(isOfflineParam) {
isOffline = isOfflineParam;
});
2013-05-29 19:55:23 +00:00
// Main entry point for synchronization
var syncRunning = false;
synchronizer.sync = function() {
2013-06-10 22:32:34 +00:00
// If sync is already running or offline
2013-08-04 00:53:46 +00:00
if(syncRunning === true || isOffline === true) {
2013-06-10 22:32:34 +00:00
return false;
2013-05-29 19:55:23 +00:00
}
syncRunning = true;
2013-07-30 08:46:36 +00:00
eventMgr.onSyncRunning(true);
2013-05-29 19:55:23 +00:00
uploadCycle = true;
function isError(error) {
if(error !== undefined) {
syncRunning = false;
2013-07-30 08:46:36 +00:00
eventMgr.onSyncRunning(false);
2013-05-29 19:55:23 +00:00
return true;
}
return false;
}
2014-04-20 01:13:43 +00:00
autosyncAll(function(error) {
2013-05-29 19:55:23 +00:00
if(isError(error)) {
return;
}
2014-04-20 01:13:43 +00:00
syncDown(function(error) {
2013-05-29 19:55:23 +00:00
if(isError(error)) {
return;
}
2014-04-20 01:13:43 +00:00
syncUp(function(error) {
if(isError(error)) {
return;
}
syncRunning = false;
eventMgr.onSyncRunning(false);
eventMgr.onSyncSuccess();
});
2013-05-29 19:55:23 +00:00
});
});
2013-06-10 22:32:34 +00:00
return true;
2013-05-29 19:55:23 +00:00
};
2013-07-18 23:30:28 +00:00
2013-07-20 01:08:17 +00:00
/***************************************************************************
* Initialize module
**************************************************************************/
2013-05-29 19:55:23 +00:00
// Initialize the export dialog
function initExportDialog(provider) {
// Reset fields
utils.resetModalInputs();
// Load preferences
2013-06-03 22:19:52 +00:00
var exportPreferences = utils.retrieveIgnoreError(provider.providerId + ".exportPreferences");
if(exportPreferences) {
2013-05-29 19:55:23 +00:00
_.each(provider.exportPreferencesInputIds, function(inputId) {
2013-08-23 23:50:14 +00:00
var exportPreferenceValue = exportPreferences[inputId];
if(_.isBoolean(exportPreferenceValue)) {
utils.setInputChecked("#input-sync-export-" + inputId, exportPreferenceValue);
}
else {
utils.setInputValue("#input-sync-export-" + inputId, exportPreferenceValue);
}
2013-05-29 19:55:23 +00:00
});
}
// Open dialog
2013-08-11 00:52:05 +00:00
$(".modal-upload-" + provider.providerId).modal();
2013-05-29 19:55:23 +00:00
}
eventMgr.addListener("onFileCreated", function(fileDesc) {
if(_.size(fileDesc.syncLocations) === 0) {
_.each(providerMap, function(provider) {
2014-04-20 01:13:43 +00:00
if(provider.autosyncConfig.mode != 'new') {
return;
}
provider.autosyncFile(fileDesc.title, fileDesc.content, fileDesc.discussionListJSON, provider.autosyncConfig, function(error, syncAttributes) {
if(error) {
return;
}
fileDesc.addSyncLocation(syncAttributes);
eventMgr.onSyncExportSuccess(fileDesc, syncAttributes);
});
});
}
});
2013-08-04 00:53:46 +00:00
eventMgr.addListener("onReady", function() {
2013-05-29 19:55:23 +00:00
// Init each provider
_.each(providerMap, function(provider) {
// Provider's import button
$(".action-sync-import-" + provider.providerId).click(function(event) {
provider.importFiles(event);
});
// Provider's export action
$(".action-sync-export-dialog-" + provider.providerId).click(function() {
initExportDialog(provider);
});
// Provider's autosync action
$(".action-autosync-dialog-" + provider.providerId).click(function() {
// Reset fields
utils.resetModalInputs();
// Load config
provider.setAutosyncDialogConfig(provider);
// Open dialog
$(".modal-autosync-" + provider.providerId).modal();
});
2013-05-29 19:55:23 +00:00
$(".action-sync-export-" + provider.providerId).click(function(event) {
2013-06-19 20:33:46 +00:00
var fileDesc = fileMgr.currentFile;
2013-07-18 23:30:28 +00:00
2014-04-13 10:45:31 +00:00
provider.exportFile(event, fileDesc.title, fileDesc.content, fileDesc.discussionListJSON, function(error, syncAttributes) {
if(error) {
2013-07-18 23:30:28 +00:00
return;
2013-07-20 01:08:17 +00:00
}
2014-04-13 10:45:31 +00:00
fileDesc.addSyncLocation(syncAttributes);
eventMgr.onSyncExportSuccess(fileDesc, syncAttributes);
});
2013-05-29 19:55:23 +00:00
// Store input values as preferences for next time we open the
// export dialog
var exportPreferences = {};
_.each(provider.exportPreferencesInputIds, function(inputId) {
2013-08-23 23:50:14 +00:00
var inputElt = document.getElementById("input-sync-export-" + inputId);
if(inputElt.type == 'checkbox') {
exportPreferences[inputId] = inputElt.checked;
}
else {
exportPreferences[inputId] = inputElt.value;
}
2013-05-29 19:55:23 +00:00
});
2013-11-05 23:03:38 +00:00
storage[provider.providerId + ".exportPreferences"] = JSON.stringify(exportPreferences);
2013-05-29 19:55:23 +00:00
});
$(".action-autosync-" + provider.providerId).click(function(event) {
var config = provider.getAutosyncDialogConfig(event);
if(config !== undefined) {
storage[provider.providerId + ".autosyncConfig"] = JSON.stringify(config);
provider.autosyncConfig = config;
}
});
2013-05-29 19:55:23 +00:00
});
});
2013-07-30 08:46:36 +00:00
eventMgr.onSynchronizerCreated(synchronizer);
2013-05-29 19:55:23 +00:00
return synchronizer;
2013-04-02 18:42:47 +00:00
});