From 8b9c6fbe0d9d0538d27b2edb7a4b66467b659b35 Mon Sep 17 00:00:00 2001 From: Xelio Date: Sun, 25 Aug 2013 22:50:59 +0800 Subject: [PATCH 1/2] Bug fix: Plugin Sync 1. Failed to create more than one realtime document. Pass assignIdCallback and failedCallback as function parameter for FileSearcher instead of saving it. 2. If a client with empty data use Sync plugin first, other clients will lose their data once connected with Realtime API. Assign '' to lastUpdateUUID on model initialization if the client do not have data. 3. Realtime API sometimes return 'CLIENT_ERROR' instead of 'NOT_FOUND' if a file is not found Change handling of 'CLIENT_ERROR' to the same as 'NOT_FOUND' --- plugins/sync.user.js | 63 +++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/plugins/sync.user.js b/plugins/sync.user.js index 9f90b9cb..87eec2d3 100644 --- a/plugins/sync.user.js +++ b/plugins/sync.user.js @@ -135,7 +135,8 @@ window.plugin.sync.RegisteredMap.prototype.updateMap = function(keyArray) { } window.plugin.sync.RegisteredMap.prototype.isUpdatedByOthers = function() { - return this.lastUpdateUUID.toString() !== this.uuid; + var remoteUUID = this.lastUpdateUUID.toString(); + return (remoteUUID !== '') && (remoteUUID !== this.uuid); } window.plugin.sync.RegisteredMap.prototype.getFileName = function() { @@ -159,10 +160,8 @@ window.plugin.sync.RegisteredMap.prototype.initFile = function(callback) { } this.fileSearcher = new plugin.sync.FileSearcher({'fileName': this.getFileName(), - 'description': 'IITC plugin data for ' + this.getFileName(), - 'assignIdCallback': assignIdCallback, - 'failedCallback': failedCallback}); - this.fileSearcher.initialize(this.forceFileSearch); + 'description': 'IITC plugin data for ' + this.getFileName()}); + this.fileSearcher.initialize(this.forceFileSearch, assignIdCallback, failedCallback); } window.plugin.sync.RegisteredMap.prototype.updateListener = function(e) { @@ -191,14 +190,18 @@ window.plugin.sync.RegisteredMap.prototype.loadRealtimeDocument = function(callb // this function called when the document is created first time // and the CollaborativeMap is populated with data in plugin field initializeModel = function(model) { + var empty = true; var map = model.createMap(); var lastUpdateUUID = model.createString(); // Init the map values if this map is first created $.each(window.plugin[_this.pluginName][_this.fieldName], function(key, val) { map.set(key, val); + empty = false; }); - lastUpdateUUID.setText(_this.uuid); + + // Only set the update client if the map is not empty, avoid clearing data of other clients + lastUpdateUUID.setText(empty ? '' : _this.uuid); model.getRoot().set('map', map); model.getRoot().set('last-udpate-uuid', lastUpdateUUID); @@ -211,8 +214,8 @@ window.plugin.sync.RegisteredMap.prototype.loadRealtimeDocument = function(callb onFileLoaded = function(doc) { _this.doc = doc; _this.model = doc.getModel(); - _this.map = doc.getModel().getRoot().get("map"); - _this.lastUpdateUUID = doc.getModel().getRoot().get("last-udpate-uuid"); + _this.map = doc.getModel().getRoot().get('map'); + _this.lastUpdateUUID = doc.getModel().getRoot().get('last-udpate-uuid'); _this.map.addEventListener(gapi.drive.realtime.EventType.VALUE_CHANGED, _this.updateListener); // Replace local value if data is changed by others @@ -240,6 +243,10 @@ window.plugin.sync.RegisteredMap.prototype.loadRealtimeDocument = function(callb _this.authorizer.authorize(); } else if(e.type === gapi.drive.realtime.ErrorType.NOT_FOUND) { _this.forceFileSearch = true; + } else if(e.type === gapi.drive.realtime.ErrorType.CLIENT_ERROR) { + // Workaround: if Realtime API open a second docuemnt and the file do not exist, + // it will rasie 'CLIENT_ERROR' instead of 'NOT_FOUND'. So we do a force file search here. + _this.forceFileSearch = true; } else { alert('Plugin Sync error: ' + e.type + ', ' + e.message); } @@ -367,8 +374,6 @@ window.plugin.sync.FileSearcher = function(options) { this.fileName = options['fileName']; this.description = options['description']; this.isFolder = options['isFolder']; - this.assignIdCallback = options['assignIdCallback']; - this.failedCallback = options['failedCallback']; this.force = false; this.parent = null; @@ -386,27 +391,27 @@ window.plugin.sync.FileSearcher.prototype.MIMETYPE_FOLDER = 'application/vnd.goo window.plugin.sync.FileSearcher.prototype.parentName = 'IITC-SYNC-DATA-V2'; window.plugin.sync.FileSearcher.prototype.parentDescription = 'Store IITC sync data'; -window.plugin.sync.FileSearcher.prototype.initialize = function(force) { +window.plugin.sync.FileSearcher.prototype.initialize = function(force, assignIdCallback, failedCallback) { this.force = force; // throw error if too many retry if(this.retryCount >= this.RETRY_LIMIT) { plugin.sync.logger.log('Too many file operation: ' + this.fileName); - this.failedCallback(); + failedCallback(); return; } if(this.force) this.retryCount++; if(this.isFolder) { - this.initFile(); + this.initFile(assignIdCallback, failedCallback); } else { - this.initParent(); + this.initParent(assignIdCallback, failedCallback); } } -window.plugin.sync.FileSearcher.prototype.initFile = function() { +window.plugin.sync.FileSearcher.prototype.initFile = function(assignIdCallback, failedCallback) { // If not force search and have cached fileId, return the fileId if(!this.force && this.fileId) { - this.assignIdCallback(this.fileId); + assignIdCallback(this.fileId); return; } @@ -416,14 +421,14 @@ window.plugin.sync.FileSearcher.prototype.initFile = function() { handleFileId = function(id) { _this.fileId = id; _this.saveFileId(); - _this.assignIdCallback(id); + assignIdCallback(id); }; handleFailed = function(resp) { _this.fileId = null; _this.saveFileId(); plugin.sync.logger.log('File operation failed: ' + (resp.error || 'unknown error')); - _this.failedCallback(resp); + failedCallback(resp); } createCallback = function(resp) { @@ -447,27 +452,25 @@ window.plugin.sync.FileSearcher.prototype.initFile = function() { this.searchFileOrFolder(searchCallback); } -window.plugin.sync.FileSearcher.prototype.initParent = function() { - var assignIdCallback, failedCallback, _this; +window.plugin.sync.FileSearcher.prototype.initParent = function(assignIdCallback, failedCallback) { + var parentAssignIdCallback, parentFailedCallback, _this; _this = this; - assignIdCallback = function(id) { - _this.initFile(); + parentAssignIdCallback = function(id) { + _this.initFile(assignIdCallback, failedCallback); } - failedCallback = function(resp) { + parentFailedCallback = function(resp) { _this.fileId = null; _this.saveFileId(); plugin.sync.logger.log('File operation failed: ' + (resp.error || 'unknown error')); - _this.failedCallback(resp); + failedCallback(resp); } this.parent = new plugin.sync.FileSearcher({'fileName': this.parentName, 'description': this.parentDescription, - 'isFolder': true, - 'assignIdCallback': assignIdCallback, - 'failedCallback': failedCallback}); - this.parent.initialize(this.force); + 'isFolder': true}); + this.parent.initialize(this.force, parentAssignIdCallback, parentFailedCallback); } window.plugin.sync.FileSearcher.prototype.createFileOrFolder = function(callback) { @@ -629,12 +632,12 @@ window.plugin.sync.generateUUID = function() { window.crypto.getRandomValues(buf); var S4 = function(num) { var ret = num.toString(16); - return "000".substring(0, 4-ret.length) + ret; + return '000'.substring(0, 4-ret.length) + ret; }; var yxxx = function(num) { return num&0x3fff|0x8000; } - return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-4"+S4(buf[3]).substring(1)+"-"+S4(yxxx(buf[4]))+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7])); + return (S4(buf[0])+S4(buf[1])+'-'+S4(buf[2])+'-4'+S4(buf[3]).substring(1)+'-'+S4(yxxx(buf[4]))+'-'+S4(buf[5])+S4(buf[6])+S4(buf[7])); } else { var d = new Date().getTime(); var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { From 7dfaa27327654a933d4e4d1052b0d0ce25a987d7 Mon Sep 17 00:00:00 2001 From: Xelio Date: Sun, 25 Aug 2013 23:59:48 +0800 Subject: [PATCH 2/2] Plugin Sync: bump version number to 0.2.1 --- plugins/keys.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/keys.user.js b/plugins/keys.user.js index bd9984a7..41939039 100644 --- a/plugins/keys.user.js +++ b/plugins/keys.user.js @@ -2,7 +2,7 @@ // @id iitc-plugin-keys@xelio // @name IITC plugin: Keys // @category Keys -// @version 0.2.0.@@DATETIMEVERSION@@ +// @version 0.2.1.@@DATETIMEVERSION@@ // @namespace https://github.com/jonatkins/ingress-intel-total-conversion // @updateURL @@UPDATEURL@@ // @downloadURL @@DOWNLOADURL@@