summaryrefslogtreecommitdiff
path: root/worker
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 /worker
parent6f8c167e2782cb4447f36f0a9415a0fd1482b027 (diff)
downloadaerc-c605ada3ddc7569ebfc153b07db12a21b30d0569.zip
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>
Diffstat (limited to 'worker')
-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 0f1c38d..4e6bc52 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()
+ }
}
}
}