From 38f2e345d935f0095415babb7506fa5a5afe24ed Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Wed, 27 Dec 2017 11:09:49 -0600 Subject: [PATCH] Updated SingletonManager --- .../javascripts/app/services/authManager.js | 2 +- .../app/services/componentManager.js | 1 - .../app/services/singletonManager.js | 42 +++++++++++++++---- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/app/services/authManager.js b/app/assets/javascripts/app/services/authManager.js index ef29e12f9..4e7f1936f 100644 --- a/app/assets/javascripts/app/services/authManager.js +++ b/app/assets/javascripts/app/services/authManager.js @@ -296,7 +296,7 @@ angular.module('app.frontend') let prefsContentType = "SN|UserPreferences"; singletonManager.registerSingleton({content_type: prefsContentType}, (resolvedSingleton) => { - console.log("AuthManager received resolved", resolvedSingleton); + console.log("AuthManager received resolved UserPreferences", resolvedSingleton); this.userPreferences = resolvedSingleton; }, () => { // Safe to create. Create and return object. diff --git a/app/assets/javascripts/app/services/componentManager.js b/app/assets/javascripts/app/services/componentManager.js index 46b71f3c6..8fc753043 100644 --- a/app/assets/javascripts/app/services/componentManager.js +++ b/app/assets/javascripts/app/services/componentManager.js @@ -48,7 +48,6 @@ class ComponentManager { recursion caused by the component being modified and saved after it is updated. */ if(syncedComponents.length > 0 && source != ModelManager.MappingSourceRemoteSaved) { - console.log("Web, Syncing Components", syncedComponents, "source", source); // Ensure any component in our data is installed by the system this.desktopManager.syncComponentsInstallation(syncedComponents); } diff --git a/app/assets/javascripts/app/services/singletonManager.js b/app/assets/javascripts/app/services/singletonManager.js index 07e892c82..3f6d260e7 100644 --- a/app/assets/javascripts/app/services/singletonManager.js +++ b/app/assets/javascripts/app/services/singletonManager.js @@ -1,7 +1,11 @@ /* The SingletonManager allows controllers to register an item as a singleton, which means only one instance of that model should exist, both on the server and on the client. When the SingletonManager detects multiple items matching the singleton predicate, - the oldest ones will be deleted, leaving the newest ones + the oldest ones will be deleted, leaving the newest ones. + + We will treat the model most recently arrived from the server as the most recent one. The reason for this is, if you're offline, + a singleton can be created, as in the case of UserPreferneces. Then when you sign in, you'll retrieve your actual user preferences. + In that case, even though the offline singleton has a more recent updated_at, the server retreived value is the one we care more about. */ class SingletonManager { @@ -16,13 +20,14 @@ class SingletonManager { }) $rootScope.$on("sync:completed", (event, data) => { - console.log("Sync completed", data); this.resolveSingletons(data.retrievedItems || []); }) + // Testing code to make sure only 1 exists setTimeout(function () { - var userPrefsTotal = modelManager.itemsForContentType("SN|UserPreferences"); - console.log("All extant prefs", userPrefsTotal); + var userPrefs = modelManager.itemsForContentType("SN|UserPreferences"); + console.assert(userPrefs.length == 1); + console.log("All extant prefs", userPrefs); }, 1000); } @@ -44,25 +49,46 @@ class SingletonManager { var predicate = singletonHandler.predicate; var singletonItems = this.filterItemsWithPredicate(retrievedItems, predicate); if(singletonItems.length > 0) { - // Check local inventory and make sure only 1 similar item exists. If more than 1, delete oldest + /* + Check local inventory and make sure only 1 similar item exists. If more than 1, delete oldest + Note that this local inventory will also contain whatever is in retrievedItems. + However, as stated in the header comment, retrievedItems take precendence over existing items, + even if they have a lower updated_at value + */ var allExtantItemsMatchingPredicate = this.filterItemsWithPredicate(this.modelManager.allItems, predicate); + /* + If there are more than 1 matches, delete everything not in `singletonItems`, + then delete all but the latest in `singletonItems` + */ if(allExtantItemsMatchingPredicate.length >= 2) { - // Purge old ones - var sorted = allExtantItemsMatchingPredicate.sort((a, b) => { + var toDelete = []; + for(var extantItem of allExtantItemsMatchingPredicate) { + if(!singletonItems.includes(extantItem)) { + // Delete it + toDelete.push(extantItem); + } + } + + // Sort incoming singleton items by most recently updated first, then delete all the rest + var sorted = singletonItems.sort((a, b) => { return a.updated_at < b.updated_at; }) - var toDelete = sorted.slice(1, sorted.length); + // Delete everything but the first one + toDelete = toDelete.concat(sorted.slice(1, sorted.length)); + for(var d of toDelete) { this.modelManager.setItemToBeDeleted(d); } this.$rootScope.sync(); + // Send remaining item to callback var singleton = sorted[0]; singletonHandler.singleton = singleton; singletonHandler.resolutionCallback(singleton); + } else if(allExtantItemsMatchingPredicate.length == 1) { if(!singletonHandler.singleton) { // Not yet notified interested parties of object