[geary/wip/131-sent-mail: 4/14] Make remote folder synchronisation a top-level API method



commit 6871c1cd902d1515fabe1d4337dbf30ab95f67e8
Author: Michael Gratton <mike vee net>
Date:   Thu Aug 8 23:00:42 2019 +1000

    Make remote folder synchronisation a top-level API method
    
    Add Geary.Folder::synchronise_remote method to allow clients to
    explicitly check for new mail in a folder. Move code from
    ImapEngine.AccountSynchronizer as the basic implementation, but also
    ensure pending replay queue notifications are processed before the
    process is complete.

 src/engine/api/geary-abstract-local-folder.vala    |  7 ++++-
 src/engine/api/geary-folder.vala                   | 13 +++++++++
 .../imap-engine-account-synchronizer.vala          | 31 +++++-----------------
 .../imap-engine/imap-engine-minimal-folder.vala    | 24 ++++++++++++++++-
 test/engine/api/geary-folder-mock.vala             |  5 ++++
 5 files changed, 53 insertions(+), 27 deletions(-)
---
diff --git a/src/engine/api/geary-abstract-local-folder.vala b/src/engine/api/geary-abstract-local-folder.vala
index afc3fe7a..e8217328 100644
--- a/src/engine/api/geary-abstract-local-folder.vala
+++ b/src/engine/api/geary-abstract-local-folder.vala
@@ -60,5 +60,10 @@ public abstract class Geary.AbstractLocalFolder : Geary.Folder {
     public override async void wait_for_close_async(Cancellable? cancellable = null) throws Error {
         yield closed_semaphore.wait_async(cancellable);
     }
-}
 
+    public override async void synchronise_remote(GLib.Cancellable? cancellable)
+        throws GLib.Error {
+        // No-op
+    }
+
+}
diff --git a/src/engine/api/geary-folder.vala b/src/engine/api/geary-folder.vala
index 948b925f..a7f4d7fe 100644
--- a/src/engine/api/geary-folder.vala
+++ b/src/engine/api/geary-folder.vala
@@ -580,6 +580,19 @@ public abstract class Geary.Folder : BaseObject, Loggable {
      */
     public abstract async void wait_for_close_async(Cancellable? cancellable = null) throws Error;
 
+    /**
+     * Synchronises the local folder with the remote mailbox.
+     *
+     * If backed by a remote folder, this ensures that the end of the
+     * vector is up to date with the end of the remote mailbox, and
+     * that all messages in the vector satisfy the minimum
+     * requirements for being used by the engine.
+     *
+     * The folder must be opened prior to attempting this operation.
+     */
+    public abstract async void synchronise_remote(GLib.Cancellable? cancellable)
+        throws GLib.Error;
+
     /**
      * List a number of contiguous emails in the folder's vector.
      *
diff --git a/src/engine/imap-engine/imap-engine-account-synchronizer.vala 
b/src/engine/imap-engine/imap-engine-account-synchronizer.vala
index 86098608..4e1b0692 100644
--- a/src/engine/imap-engine/imap-engine-account-synchronizer.vala
+++ b/src/engine/imap-engine/imap-engine-account-synchronizer.vala
@@ -114,12 +114,7 @@ private class Geary.ImapEngine.RefreshFolderSync : FolderOperation {
         bool was_opened = false;
         MinimalFolder minimal = (MinimalFolder) this.folder;
         try {
-            // Open the folder on no delay since there's no point just
-            // waiting around for it. Then claim a remote session so
-            // we know that a remote connection has been made and the
-            // folder has had a chance to normalise itself.
             yield minimal.open_async(Folder.OpenFlags.NO_DELAY, cancellable);
-            yield minimal.claim_remote_session(cancellable);
             was_opened = true;
             debug("Synchronising %s", minimal.to_string());
             yield sync_folder(cancellable);
@@ -169,24 +164,9 @@ private class Geary.ImapEngine.RefreshFolderSync : FolderOperation {
         }
     }
 
-    protected virtual async void sync_folder(Cancellable cancellable)
-        throws Error {
-        yield wait_for_prefetcher(cancellable);
-    }
-
-    protected async void wait_for_prefetcher(Cancellable cancellable)
-        throws Error {
-        MinimalFolder minimal = (MinimalFolder) this.folder;
-        try {
-            yield minimal.email_prefetcher.active_sem.wait_async(cancellable);
-        } catch (Error err) {
-            Logging.debug(
-                Logging.Flag.PERIODIC,
-                "Error waiting for email prefetcher to complete %s: %s",
-                folder.to_string(),
-                err.message
-            );
-        }
+    protected virtual async void sync_folder(GLib.Cancellable cancellable)
+        throws GLib.Error {
+        yield this.folder.synchronise_remote(cancellable);
     }
 
 }
@@ -289,8 +269,9 @@ private class Geary.ImapEngine.CheckFolderSync : RefreshFolderSync {
                 next_epoch = prefetch_max_epoch.add_days(-1);
             }
 
-            // let the prefetcher catch up
-            yield wait_for_prefetcher(cancellable);
+            // Wait for basic syncing (i.e. the prefetcher) to
+            // complete as well.
+            yield base.sync_folder(cancellable);
         }
     }
 
diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala 
b/src/engine/imap-engine/imap-engine-minimal-folder.vala
index 7a0b6c54..80d4695f 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -65,12 +65,12 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
     internal ImapDB.Folder local_folder { get; private set; }
 
     internal ReplayQueue? replay_queue { get; private set; default = null; }
-    internal EmailPrefetcher email_prefetcher { get; private set; }
     internal ContactHarvester harvester { get; private set; }
 
     private weak GenericAccount _account;
     private Geary.AggregatedFolderProperties _properties =
         new Geary.AggregatedFolderProperties(false, false);
+    private EmailPrefetcher email_prefetcher;
 
     private int open_count = 0;
     private Folder.OpenFlags open_flags = OpenFlags.NONE;
@@ -278,6 +278,28 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         yield this.closed_semaphore.wait_async(cancellable);
     }
 
+    /** {@inheritDoc} */
+    public override async void synchronise_remote(GLib.Cancellable? cancellable)
+        throws GLib.Error {
+        check_open("synchronise_remote");
+        // The normalisation process will pick up any missing messages
+        // if closed so ensure there is a remote session
+        Imap.FolderSession remote = yield claim_remote_session(cancellable);
+
+        // Send a NOOP so the server can return an untagged EXISTS if
+        // any new messages have arrived since the remote was opened.
+        yield remote.send_noop(cancellable);
+
+        // Wait until the replay queue has processed all notifications
+        // so the prefetcher becomes aware of the new mail
+        this.replay_queue.flush_notifications();
+        yield this.replay_queue.checkpoint(cancellable);
+
+        // Finally, wait for the prefetcher to have finished
+        // downloading the new mail.
+        yield this.email_prefetcher.active_sem.wait_async(cancellable);
+    }
+
     // used by normalize_folders() during the normalization process; should not be used elsewhere
     private async void detach_all_emails_async(Cancellable? cancellable) throws Error {
         Gee.List<Email>? all = yield local_folder.list_email_by_id_async(null, -1,
diff --git a/test/engine/api/geary-folder-mock.vala b/test/engine/api/geary-folder-mock.vala
index e663341a..29856044 100644
--- a/test/engine/api/geary-folder-mock.vala
+++ b/test/engine/api/geary-folder-mock.vala
@@ -78,6 +78,11 @@ public class Geary.MockFolder : Folder, MockObject {
         throw new EngineError.UNSUPPORTED("Mock method");
     }
 
+    public override async void synchronise_remote(GLib.Cancellable? cancellable)
+        throws GLib.Error {
+        void_call("synchronise_remote", { cancellable });
+    }
+
     public override async Gee.List<Geary.Email>?
         list_email_by_id_async(Geary.EmailIdentifier? initial_id,
                                int count,


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