[folks] Split setup of PersonaStores out into a PersonaStore.prepare() method



commit 14d0402e7ec633786ce91f9b877d2855deaff4d3
Author: Philip Withnall <philip withnall collabora co uk>
Date:   Wed Jun 30 13:52:08 2010 +0100

    Split setup of PersonaStores out into a PersonaStore.prepare() method
    
    This allows the PersonaStore.personas_added and PersonaStore.personas_removed
    signals to be connected to before the PersonaStore could first emit them,
    removing a race condition.

 backends/telepathy/tpf-persona-store.vala |    4 +++
 folks/individual-aggregator.vala          |   17 +++++++++++++++-
 folks/persona-store.vala                  |   30 +++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 1 deletions(-)
---
diff --git a/backends/telepathy/tpf-persona-store.vala b/backends/telepathy/tpf-persona-store.vala
index f941630..095142c 100644
--- a/backends/telepathy/tpf-persona-store.vala
+++ b/backends/telepathy/tpf-persona-store.vala
@@ -117,6 +117,10 @@ public class Tpf.PersonaStore : Folks.PersonaStore
       this.groups = new HashMap<string, Channel> ();
       this.favourite_handles = new HashSet<uint> ();
       this.ll = new TpLowlevel ();
+    }
+
+  public override async void prepare ()
+    {
       this.account_manager = AccountManager.dup ();
 
       this.account_manager.account_disabled.connect ((a) =>
diff --git a/folks/individual-aggregator.vala b/folks/individual-aggregator.vala
index 4282017..f1f523c 100644
--- a/folks/individual-aggregator.vala
+++ b/folks/individual-aggregator.vala
@@ -112,8 +112,23 @@ public class Folks.IndividualAggregator : Object
   private void backend_persona_store_added_cb (Backend backend,
       PersonaStore store)
     {
-      this.stores.set (this.get_store_full_id (store.type_id, store.id), store);
+      string store_id = this.get_store_full_id (store.type_id, store.id);
+
+      this.stores.set (store_id, store);
       store.personas_changed.connect (this.personas_changed_cb);
+
+      store.prepare.begin ((obj, result) =>
+        {
+          try
+            {
+              store.prepare.end (result);
+            }
+          catch (GLib.Error e)
+            {
+              warning ("Error preparing PersonaStore '%s': %s", store_id,
+                  e.message);
+            }
+        });
     }
 
   private void backend_persona_store_removed_cb (Backend backend,
diff --git a/folks/persona-store.vala b/folks/persona-store.vala
index 94cecbe..95350b4 100644
--- a/folks/persona-store.vala
+++ b/folks/persona-store.vala
@@ -39,6 +39,12 @@ public errordomain Folks.PersonaStoreError
 
 /**
  * A store for { link Persona}s.
+ *
+ * After creating a PersonaStore instance, you must connect to the
+ * { link PersonaStore.personas_changed} signal, //then// call
+ * { link PersonaStore.prepare}, otherwise a race condition may occur between
+ * emission of { link PersonaStore.personas_changed} and your code connecting to
+ * it.
  */
 public abstract class Folks.PersonaStore : Object
 {
@@ -46,6 +52,9 @@ public abstract class Folks.PersonaStore : Object
    * Emitted when one or more { link Persona}s are added to or removed from
    * the store.
    *
+   * This will not be emitted until after { link PersonaStore.prepare} has been
+   * called.
+   *
    * @param added a list of { link Persona}s which have been removed
    * @param removed a list of { link Persona}s which have been removed
    * @param message a string message from the backend, if any
@@ -63,6 +72,9 @@ public abstract class Folks.PersonaStore : Object
    *
    * At this point, the PersonaStore and all its { link Persona}s are invalid,
    * so any client referencing it should unreference it.
+   *
+   * This will not be emitted until after { link PersonaStore.prepare} has been
+   * called.
    */
   public abstract signal void removed ();
 
@@ -70,6 +82,9 @@ public abstract class Folks.PersonaStore : Object
    * The type of PersonaStore this is.
    *
    * This is the same for all PersonaStores provided by a given { link Backend}.
+   *
+   * This is guaranteed to always be available; even before
+   * { link PersonaStore.prepare} is called.
    */
   public abstract string type_id { get; protected set; }
 
@@ -88,6 +103,21 @@ public abstract class Folks.PersonaStore : Object
   public abstract HashTable<string, Persona> personas { get; }
 
   /**
+   * Prepare the PersonaStore for use.
+   *
+   * This connects the PersonaStore to whichever backend-specific services it
+   * requires to be able to provide { link Persona}s. This should be called
+   * //after// connecting to the { link PersonaStore.personas_changed} signal,
+   * or a race condition could occur, with the signal being emitted before your
+   * code has connected to it, and { link Persona}s getting "lost" as a result.
+   *
+   * This is normally handled transparently by the { link IndividualAggregator}.
+   *
+   * If this function throws an error, the PersonaStore will not be functional.
+   */
+  public abstract async void prepare () throws GLib.Error;
+
+  /**
    * Add a new { link Persona} to the PersonaStore.
    *
    * The { link Persona} will be created by the PersonaStore backend from the



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]