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.
This commit is contained in:
Michael Gratton 2019-08-08 23:00:42 +10:00 committed by Michael James Gratton
parent ee11d0d8ec
commit 6871c1cd90
5 changed files with 53 additions and 27 deletions

View file

@ -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
}
}

View file

@ -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.
*

View file

@ -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);
}
}

View file

@ -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,

View file

@ -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,