fix(qr): close the gateway connection on errors

This commit is contained in:
ayn2op 2026-09-29 01:19:37 -04:00
parent 5022ed3d93
commit 48a12551aa
3 changed files with 40 additions and 3 deletions

View file

@ -79,12 +79,14 @@ func (m Model) View() tview.Element {
}
func (m Model) Update(msg tview.Msg) (Model, tview.Cmd) {
var errCmd tview.Cmd
switch msg := msg.(type) {
case selectTabMsg:
m.active = tab(msg)
return m, m.Init()
case error:
return m, showErrorDialog(msg)
// The active tab still gets the error, so the QR tab can close its connection.
errCmd = showErrorDialog(msg)
case copyErrorMsg:
return m, setClipboard(string(msg))
}
@ -98,7 +100,7 @@ func (m Model) Update(msg tview.Msg) (Model, tview.Cmd) {
case tokenTab:
m.token, cmd = m.token.Update(msg)
}
return m, cmd
return m, tview.Batch(errCmd, cmd)
}
func showErrorDialog(err error) tview.Cmd {

View file

@ -105,3 +105,31 @@ func TestModelGateway(t *testing.T) {
}
})
}
func TestCloseConn(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
conn, err := (&websocket.Upgrader{}).Upgrade(w, r, nil)
if err != nil {
t.Error(err)
return
}
defer conn.Close()
_, _, _ = conn.ReadMessage()
}))
t.Cleanup(server.Close)
ws, _, err := websocket.DefaultDialer.Dial("ws"+strings.TrimPrefix(server.URL, "http"), nil)
if err != nil {
t.Fatal(err)
}
conn := &gatewayConn{ws: ws}
// Closing twice must not error, or the error case would close it again forever.
for range 2 {
if msg := closeConn(conn)(); msg != (connCloseMsg{}) {
t.Fatalf("closeConn() = %#v, want connCloseMsg", msg)
}
}
if msg := listen(conn)(); msg != nil {
t.Fatalf("listen() after close = %#v, want nil", msg)
}
}

View file

@ -8,6 +8,8 @@ import (
"encoding/base64"
json "encoding/json/v2"
"errors"
"log/slog"
"net"
"strings"
"sync"
"time"
@ -57,9 +59,10 @@ func connect() tview.Cmd {
func closeConn(conn *gatewayConn) tview.Cmd {
return func() tview.Msg {
// An error here must not reach the error case, which would close the connection again.
if conn != nil {
if err := conn.ws.Close(); err != nil {
return err
slog.Error("failed to close remote auth gateway connection", "err", err)
}
}
return connCloseMsg{}
@ -99,6 +102,10 @@ func listen(conn *gatewayConn) tview.Cmd {
}
_, data, err := conn.ws.ReadMessage()
if errors.Is(err, net.ErrClosed) {
// closeConn closed the connection.
return nil
}
if err != nil {
return err
}