diff options
author | Robin Jarry <robin@jarry.cc> | 2021-12-06 23:53:39 +0100 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2022-01-14 21:17:40 +0100 |
commit | c605ada3ddc7569ebfc153b07db12a21b30d0569 (patch) | |
tree | 7c7ef223842521d131cbf08e699cdba76eb9da3f | |
parent | 6f8c167e2782cb4447f36f0a9415a0fd1482b027 (diff) | |
download | aerc-c605ada3ddc7569ebfc153b07db12a21b30d0569.tar.gz |
imap: attempt automatic reconnection on error
Attempt to reconnect to the server when there is an unexpected
disconnection or network error.
Use the Client.LoggedOut() channel which is closed when the connection
is closed.
This patch is rather flaky and is certainly bugged. However, it is
a start.
Signed-off-by: Robin Jarry <robin@jarry.cc>
-rw-r--r-- | worker/imap/worker.go | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/worker/imap/worker.go b/worker/imap/worker.go index 0f1c38d6..4e6bc52a 100644 --- a/worker/imap/worker.go +++ b/worker/imap/worker.go @@ -56,6 +56,10 @@ type IMAPWorker struct { worker *types.Worker // Map of sequence numbers to UIDs, index 0 is seq number 1 seqMap []uint32 + // automatic reconnect + loggingOut bool + loggedOut <-chan struct{} + reconnecting bool } func NewIMAPWorker(worker *types.Worker) (types.Backend, error) { @@ -69,7 +73,10 @@ func NewIMAPWorker(worker *types.Worker) (types.Backend, error) { func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { if w.client != nil && w.client.State() == imap.SelectedState { - close(w.idleStop) + if w.idleStop != nil { + close(w.idleStop) + w.idleStop = nil + } if err := <-w.idleDone; err != nil { w.worker.PostMessage(&types.Error{Error: err}, nil) } @@ -155,21 +162,27 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { } } case *types.Connect: - if w.client != nil && w.client.State() == imap.SelectedState { + if w.client != nil && w.client.State() == imap.SelectedState && !w.reconnecting { return fmt.Errorf("Already connected") } + w.loggingOut = false c, err := w.connect() if err != nil { + if !w.reconnecting { + go w.tryReconnect() + } return err } - c.Updates = w.updates + w.loggedOut = c.LoggedOut() w.client = &imapClient{c, sortthread.NewThreadClient(c), sortthread.NewSortClient(c)} w.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) case *types.Disconnect: + w.reconnecting = false if w.client == nil || w.client.State() != imap.SelectedState { return fmt.Errorf("Not connected") } + w.loggingOut = true if err := w.client.Logout(); err != nil { return err } @@ -378,6 +391,25 @@ func (w *IMAPWorker) setKeepaliveParameters(conn *net.TCPConn) error { return err } +func (w *IMAPWorker) tryReconnect() { + w.reconnecting = true + for w.reconnecting { + w.worker.Logger.Printf("IMAP reconnection in 2 seconds...\n") + time.Sleep(2 * time.Second) + c := make(chan types.WorkerMessage) + w.worker.PostAction(&types.Connect{}, func(m types.WorkerMessage) { + c <- m + }) + result := <-c + switch result.(type) { + case *types.Done: + w.reconnecting = false + case *types.Error: + w.worker.Logger.Printf("IMAP connection failed\n") + } + } +} + func (w *IMAPWorker) Run() { for { select { @@ -395,6 +427,12 @@ func (w *IMAPWorker) Run() { } case update := <-w.updates: w.handleImapUpdate(update) + case <-w.loggedOut: + w.loggedOut = nil + if !w.loggingOut && !w.reconnecting { + w.reconnecting = true + go w.tryReconnect() + } } } } |