[folks] Add PersonaStore.is_prepared and make prepare() idempotent.



commit 329c41f971e0aad006b880c2640a30d38b459675
Author: Travis Reitter <travis reitter collabora co uk>
Date:   Thu Sep 9 09:07:11 2010 -0700

    Add PersonaStore.is_prepared and make prepare() idempotent.
    
    Helps bgo#629331.

 backends/key-file/kf-persona-store.vala       |  186 ++++++++++++++-----------
 backends/telepathy/lib/tpf-persona-store.vala |  131 ++++++++++-------
 folks/persona-store.vala                      |   10 ++
 3 files changed, 194 insertions(+), 133 deletions(-)
---
diff --git a/backends/key-file/kf-persona-store.vala b/backends/key-file/kf-persona-store.vala
index 6077d4b..6407eee 100644
--- a/backends/key-file/kf-persona-store.vala
+++ b/backends/key-file/kf-persona-store.vala
@@ -36,6 +36,7 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore
   private GLib.KeyFile key_file;
   private uint first_unused_id = 0;
   private unowned Cancellable save_key_file_cancellable = null;
+  private bool _is_prepared = false;
 
   /**
    * { inheritDoc}
@@ -53,6 +54,18 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore
   public override string id { get; private set; }
 
   /**
+   * Whether this PersonaStore has been prepared.
+   *
+   * See { link Folks.PersonaStore.is_prepared}.
+   *
+   * @since 0.3.0
+   */
+  public override bool is_prepared
+    {
+      get { return this._is_prepared; }
+    }
+
+  /**
    * { inheritDoc}
    */
   public override HashTable<string, Persona> personas
@@ -81,98 +94,111 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore
    */
   public override async void prepare ()
     {
-      string filename = this.file.get_path ();
-      this.key_file = new GLib.KeyFile ();
-
-      /* Load or create the file */
-      while (true)
+      lock (this._is_prepared)
         {
-          /* Load the file; if this fails due to the file not existing or having
-           * been deleted in the meantime, we can continue below and try to
-           * create it instead. */
-          try
+          if (!this._is_prepared)
             {
-              string contents = null;
-              size_t length = 0;
+              string filename = this.file.get_path ();
+              this.key_file = new GLib.KeyFile ();
 
-              yield this.file.load_contents_async (null, out contents,
-                  out length);
-              if (length > 0)
+              /* Load or create the file */
+              while (true)
                 {
-                  this.key_file.load_from_data (contents, length,
-                      KeyFileFlags.KEEP_COMMENTS);
+                  /* Load the file; if this fails due to the file not existing
+                   * or having been deleted in the meantime, we can continue
+                   * below and try to create it instead. */
+                  try
+                    {
+                      string contents = null;
+                      size_t length = 0;
+
+                      yield this.file.load_contents_async (null, out contents,
+                          out length);
+                      if (length > 0)
+                        {
+                          this.key_file.load_from_data (contents, length,
+                              KeyFileFlags.KEEP_COMMENTS);
+                        }
+                      break;
+                    }
+                  catch (Error e1)
+                    {
+                      if (!(e1 is IOError.NOT_FOUND))
+                        {
+                          warning ("The relationship key file '%s' could " +
+                              "not be loaded: %s", filename, e1.message);
+                          this.removed ();
+                          return;
+                        }
+                    }
+
+                  /* Ensure the parent directory tree exists for the new file */
+                  File parent_dir = this.file.get_parent ();
+
+                  try
+                    {
+                      /* Recursively create the directory */
+                      parent_dir.make_directory_with_parents ();
+                    }
+                  catch (Error e3)
+                    {
+                      if (!(e3 is IOError.EXISTS))
+                        {
+                          warning ("The relationship key file directory " +
+                              "'%s' could not be created: %s",
+                              parent_dir.get_path (), e3.message);
+                          this.removed ();
+                          return;
+                        }
+                    }
+
+                  /* Create a new file; if this fails due to the file having
+                   * been created in the meantime, we can loop back round and
+                   * try and load it. */
+                  try
+                    {
+                      /* Create the file */
+                      FileOutputStream stream = yield this.file.create_async (
+                          FileCreateFlags.PRIVATE, Priority.DEFAULT);
+                      yield stream.close_async (Priority.DEFAULT);
+                    }
+                  catch (Error e2)
+                    {
+                      if (!(e2 is IOError.EXISTS))
+                        {
+                          warning ("The relationship key file '%s' could " +
+                              "not be created: %s", filename, e2.message);
+                          this.removed ();
+                          return;
+                        }
+                    }
                 }
-              break;
-            }
-          catch (Error e1)
-            {
-              if (!(e1 is IOError.NOT_FOUND))
-                {
-                  warning ("The relationship key file '%s' could not be " +
-                      "loaded: %s", filename, e1.message);
-                  this.removed ();
-                  return;
-                }
-            }
-
-          /* Ensure the parent directory tree exists for the new file */
-          File parent_dir = this.file.get_parent ();
 
-          try
-            {
-              /* Recursively create the directory */
-              parent_dir.make_directory_with_parents ();
-            }
-          catch (Error e3)
-            {
-              if (!(e3 is IOError.EXISTS))
+              /* We've loaded or created a key file by now, so cycle through the
+               * groups: each group is a persona which we have to create and
+               * emit */
+              string[] groups = this.key_file.get_groups ();
+              foreach (string persona_id in groups)
                 {
-                  warning ("The relationship key file directory '%s' could " +
-                      "not be created: %s", parent_dir.get_path (), e3.message);
-                  this.removed ();
-                  return;
+                  if (persona_id.to_int () == this.first_unused_id)
+                    this.first_unused_id++;
+
+                  Persona persona = new Kf.Persona (this.key_file, persona_id,
+                      this);
+                  this._personas.insert (persona.iid, persona);
                 }
-            }
 
-          /* Create a new file; if this fails due to the file having been
-           * created in the meantime, we can loop back round and try and load
-           * it. */
-          try
-            {
-              /* Create the file */
-              FileOutputStream stream = yield this.file.create_async (
-                  FileCreateFlags.PRIVATE, Priority.DEFAULT);
-              yield stream.close_async (Priority.DEFAULT);
-            }
-          catch (Error e2)
-            {
-              if (!(e2 is IOError.EXISTS))
+              if (this._personas.size () > 0)
                 {
-                  warning ("The relationship key file '%s' could not be " +
-                      "created: %s", filename, e2.message);
-                  this.removed ();
-                  return;
+                  /* FIXME: Groupable.ChangeReason is not the right enum to use
+                   * here */
+                  this.personas_changed (this._personas.get_values (), null,
+                      null, null, Groupable.ChangeReason.NONE);
                 }
-            }
-        }
-
-      /* We've loaded or created a key file by now, so cycle through the groups:
-       * each group is a persona which we have to create and emit */
-      string[] groups = this.key_file.get_groups ();
-      foreach (string persona_id in groups)
-        {
-          if (persona_id.to_int () == this.first_unused_id)
-            this.first_unused_id++;
 
-          Persona persona = new Kf.Persona (this.key_file, persona_id, this);
-          this._personas.insert (persona.iid, persona);
-        }
-
-      if (this._personas.size () > 0)
-        {
-          /* FIXME: Groupable.ChangeReason is not the right enum to use here */
-          this.personas_changed (this._personas.get_values (), null, null, null,
-              Groupable.ChangeReason.NONE);
+              this._is_prepared = true;
+              this.notify_property ("is-prepared");
+            }
         }
     }
 
diff --git a/backends/telepathy/lib/tpf-persona-store.vala b/backends/telepathy/lib/tpf-persona-store.vala
index 0dedb92..c03f1d1 100644
--- a/backends/telepathy/lib/tpf-persona-store.vala
+++ b/backends/telepathy/lib/tpf-persona-store.vala
@@ -56,6 +56,7 @@ public class Tpf.PersonaStore : Folks.PersonaStore
   private AccountManager account_manager;
   private Logger logger;
   private Contact self_contact;
+  private bool _is_prepared = false;
 
   internal signal void group_members_changed (string group,
       GLib.List<Persona>? added, GLib.List<Persona>? removed);
@@ -92,6 +93,18 @@ public class Tpf.PersonaStore : Folks.PersonaStore
   public override string id { get; private set; }
 
   /**
+   * Whether this PersonaStore has been prepared.
+   *
+   * See { link Folks.PersonaStore.is_prepared}.
+   *
+   * @since 0.3.0
+   */
+  public override bool is_prepared
+    {
+      get { return this._is_prepared; }
+    }
+
+  /**
    * The { link Persona}s exposed by this PersonaStore.
    *
    * See { link Folks.PersonaStore.personas}.
@@ -155,64 +168,76 @@ public class Tpf.PersonaStore : Folks.PersonaStore
    */
   public override async void prepare ()
     {
-      this.account_manager = AccountManager.dup ();
-
-      this.account_manager.account_disabled.connect ((a) =>
-        {
-          if (this.account == a)
-            {
-              this.personas_changed (null, this._personas.get_values (), null,
-                  null, 0);
-              this.removed ();
-            }
-        });
-      this.account_manager.account_removed.connect ((a) =>
-        {
-          if (this.account == a)
-            {
-              this.personas_changed (null, this._personas.get_values (), null,
-                  null, 0);
-              this.removed ();
-            }
-        });
-      this.account_manager.account_validity_changed.connect ((a, valid) =>
+      lock (this._is_prepared)
         {
-          if (!valid && this.account == a)
+          if (!this._is_prepared)
             {
-              this.personas_changed (null, this._personas.get_values (), null,
-                  null, 0);
-              this.removed ();
-            }
-        });
+              this.account_manager = AccountManager.dup ();
 
-      this.account.status_changed.connect (this.account_status_changed_cb);
+              this.account_manager.account_disabled.connect ((a) =>
+                {
+                  if (this.account == a)
+                    {
+                      this.personas_changed (null, this._personas.get_values (),
+                        null, null, 0);
+                      this.removed ();
+                    }
+                });
+              this.account_manager.account_removed.connect ((a) =>
+                {
+                  if (this.account == a)
+                    {
+                      this.personas_changed (null, this._personas.get_values (),
+                        null, null, 0);
+                      this.removed ();
+                    }
+                });
+              this.account_manager.account_validity_changed.connect (
+                  (a, valid) =>
+                    {
+                      if (!valid && this.account == a)
+                        {
+                          this.personas_changed (null, this._personas.get_values
+                            (), null, null, 0);
+                          this.removed ();
+                        }
+                    });
+
+              this.account.status_changed.connect (
+                  this.account_status_changed_cb);
+
+              TelepathyGLib.ConnectionStatusReason reason;
+              var status = this.account.get_connection_status (out reason);
+              /* immediately handle accounts which are not currently being
+               * disconnected */
+              if (status != TelepathyGLib.ConnectionStatus.DISCONNECTED)
+                {
+                  this.account_status_changed_cb (
+                      TelepathyGLib.ConnectionStatus.DISCONNECTED, status,
+                      reason, null, null);
+                }
 
-      TelepathyGLib.ConnectionStatusReason reason;
-      var status = this.account.get_connection_status (out reason);
-      /* immediately handle accounts which are not currently being disconnected
-       */
-      if (status != TelepathyGLib.ConnectionStatus.DISCONNECTED)
-        {
-          this.account_status_changed_cb (
-              TelepathyGLib.ConnectionStatus.DISCONNECTED, status, reason, null,
-              null);
-        }
+              try
+                {
+                  this.logger = new Logger (this.id);
+                  this.logger.invalidated.connect (() =>
+                    {
+                      warning ("lost connection to the telepathy-logger " +
+                        "service");
+                      this.logger = null;
+                    });
+                  this.logger.favourite_contacts_changed.connect (
+                      this.favourite_contacts_changed_cb);
+                }
+              catch (DBus.Error e)
+                {
+                  warning ("couldn't connect to the telepathy-logger service");
+                  this.logger = null;
+                }
 
-      try
-        {
-          this.logger = new Logger (this.id);
-          this.logger.invalidated.connect (() =>
-            {
-              warning ("lost connection to the telepathy-logger service");
-              this.logger = null;
-            });
-          this.logger.favourite_contacts_changed.connect (
-              this.favourite_contacts_changed_cb);
-        }
-      catch (DBus.Error e)
-        {
-          warning ("couldn't connect to the telepathy-logger service");
-          this.logger = null;
+              this._is_prepared = true;
+              this.notify_property ("is-prepared");
+            }
         }
     }
 
diff --git a/folks/persona-store.vala b/folks/persona-store.vala
index 2d865ef..a04c60c 100644
--- a/folks/persona-store.vala
+++ b/folks/persona-store.vala
@@ -175,6 +175,14 @@ public abstract class Folks.PersonaStore : Object
    */
   public abstract HashTable<string, Persona> personas { get; }
 
+  /**
+   * Whether { link PersonaStore.prepare} has successfully completed for this
+   * store.
+   *
+   * @since 0.3.0
+   */
+  public abstract bool is_prepared { get; default = false; }
+
    /**
    * Whether the PersonaStore is writeable.
    *
@@ -216,6 +224,8 @@ public abstract class Folks.PersonaStore : Object
    *
    * If this function throws an error, the PersonaStore will not be functional.
    *
+   * This function is guaranteed to be idempotent (since version 0.3.0).
+   *
    * @since 0.1.11
    */
   public abstract async void prepare () throws GLib.Error;



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