Stackedit/js/synchronizer.js

216 lines
6.6 KiB
JavaScript
Raw Normal View History

2013-04-02 18:42:47 +00:00
define(["jquery", "core", "gdrive"], function($, core, gdrive) {
2013-04-01 16:46:48 +00:00
var synchronizer = {};
2013-04-02 18:42:47 +00:00
// Dependencies
var fileManager = undefined;
// Used to know the providers we are connected to
synchronizer.useGoogleDrive = false;
var onSyncBegin = undefined;
var onSyncEnd = undefined;
var onQueueChanged = undefined;
2013-04-01 16:46:48 +00:00
// A synchronization queue containing fileIndex that has to be synchronized
var syncUpQueue = undefined;
2013-04-02 18:42:47 +00:00
synchronizer.init = function(fileManagerModule, options) {
fileManager = fileManagerModule;
onSyncBegin = options.onSyncBegin || core.doNothing;
onSyncEnd = options.onSyncEnd || core.doNothing;
onQueueChanged = options.onQueueChanged || core.doNothing;
2013-04-01 16:46:48 +00:00
syncUpQueue = ";";
// Load the queue from localStorage in case a previous synchronization
// was aborted
if (localStorage["sync.queue"]) {
syncUpQueue = localStorage["sync.queue"];
onQueueChanged();
2013-04-01 16:46:48 +00:00
}
if (localStorage["sync.current"]) {
this.addFileForUpload(localStorage["sync.current"]);
}
};
// Add a file to the synchronization queue
synchronizer.addFileForUpload = function(fileIndex) {
// Check that file has synchronized locations
if(localStorage[fileIndex + ".sync"].length === 1) {
return;
2013-04-01 16:46:48 +00:00
}
// Check that file is not in the queue
if (syncUpQueue.indexOf(";" + fileIndex + ";") !== -1) {
return;
}
syncUpQueue += fileIndex + ";";
localStorage["sync.queue"] = syncUpQueue;
onQueueChanged();
2013-04-01 16:46:48 +00:00
};
// Recursive function to upload a single file on multiple locations
function fileUp(fileSyncIndexList, content, title, callback) {
if (fileSyncIndexList.length === 0) {
localStorage.removeItem("sync.current");
// run the next file synchronization
syncUp(callback);
return;
}
var fileSyncIndex = fileSyncIndexList.pop();
// Try to find the provider
if (fileSyncIndex.indexOf(SYNC_PROVIDER_GDRIVE) === 0) {
var id = fileSyncIndex.substring(SYNC_PROVIDER_GDRIVE.length);
gdrive.updateFile(id, title, content, function(result) {
2013-04-02 18:42:47 +00:00
if (result !== undefined) {
fileUp(fileSyncIndexList, content, title, callback);
2013-04-01 16:46:48 +00:00
return;
}
2013-04-02 18:42:47 +00:00
// If error we put the fileIndex back in the queue
synchronizer.addFileForUpload(localStorage["sync.current"]);
localStorage.removeItem("sync.current");
callback();
return;
2013-04-01 16:46:48 +00:00
});
} else {
fileUp(fileSyncIndexList, content, title, callback);
}
}
function syncUp(callback) {
// If nothing to synchronize
if (syncUpQueue.length === 1) {
callback();
return;
}
// Dequeue the fileIndex
var separatorPos = syncUpQueue.indexOf(";", 1);
var fileIndex = syncUpQueue.substring(1, separatorPos);
localStorage["sync.current"] = fileIndex;
syncUpQueue = syncUpQueue.substring(separatorPos);
localStorage["sync.queue"] = syncUpQueue;
onQueueChanged();
2013-04-01 16:46:48 +00:00
var content = localStorage[fileIndex + ".content"];
var title = localStorage[fileIndex + ".title"];
// Parse the list of synchronized locations associated to the file
var fileSyncIndexList = localStorage[fileIndex + ".sync"].split(";");
fileUp(fileSyncIndexList, content, title, callback);
};
function syncDownGdrive(callback) {
2013-04-02 18:42:47 +00:00
if (synchronizer.useGoogleDrive === false) {
2013-04-01 16:46:48 +00:00
callback();
return;
}
var lastChangeId = parseInt(localStorage[SYNC_PROVIDER_GDRIVE
+ "lastChangeId"]);
gdrive.checkUpdates(lastChangeId, function(changes, newChangeId) {
if (changes === undefined) {
callback();
return;
}
gdrive.downloadContent(changes, function(changes) {
if (changes === undefined) {
callback();
return;
}
var updateFileTitles = false;
for ( var i = 0; i < changes.length; i++) {
var change = changes[i];
var fileSyncIndex = SYNC_PROVIDER_GDRIVE + change.fileId;
var fileIndex = fileManager.getFileIndexFromSync(fileSyncIndex);
2013-04-01 16:46:48 +00:00
// No file corresponding (this should never happen...)
if(fileIndex === undefined) {
// We can remove the stored etag
localStorage.removeItem(fileSyncIndex + ".etag");
continue;
}
var title = localStorage[fileIndex + ".title"];
// File deleted
if (change.deleted === true) {
fileManager.removeSync(fileSyncIndex);
updateFileTitles = true;
2013-04-02 18:42:47 +00:00
core.showMessage('"' + title + '" has been removed from Google Drive.');
2013-04-01 16:46:48 +00:00
continue;
}
var content = localStorage[fileIndex + ".content"];
var file = change.file;
var titleChanged = title != file.title;
var contentChanged = content != file.content;
// If file is in the upload queue we have a conflict
if ((titleChanged || contentChanged) && syncUpQueue.indexOf(";" + fileIndex + ";") !== -1) {
fileManager.createFile(title + " (backup)", content);
updateFileTitles = true;
2013-04-02 18:42:47 +00:00
core.showMessage('Conflict detected on "' + title + '". A backup has been created locally.');
2013-04-01 16:46:48 +00:00
}
// If file title changed
if(titleChanged) {
localStorage[fileIndex + ".title"] = file.title;
updateFileTitles = true;
2013-04-02 18:42:47 +00:00
core.showMessage('"' + title + '" has been renamed to "' + file.title + '" on Google Drive.');
2013-04-01 16:46:48 +00:00
}
// If file content changed
if(contentChanged) {
localStorage[fileIndex + ".content"] = file.content;
2013-04-02 18:42:47 +00:00
core.showMessage('"' + file.title + '" has been updated from Google Drive.');
2013-04-01 16:46:48 +00:00
if(fileIndex == localStorage["file.current"]) {
updateFileTitles = false; // Done by next function
fileManager.selectFile();
}
}
// Update file etag
localStorage[fileSyncIndex + ".etag"] = file.etag;
// Synchronize file to others locations
synchronizer.addFileForUpload(fileIndex);
}
if(updateFileTitles) {
fileManager.updateFileTitles();
}
localStorage[SYNC_PROVIDER_GDRIVE
+ "lastChangeId"] = newChangeId;
callback();
});
});
}
function syncDown(callback) {
syncDownGdrive(callback);
};
var syncRunning = false;
var lastSync = 0;
synchronizer.sync = function() {
// If sync is already running or timeout is not reached or offline
2013-04-02 18:42:47 +00:00
if (syncRunning || lastSync + SYNC_PERIOD > core.currentTime || core.isOffline) {
2013-04-01 16:46:48 +00:00
return;
}
syncRunning = true;
2013-04-02 18:42:47 +00:00
lastSync = core.currentTime;
onSyncBegin();
2013-04-01 16:46:48 +00:00
syncDown(function() {
syncUp(function() {
syncRunning = false;
onSyncEnd();
2013-04-01 16:46:48 +00:00
});
});
};
synchronizer.forceSync = function() {
lastSync = 0;
this.sync();
};
synchronizer.isRunning = function() {
return syncRunning;
};
2013-04-01 16:46:48 +00:00
synchronizer.isQueueEmpty = function() {
return syncUpQueue.length === 1;
};
2013-04-01 16:46:48 +00:00
return synchronizer;
2013-04-02 18:42:47 +00:00
});