From 817306b1add73a8d98900de36073709db0e6116d Mon Sep 17 00:00:00 2001 From: ayn2op Date: Mon, 12 Oct 2026 12:37:43 -0400 Subject: [PATCH] fix(gateway): show the login when the token is rejected Closes #843 --- internal/gateway/gateway.go | 2 +- internal/gateway/gateway_test.go | 17 +++++++++++++++++ internal/ui/chat/msg.go | 12 ++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 internal/gateway/gateway_test.go diff --git a/internal/gateway/gateway.go b/internal/gateway/gateway.go index 2968bfb..b0b8689 100644 --- a/internal/gateway/gateway.go +++ b/internal/gateway/gateway.go @@ -16,5 +16,5 @@ func New(id discordgateway.Identifier) *discordgateway.Gateway { conn := ws.NewConnWithDialer(codec, NewDialer()) socket := ws.NewCustomWebsocket(conn, discordgateway.AddGatewayParams(gatewayURL)) - return discordgateway.FromWebsocketGateway(ws.NewGateway(socket, nil), discordgateway.State{Identifier: id}) + return discordgateway.FromWebsocketGateway(ws.NewGateway(socket, &discordgateway.DefaultGatewayOpts), discordgateway.State{Identifier: id}) } diff --git a/internal/gateway/gateway_test.go b/internal/gateway/gateway_test.go new file mode 100644 index 0000000..a69ba55 --- /dev/null +++ b/internal/gateway/gateway_test.go @@ -0,0 +1,17 @@ +package gateway + +import ( + "testing" + + discordgateway "github.com/ayn2op/arikawa/v3/gateway" + "github.com/ayn2op/arikawa/v3/utils/ws" +) + +func TestNew(t *testing.T) { + t.Run("authentication failed", func(t *testing.T) { + opts := New(discordgateway.DefaultIdentifier("token")).Opts() + if !opts.ErrorIsFatalClose(&ws.CloseEvent{Code: 4004}) { + t.Error("gateway reconnects after the token is rejected") + } + }) +} diff --git a/internal/ui/chat/msg.go b/internal/ui/chat/msg.go index 55e49fc..47a7934 100644 --- a/internal/ui/chat/msg.go +++ b/internal/ui/chat/msg.go @@ -2,22 +2,34 @@ package chat import ( "context" + "errors" "log/slog" "time" "github.com/ayn2op/arikawa/v3/discord" "github.com/ayn2op/arikawa/v3/gateway" + "github.com/ayn2op/arikawa/v3/utils/ws" "github.com/ayn2op/discordo/internal/ui/chat/composer" "github.com/ayn2op/discordo/internal/ui/chat/guildstree" "github.com/ayn2op/ningen/v3" "github.com/ayn2op/tview" ) +// closeCodeAuthenticationFailed is the close code of the gateway for a token it rejects. +const closeCodeAuthenticationFailed = 4004 + func openState(state *ningen.State) tview.Cmd { return func() tview.Msg { if err := state.Open(context.Background()); err != nil { slog.Error("failed to open chat state", "err", err) + + // A rejected token never works again, so ask for a new one. + var event *ws.CloseEvent + if errors.As(err, &event) && event.Code == closeCodeAuthenticationFailed { + return LogoutMsg{} + } } + return nil } }