Commit 2c8a232f authored by Michael Gratton's avatar Michael Gratton 🤞

Ensure that cancelled commands throw a cancelled error, not a timeout

Commands that were cancelled, e.g. because the network connection was
lost and so commands in progress were backed out, were throwing
timeout errors to callers of wait_until_complete since they had received
no response. This was causing e.g. account operations to fail, and the
alleged timeout be reported as problem in the UI.

This takes note of whether a command was cancelled and throws an
appropriate error in wait_until_complete if so. Callers can then clean
up and choose to be more circumspect in their error reporting.

Fixes #285
parent ffe4775e
Pipeline #65919 passed with stages
in 19 minutes and 51 seconds
......@@ -79,6 +79,7 @@ public class Geary.Imap.Command : BaseObject {
new Geary.Nonblocking.Semaphore();
private bool timed_out = false;
private bool cancelled = false;
private Geary.Nonblocking.Spinlock? literal_spinlock = null;
private GLib.Cancellable? literal_cancellable = null;
......@@ -209,10 +210,12 @@ public class Geary.Imap.Command : BaseObject {
* Cancels this command's execution.
*
* When this method is called, all locks will be released,
* including {@link wait_until_complete}.
* including {@link wait_until_complete}, which will then throw a
* `GLib.IOError.CANCELLED` error.
*/
internal virtual void cancel_command() {
cancel_send();
this.cancelled = true;
this.response_timer.reset();
this.complete_lock.blind_notify();
}
......@@ -220,17 +223,23 @@ public class Geary.Imap.Command : BaseObject {
/**
* Yields until the command has been completed or cancelled.
*
* Throws an error if cancelled, if the command is cancelled, or
* if the command's response was bad.
* Throws an error if the command or the cancellable argument is
* cancelled, if the command timed out, or if the command's
* response was bad.
*/
public async void wait_until_complete(GLib.Cancellable cancellable)
throws GLib.Error {
yield this.complete_lock.wait_async(cancellable);
if (this.cancelled) {
throw new GLib.IOError.CANCELLED(
"%s: Command was cancelled", to_brief_string()
);
}
if (this.timed_out) {
throw new ImapError.TIMED_OUT(
"%s: No command response was received",
to_brief_string()
"%s: Command timed out", to_brief_string()
);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment