send: don't block the UI thread during the sending

This commit is contained in:
Reto Brunner 2021-01-24 18:00:23 +01:00
parent 3720c86236
commit 9385827cae

View file

@ -13,7 +13,6 @@ import (
"github.com/emersion/go-sasl" "github.com/emersion/go-sasl"
"github.com/emersion/go-smtp" "github.com/emersion/go-smtp"
"github.com/google/shlex" "github.com/google/shlex"
"github.com/miolini/datacounter"
"github.com/pkg/errors" "github.com/pkg/errors"
"git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/lib"
@ -91,6 +90,16 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error {
rcpts: rcpts, rcpts: rcpts,
} }
// we don't want to block the UI thread while we are sending
// so we do everything in a goroutine and hide the composer from the user
aerc.RemoveTab(composer)
aerc.PushStatus("Sending...", 10*time.Second)
var copyBuf bytes.Buffer // for the Sent folder content if CopyTo is set
failCh := make(chan error)
//writer
go func() {
var sender io.WriteCloser var sender io.WriteCloser
switch ctx.scheme { switch ctx.scheme {
case "smtp": case "smtp":
@ -103,35 +112,25 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error {
sender, err = nil, fmt.Errorf("unsupported scheme %v", ctx.scheme) sender, err = nil, fmt.Errorf("unsupported scheme %v", ctx.scheme)
} }
if err != nil { if err != nil {
return errors.Wrap(err, "send:") failCh <- errors.Wrap(err, "send:")
} }
// if we copy via the worker we need to know the count var writer io.Writer = sender
counter := datacounter.NewWriterCounter(sender)
var writer io.Writer = counter
writer = counter
var copyBuf bytes.Buffer
if config.CopyTo != "" { if config.CopyTo != "" {
writer = io.MultiWriter(writer, &copyBuf) writer = io.MultiWriter(writer, &copyBuf)
} }
err = composer.WriteMessage(header, writer)
aerc.RemoveTab(composer)
aerc.PushStatus("Sending...", 10*time.Second)
ch := make(chan error)
go func() {
err := composer.WriteMessage(header, writer)
if err != nil { if err != nil {
ch <- err failCh <- err
return return
} }
ch <- sender.Close() failCh <- sender.Close()
}() }()
// we don't want to block the UI thread while we are sending //cleanup + copy to sent
go func() { go func() {
err = <-ch err = <-failCh
if err != nil { if err != nil {
aerc.PushError(err.Error()) aerc.PushError(err.Error())
aerc.NewTab(composer, tabName) aerc.NewTab(composer, tabName)
@ -139,9 +138,9 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error {
} }
if config.CopyTo != "" { if config.CopyTo != "" {
aerc.PushStatus("Copying to "+config.CopyTo, 10*time.Second) aerc.PushStatus("Copying to "+config.CopyTo, 10*time.Second)
errCh := copyToSent(composer.Worker(), config.CopyTo, errch := copyToSent(composer.Worker(), config.CopyTo,
int(counter.Count()), &copyBuf) copyBuf.Len(), &copyBuf)
err = <-errCh err = <-errch
if err != nil { if err != nil {
errmsg := fmt.Sprintf( errmsg := fmt.Sprintf(
"message sent, but copying to %v failed: %v", "message sent, but copying to %v failed: %v",