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



commit 4b84616d8263857f83cdbe53135a5d24ecc2b9d1
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 361bbca1..570fe3ba 100644
--- a/src/engine/imap/command/imap-command.vala
+++ b/src/engine/imap/command/imap-command.vala
@@ -178,9 +178,45 @@ public class Geary.Imap.Command : BaseObject {
                     // Will get notified via continuation_requested
                     // when server indicated the literal can be sent.
                     yield this.literal_spinlock.wait_async(cancellable);
-                    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 (true) {
+                            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]