[geary/wip/362-utf8-attachments: 5/8] Reduce blocking the main thread when sending email



commit 3dc5476fcda56bd89ab7fb653b281241a3f3e004
Author: Michael Gratton <mike vee net>
Date:   Fri Jul 19 16:49:43 2019 +1000

    Reduce blocking the main thread when sending email
    
    Make guessing charset and encoding work on a background thread when
    constructing RFC822.Message instances from ComposedEmail.

 src/engine/rfc822/rfc822-message.vala |  8 ++++--
 src/engine/rfc822/rfc822-utils.vala   | 47 ++++++++++++++++++++++++-----------
 2 files changed, 38 insertions(+), 17 deletions(-)
---
diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala
index 0550aa80..6b335bd5 100644
--- a/src/engine/rfc822/rfc822-message.vala
+++ b/src/engine/rfc822/rfc822-message.vala
@@ -1070,12 +1070,16 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         throws GLib.Error {
         GMime.Stream content_stream = new GMime.StreamMem.with_buffer(content);
         if (charset == null) {
-            charset = Geary.RFC822.Utils.get_best_charset(content_stream);
+            charset = yield Utils.get_best_charset(content_stream, cancellable);
         }
         GMime.StreamFilter filter_stream = new GMime.StreamFilter(content_stream);
         filter_stream.add(new GMime.FilterCharset(UTF8_CHARSET, charset));
         if (encoding == null) {
-            encoding = Geary.RFC822.Utils.get_best_encoding(filter_stream);
+            encoding = yield Utils.get_best_encoding(
+                filter_stream,
+                GMime.EncodingConstraint.7BIT,
+                cancellable
+            );
         }
         if (is_flowed && encoding == GMime.ContentEncoding.BASE64) {
             // Base64-encoded text needs to have CR's added after LF's
diff --git a/src/engine/rfc822/rfc822-utils.vala b/src/engine/rfc822/rfc822-utils.vala
index dfa4180e..55a92061 100644
--- a/src/engine/rfc822/rfc822-utils.vala
+++ b/src/engine/rfc822/rfc822-utils.vala
@@ -254,37 +254,54 @@ public string to_preview_text(string? text, TextFormat format) {
 /**
  * Uses a GMime.FilterBest to determine the best charset.
  *
- * WARNING: This call does not perform async I/O, meaning it will loop on the
- * stream without relinquishing control to the event loop.  Use with
- * caution.
+ * This may require processing the entire stream, so occurs in a
+ * background thread.
  */
-public string get_best_charset(GMime.Stream in_stream) {
+public async string get_best_charset(GMime.Stream in_stream,
+                                     GLib.Cancellable? cancellable)
+    throws GLib.Error {
     GMime.FilterBest filter = new GMime.FilterBest(
         GMime.FilterBestFlags.CHARSET
     );
-    GMime.StreamFilter out_stream = new GMime.StreamFilter(new GMime.StreamNull());
+    GMime.StreamFilter out_stream = new GMime.StreamFilter(
+        new GMime.StreamNull()
+    );
     out_stream.add(filter);
-    in_stream.write_to_stream(out_stream);
-    in_stream.reset();
+
+    yield Nonblocking.Concurrent.global.schedule_async(() => {
+            in_stream.write_to_stream(out_stream);
+            in_stream.reset();
+        },
+        cancellable
+    );
     return filter.charset();
 }
 
 /**
  * Uses a GMime.FilterBest to determine the best encoding.
  *
- * WARNING: This call does not perform async I/O, meaning it will loop on the
- * stream without relinquishing control to the event loop.  Use with
- * caution.
+ * This may require processing the entire stream, so occurs in a
+ * background thread.
  */
-public GMime.ContentEncoding get_best_encoding(GMime.Stream in_stream) {
+public async GMime.ContentEncoding get_best_encoding(GMime.Stream in_stream,
+                                                     GMime.EncodingConstraint constraint,
+                                                     GLib.Cancellable? cancellable)
+    throws GLib.Error {
     GMime.FilterBest filter = new GMime.FilterBest(
         GMime.FilterBestFlags.ENCODING
     );
-    GMime.StreamFilter out_stream = new GMime.StreamFilter(new GMime.StreamNull());
+    GMime.StreamFilter out_stream = new GMime.StreamFilter(
+        new GMime.StreamNull()
+    );
     out_stream.add(filter);
-    in_stream.write_to_stream(out_stream);
-    in_stream.reset();
-    return filter.encoding(GMime.EncodingConstraint.7BIT);
+
+    yield Nonblocking.Concurrent.global.schedule_async(() => {
+            in_stream.write_to_stream(out_stream);
+            in_stream.reset();
+        },
+        cancellable
+    );
+    return filter.encoding(constraint);
 }
 
 }


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