aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2021-12-06 23:53:39 +0100
committerRobin Jarry <robin@jarry.cc>2022-01-14 21:17:40 +0100
commitc605ada3ddc7569ebfc153b07db12a21b30d0569 (patch)
tree7c7ef223842521d131cbf08e699cdba76eb9da3f
parent6f8c167e2782cb4447f36f0a9415a0fd1482b027 (diff)
downloadaerc-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.go44
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()
+ }
}
}
}