diff options
author | Robin Jarry <robin@jarry.cc> | 2024-01-27 21:36:25 +0100 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-01-31 16:08:45 +0100 |
commit | fd4dd42408856048dd71f83ae1f30e2ab84621da (patch) | |
tree | 6ae89fff21d1100d814249545170b7d572bb8740 | |
parent | 4998406cce859791013880ec5f8f402007a2d1bd (diff) | |
download | aerc-fd4dd42408856048dd71f83ae1f30e2ab84621da.tar.gz |
ipc: wait for app to be ready before accepting commands
Pass a cancellable context to the IPC server and defer accepting
connections until the first worker message has been received by the main
thread.
This is not a real fix for the :split command not working at startup.
:split requires a mail store to be present on the currently selected
account tab+folder. I could have waited for a types.DirectoryContents
message but it seems silly and bug prone since such a message may never
arrive and we don't want to pool IPC messages forever.
Also, a types.DirectoryContents message may arrive for one account but
:split is only effective *per account* and the default selected account
tab is the first one.
In any case, this band aid prevents aerc from crashing or breaking down
the terminal when running IPC commands in the aerc-startup hook.
Fixes: https://lists.sr.ht/~rjarry/aerc-devel/%3CCYPN7AVYQ69S.WV0T67VM6WX3%40wegtam.com%3E
Fixes: https://todo.sr.ht/~rjarry/aerc/173
Reported-by: Jens Grassel <jens@wegtam.com>
Reported-by: Justine Smithies <justine@smithies.me.uk>
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Thomas Böhler <witcher@wiredspace.de>
Reviewed-by: Thomas Böhler <witcher@wiredspace.de>
-rw-r--r-- | lib/ipc/receive.go | 8 | ||||
-rw-r--r-- | main.go | 12 |
2 files changed, 17 insertions, 3 deletions
diff --git a/lib/ipc/receive.go b/lib/ipc/receive.go index 47ffa89f..dbacc660 100644 --- a/lib/ipc/receive.go +++ b/lib/ipc/receive.go @@ -2,6 +2,7 @@ package ipc import ( "bufio" + "context" "errors" "net" "net/url" @@ -20,9 +21,10 @@ import ( type AercServer struct { listener net.Listener handler Handler + startup context.Context } -func StartServer(handler Handler) (*AercServer, error) { +func StartServer(handler Handler, startup context.Context) (*AercServer, error) { sockpath := xdg.RuntimePath("aerc.sock") // remove the socket if it is not connected to a session if err := ConnectAndExec(nil); err != nil { @@ -33,7 +35,7 @@ func StartServer(handler Handler) (*AercServer, error) { if err != nil { return nil, err } - as := &AercServer{listener: l, handler: handler} + as := &AercServer{listener: l, handler: handler, startup: startup} go as.Serve() return as, nil @@ -48,6 +50,8 @@ var lastId int64 = 0 // access via atomic func (as *AercServer) Serve() { defer log.PanicHandler() + <-as.startup.Done() + for { conn, err := as.listener.Accept() switch { @@ -2,6 +2,7 @@ package main import ( "bytes" + "context" "encoding/base64" "errors" "fmt" @@ -10,6 +11,7 @@ import ( "runtime" "sort" "strings" + "sync" "time" "git.sr.ht/~rjarry/go-opt" @@ -225,8 +227,9 @@ func main() { if config.Ui.MouseEnabled { ui.EnableMouse() } + startup, startupDone := context.WithCancel(context.Background()) - as, err := ipc.StartServer(app.IPCHandler()) + as, err := ipc.StartServer(app.IPCHandler(), startup) if err != nil { log.Warnf("Failed to start Unix server: %v", err) } else { @@ -269,6 +272,7 @@ func main() { log.Errorf("aerc-shutdown hook: %s", err) } }(time.Now()) + var once sync.Once loop: for { select { @@ -276,6 +280,12 @@ loop: ui.HandleEvent(event) case msg := <-types.WorkerMessages: app.HandleMessage(msg) + // XXX: The app may not be 100% ready at this point. + // The issue is that there is no real way to tell when + // it will be ready. And in some cases, it may never be. + // At least, we can be confident that accepting IPC + // commands will not crash the whole process. + once.Do(startupDone) case callback := <-ui.Callbacks: callback() case <-ui.Redraw: |