[geary/wip/17-noisy-problem-reports: 3/12] Provide common account and service status tracking via Account



commit 20447c814f5757f976ce53df4f714297b47e775e
Author: Michael Gratton <mike vee net>
Date:   Sun Dec 30 11:32:03 2018 +1100

    Provide common account and service status tracking via Account
    
    Similarly to ClientService, add a `current_status` property that denotes
    the account's operational state, so that clients can just set a notify
    on that to be informed of all account status changes. Keep the property
    updated by watching for changes to the client service's status property.

 src/engine/api/geary-account.vala                  | 89 +++++++++++++++++++---
 src/engine/api/geary-client-service.vala           | 15 ++++
 .../imap-engine/imap-engine-generic-account.vala   | 44 +++++------
 src/engine/smtp/smtp-client-service.vala           |  6 +-
 test/engine/api/geary-account-mock.vala            | 35 +++------
 5 files changed, 126 insertions(+), 63 deletions(-)
---
diff --git a/src/engine/api/geary-account.vala b/src/engine/api/geary-account.vala
index d381208a..f54b3cbe 100644
--- a/src/engine/api/geary-account.vala
+++ b/src/engine/api/geary-account.vala
@@ -27,32 +27,73 @@ public abstract class Geary.Account : BaseObject {
     internal const uint AUTH_ATTEMPTS_MAX = 3;
 
 
-    /**
+     /**
+     * Denotes the account's current status.
+     *
+     * @see Account.current_status
+     * @see ClientService.current_status
+     */
+    [Flags]
+    public enum Status {
+
+        /**
+         * The account is currently online and operating normally.
+         *
+         * This flags will be set when the account's {@link incoming}
+         * service's {@link ClientService.current_status} is {@link
+         * ClientService.Status.CONNECTED}.
+         */
+        ONLINE,
+
+        /**
+         * One or of the account's services is degraded.
+         *
+         * This flag will be set when one or both of its services has
+         * encountered a problem. Consult the {@link
+         * ClientService.current_status} to determine which and the
+         * exact problem.
+         */
+        SERVICE_PROBLEM;
+
+
+        /** Determines if the {@link ONLINE} flag is set. */
+        public bool is_online() {
+            return (this & ONLINE) == ONLINE;
+        }
+
+        /** Determines if the {@link SERVICE_PROBLEM} flag is set. */
+        public bool has_service_problem() {
+            return (this & SERVICE_PROBLEM) == SERVICE_PROBLEM;
+        }
+
+    }
+
+
+   /**
      * The account's current configuration.
      */
     public AccountInformation information { get; protected set; }
 
     /**
-     * Determines if this account appears to be online.
+     * The account's current status.
      *
-     * This property is true if the account is to the best of the
-     * engine's knowledge is online, i.e. it is enabled, has been able
-     * to connect to the remote incoming mail server, and so on. Some
-     * network problems are not immediately obvious however, and so at
-     * times the value of this property may be inaccurate. At best it
-     * should be treated as a heuristic.
+     * This property's value is set based on the {@link
+     * ClientService.current_status} of the account's {@link incoming}
+     * and {@link outgoing} services. if
+     *
+     * @see ClientService.current_status
      */
-    public abstract bool is_online { get; protected set; }
+    public Status current_status { get; protected set; default = 0; }
 
     /**
      * The service manager for the incoming email service.
      */
-    public abstract ClientService incoming { get; }
+    public ClientService incoming { get; private set; }
 
     /**
      * The service manager for the outgoing email service.
      */
-    public abstract ClientService outgoing { get; }
+    public ClientService outgoing { get; private set; }
 
     public Geary.ProgressMonitor search_upgrade_monitor { get; protected set; }
     public Geary.ProgressMonitor db_upgrade_monitor { get; protected set; }
@@ -174,11 +215,22 @@ public abstract class Geary.Account : BaseObject {
         Gee.Map<Geary.EmailIdentifier, Geary.EmailFlags> map);
 
 
-    protected Account(AccountInformation information) {
+    protected Account(AccountInformation information,
+                      ClientService incoming,
+                      ClientService outgoing) {
         this.information = information;
+        this.incoming = incoming;
+        this.outgoing = outgoing;
         this.id = "%s[%s]".printf(
             information.id, information.service_provider.to_value()
         );
+
+        incoming.notify["current-status"].connect(
+            on_service_status_notify
+        );
+        outgoing.notify["current-status"].connect(
+            on_service_status_notify
+        );
     }
 
     /**
@@ -478,4 +530,17 @@ public abstract class Geary.Account : BaseObject {
         );
     }
 
+    private void on_service_status_notify() {
+        Status new_status = 0;
+        if (incoming.current_status != UNKNOWN &&
+            incoming.current_status != UNREACHABLE) {
+            new_status |= ONLINE;
+        }
+        if (incoming.current_status.is_error() ||
+            outgoing.current_status.is_error()) {
+            new_status |= SERVICE_PROBLEM;
+        }
+        this.current_status = new_status;
+    }
+
 }
diff --git a/src/engine/api/geary-client-service.vala b/src/engine/api/geary-client-service.vala
index 8cd879b3..1c72df46 100644
--- a/src/engine/api/geary-client-service.vala
+++ b/src/engine/api/geary-client-service.vala
@@ -25,6 +25,7 @@ public abstract class Geary.ClientService : BaseObject {
      * Denotes the service's current status.
      *
      * @see ClientService.current_status
+     * @see Account.current_status
      */
     public enum Status {
 
@@ -109,6 +110,18 @@ public abstract class Geary.ClientService : BaseObject {
             );
         }
 
+        /**
+         * Determines the current status is an error condition.
+         *
+         * Returns true if not offline or connected.
+         */
+        public bool is_error() {
+            return (
+                this != OFFLINE &&
+                this != CONNECTED
+            );
+        }
+
         public string to_value() {
             return ObjectUtils.to_enum_nick<Status>(typeof(Status), this);
         }
@@ -144,6 +157,8 @@ public abstract class Geary.ClientService : BaseObject {
      * (e.g. online/offline state may not be fully known, and hence
      * the value of this property reflects the engine's current
      * understanding of the service's status, not necessarily reality.
+     *
+     * @see Account.current_status
      */
     public Status current_status { get; protected set; default = OFFLINE; }
 
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala 
b/src/engine/imap-engine/imap-engine-generic-account.vala
index 97dbdc27..123e0ca1 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -25,14 +25,6 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
         Geary.SpecialFolderType.ARCHIVE,
     };
 
-    public override bool is_online { get; protected set; default = false; }
-
-    /** Returns the IMAP client service. */
-    public override ClientService incoming { get { return this.imap; } }
-
-    /** Returns the SMTP client service. */
-    public override ClientService outgoing { get { return this.smtp; } }
-
     /** Service for incoming IMAP connections. */
     public Imap.ClientService imap  { get; private set; }
 
@@ -64,26 +56,32 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
                           ImapDB.Account local,
                           Endpoint incoming_remote,
                           Endpoint outgoing_remote) {
-        base(config);
+        Imap.ClientService imap = new Imap.ClientService(
+            config,
+            config.incoming,
+            incoming_remote
+        );
+        Smtp.ClientService smtp = new Smtp.ClientService(
+            config,
+            config.outgoing,
+            outgoing_remote
+        );
+
+        base(config, imap, smtp);
+
         this.local = local;
         this.local.contacts_loaded.connect(() => { contacts_loaded(); });
 
-        this.imap = new Imap.ClientService(
-            config, config.incoming, incoming_remote
-        );
-        this.imap.min_pool_size = IMAP_MIN_POOL_SIZE;
-        this.imap.notify["current-status"].connect(
+        imap.min_pool_size = IMAP_MIN_POOL_SIZE;
+        imap.notify["current-status"].connect(
             on_imap_status_notify
         );
+        this.imap = imap;
 
-        this.smtp = new Smtp.ClientService(
-            config,
-            config.outgoing,
-            outgoing_remote,
-            new Outbox.Folder(this, this.local)
-        );
-        this.smtp.email_sent.connect(on_email_sent);
-        this.smtp.report_problem.connect(notify_report_problem);
+        smtp.outbox = new Outbox.Folder(this, local);
+        smtp.email_sent.connect(on_email_sent);
+        smtp.report_problem.connect(notify_report_problem);
+        this.smtp = smtp;
 
         this.sync = new AccountSynchronizer(this);
 
@@ -994,11 +992,9 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
     private void on_imap_status_notify() {
         if (this.open) {
             if (this.imap.current_status == CONNECTED) {
-                this.is_online = true;
                 this.remote_ready_lock.blind_notify();
                 update_remote_folders();
             } else {
-                this.is_online = false;
                 this.remote_ready_lock.reset();
                 this.refresh_folder_timer.reset();
             }
diff --git a/src/engine/smtp/smtp-client-service.vala b/src/engine/smtp/smtp-client-service.vala
index a6027a24..58b93634 100644
--- a/src/engine/smtp/smtp-client-service.vala
+++ b/src/engine/smtp/smtp-client-service.vala
@@ -23,7 +23,7 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
 
 
     /** Folder used for storing and retrieving queued mail. */
-    public Outbox.Folder outbox { get; private set; }
+    public Outbox.Folder? outbox { get; internal set; default = null; }
 
     /** Progress monitor indicating when email is being sent. */
     public ProgressMonitor sending_monitor {
@@ -47,10 +47,8 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
 
     public ClientService(AccountInformation account,
                          ServiceInformation service,
-                         Endpoint remote,
-                         Outbox.Folder outbox) {
+                         Endpoint remote) {
         base(account, service, remote);
-        this.outbox = outbox;
     }
 
     /**
diff --git a/test/engine/api/geary-account-mock.vala b/test/engine/api/geary-account-mock.vala
index b9274e9e..6b2b76df 100644
--- a/test/engine/api/geary-account-mock.vala
+++ b/test/engine/api/geary-account-mock.vala
@@ -19,7 +19,7 @@ public class Geary.MockAccount : Account, MockObject {
     public class MockContactStore : ContactStore {
 
         internal MockContactStore() {
-            
+
         }
 
         public override async void
@@ -60,34 +60,23 @@ public class Geary.MockAccount : Account, MockObject {
     }
 
 
-    public override bool is_online { get; protected set; default = false; }
-
-    public override ClientService incoming {
-        get { return this.incoming; }
-    }
-    private ClientService _incoming;
-
-    public override ClientService outgoing {
-        get { return this._outgoing; }
-    }
-    private ClientService _outgoing;
-
     protected Gee.Queue<ExpectedCall> expected {
         get; set; default = new Gee.LinkedList<ExpectedCall>();
     }
 
 
     public MockAccount(AccountInformation config) {
-        base(config);
-        this._incoming = new MockClientService(
-            config,
-            config.incoming,
-            new Endpoint(config.incoming.host, config.incoming.port, 0, 0)
-        );
-        this._outgoing = new MockClientService(
-            config,
-            config.outgoing,
-            new Endpoint(config.outgoing.host, config.outgoing.port, 0, 0)
+        base(config,
+             new MockClientService(
+                 config,
+                 config.incoming,
+                 new Endpoint(config.incoming.host, config.incoming.port, 0, 0)
+             ),
+             new MockClientService(
+                 config,
+                 config.outgoing,
+                 new Endpoint(config.outgoing.host, config.outgoing.port, 0, 0)
+             )
         );
     }
 


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