[geary/wip/543-append-failure] Write literal data in chunks when sending to server



commit e3eef7153c9d3212678d3ed8cfa8fb6043168d56
Author: Michael Gratton <mike vee net>
Date:   Thu Aug 29 23:13:48 2019 +1000

    Write literal data in chunks when sending to server
    
    By splitting literal writes into apprpriately sized chunks, the
    command's response timer can be updated so that the command doesn't
    fail due to a timeout as large values are being sent.
    
    Fixes #543

 src/engine/imap/command/imap-command.vala | 42 ++++++++++++++++++++++++++++---
 1 file changed, 39 insertions(+), 3 deletions(-)
---
diff --git a/src/engine/imap/command/imap-command.vala b/src/engine/imap/command/imap-command.vala
index d4e8a57e..937d78ea 100644
--- a/src/engine/imap/command/imap-command.vala
+++ b/src/engine/imap/command/imap-command.vala
@@ -181,9 +181,45 @@ public class Geary.Imap.Command : BaseObject {
                     debug("Waiting for continuation");
                     yield this.literal_spinlock.wait_async(cancellable);
                     debug("Got continuation");
-                    yield ser.push_literal_data(
-                        literal.value.get_uint8_array(), cancellable
-                    );
+
+                    // Buffer size is dependent on timeout, since we
+                    // need to ensure we can send a full buffer before
+                    // the timeout is up. v.92 56k baud modems have
+                    // theoretical max upload of 48kbit/s and GSM 2G
+                    // 40kbit/s, but typical is usually well below
+                    // that, so assume a low end of 1kbyte/s. Hence
+                    // buffer size needs to be less than or equal to
+                    // (response_timeout * 1)k, rounded down to the
+                    // nearest power of two.
+                    uint buf_size = 1;
+                    while (buf_size <= this.response_timeout) {
+                        buf_size <<= 1;
+                    }
+                    buf_size >>= 1;
+
+                    uint8[] buf = new uint8[buf_size * 1024];
+                    GLib.InputStream data = literal.value.get_input_stream();
+                    try {
+                        while (!data.is_closed()) {
+                            size_t read;
+                            yield data.read_all_async(
+                                buf, Priority.DEFAULT, cancellable, out read
+                            );
+                            if (read <= 0) {
+                                break;
+                            }
+
+                            buf.length = (int) read;
+                            yield ser.push_literal_data(buf, cancellable);
+                            this.response_timer.start();
+                        }
+                    } finally {
+                        try {
+                            yield data.close_async();
+                        } catch (GLib.Error err) {
+                            // Oh well
+                        }
+                    }
                 }
             }
         }


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