From 922ffdcf6ba49a88bbc15a84f97d414800bcf475 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 4 Jul 2023 00:03:36 +0300 Subject: [PATCH] Update bridge states --- bridgestate.go | 26 ++++++-------------------- commands.go | 4 ++-- libgm/events/ready.go | 12 ++++++++++++ libgm/rpc.go | 22 +++++++++++++++++++++- user.go | 21 ++++++++++++++++++--- 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/bridgestate.go b/bridgestate.go index 1451daa..d81a9a5 100644 --- a/bridgestate.go +++ b/bridgestate.go @@ -21,29 +21,15 @@ import ( ) const ( - WALoggedOut status.BridgeStateErrorCode = "wa-logged-out" - WAMainDeviceGone status.BridgeStateErrorCode = "wa-main-device-gone" - WAUnknownLogout status.BridgeStateErrorCode = "wa-unknown-logout" - WANotConnected status.BridgeStateErrorCode = "wa-not-connected" - WAConnecting status.BridgeStateErrorCode = "wa-connecting" - WAKeepaliveTimeout status.BridgeStateErrorCode = "wa-keepalive-timeout" - WAPhoneOffline status.BridgeStateErrorCode = "wa-phone-offline" - WAConnectionFailed status.BridgeStateErrorCode = "wa-connection-failed" - WADisconnected status.BridgeStateErrorCode = "wa-transient-disconnect" + GMListenError status.BridgeStateErrorCode = "gm-listen-error" + GMFatalError status.BridgeStateErrorCode = "gm-listen-fatal-error" + GMNotConnected status.BridgeStateErrorCode = "gm-not-connected" + GMConnecting status.BridgeStateErrorCode = "gm-connecting" + GMConnectionFailed status.BridgeStateErrorCode = "gm-connection-failed" ) func init() { - status.BridgeStateHumanErrors.Update(status.BridgeStateErrorMap{ - WALoggedOut: "You were logged out from another device. Relogin to continue using the bridge.", - WAMainDeviceGone: "Your phone was logged out from WhatsApp. Relogin to continue using the bridge.", - WAUnknownLogout: "You were logged out for an unknown reason. Relogin to continue using the bridge.", - WANotConnected: "You're not connected to WhatsApp", - WAConnecting: "Reconnecting to WhatsApp...", - WAKeepaliveTimeout: "The WhatsApp web servers are not responding. The bridge will try to reconnect.", - WAPhoneOffline: "Your phone hasn't been seen in over 12 days. The bridge is currently connected, but will get disconnected if you don't open the app soon.", - WAConnectionFailed: "Connecting to the WhatsApp web servers failed.", - WADisconnected: "Disconnected from WhatsApp. Trying to reconnect.", - }) + status.BridgeStateHumanErrors.Update(status.BridgeStateErrorMap{}) } func (user *User) GetRemoteID() string { diff --git a/commands.go b/commands.go index fac97ce..d29dfd4 100644 --- a/commands.go +++ b/commands.go @@ -173,7 +173,7 @@ func fnReconnect(ce *WrappedCommandEvent) { } } else { ce.User.DeleteConnection() - ce.User.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: WANotConnected}) + ce.User.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: GMNotConnected}) ce.User.Connect() ce.Reply("Restarted connection to Google Messages") } @@ -195,7 +195,7 @@ func fnDisconnect(ce *WrappedCommandEvent) { } ce.User.DeleteConnection() ce.Reply("Successfully disconnected. Use the `reconnect` command to reconnect.") - ce.User.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Error: WANotConnected}) + ce.User.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Error: GMNotConnected}) } var cmdPing = &commands.FullHandler{ diff --git a/libgm/events/ready.go b/libgm/events/ready.go index 22acf27..f6f0f38 100644 --- a/libgm/events/ready.go +++ b/libgm/events/ready.go @@ -1,6 +1,8 @@ package events import ( + "net/http" + "go.mau.fi/mautrix-gmessages/libgm/util" ) @@ -13,3 +15,13 @@ func NewClientReady(session *util.SessionResponse) *ClientReady { Session: session, } } + +type ListenFatalError struct { + Resp *http.Response +} + +type ListenTemporaryError struct { + Error error +} + +type ListenRecovered struct{} diff --git a/libgm/rpc.go b/libgm/rpc.go index 90d2ef4..1b97617 100644 --- a/libgm/rpc.go +++ b/libgm/rpc.go @@ -8,6 +8,7 @@ import ( "io" "net/http" "os" + "time" "go.mau.fi/mautrix-gmessages/libgm/events" "go.mau.fi/mautrix-gmessages/libgm/util" @@ -25,6 +26,7 @@ type RPC struct { func (r *RPC) ListenReceiveMessages(payload []byte) { r.listenID++ listenID := r.listenID + errored := true for r.listenID == listenID { r.client.Logger.Debug().Msg("Starting new long-polling request") req, err := http.NewRequest("POST", util.RECEIVE_MESSAGES, bytes.NewReader(payload)) @@ -35,7 +37,25 @@ func (r *RPC) ListenReceiveMessages(payload []byte) { resp, reqErr := r.http.Do(req) //r.client.Logger.Info().Any("bodyLength", len(payload)).Any("url", util.RECEIVE_MESSAGES).Any("headers", resp.Request.Header).Msg("RPC Request Headers") if reqErr != nil { - panic(fmt.Errorf("Error making request: %v", err)) + r.client.triggerEvent(&events.ListenTemporaryError{Error: reqErr}) + errored = true + r.client.Logger.Err(err).Msg("Error making listen request, retrying in 5 seconds") + time.Sleep(5 * time.Second) + continue + } + if resp.StatusCode >= 400 && resp.StatusCode < 501 { + r.client.triggerEvent(&events.ListenFatalError{Resp: resp}) + return + } else if resp.StatusCode >= 500 { + r.client.triggerEvent(&events.ListenTemporaryError{Error: fmt.Errorf("http %d while polling", resp.StatusCode)}) + errored = true + r.client.Logger.Debug().Int("statusCode", resp.StatusCode).Msg("5xx error in long polling, retrying in 5 seconds") + time.Sleep(5 * time.Second) + continue + } + if errored { + errored = false + r.client.triggerEvent(&events.ListenRecovered{}) } r.client.Logger.Debug().Int("statusCode", resp.StatusCode).Msg("Long polling opened") r.conn = resp.Body diff --git a/user.go b/user.go index 0a2fea2..1615500 100644 --- a/user.go +++ b/user.go @@ -29,7 +29,6 @@ import ( "github.com/rs/zerolog" "maunium.net/go/maulogger/v2" "maunium.net/go/maulogger/v2/maulogadapt" - "maunium.net/go/mautrix" "maunium.net/go/mautrix/appservice" "maunium.net/go/mautrix/bridge" @@ -445,14 +444,14 @@ func (user *User) Connect() bool { user.tryAutomaticDoublePuppeting() } user.zlog.Debug().Msg("Connecting to Google Messages") - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting, Error: WAConnecting}) + user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting, Error: GMConnecting}) user.createClient() err := user.Client.Connect(user.Session.WebAuthKey) if err != nil { user.zlog.Err(err).Msg("Error connecting to Google Messages") user.BridgeState.Send(status.BridgeState{ StateEvent: status.StateUnknownError, - Error: WAConnectionFailed, + Error: GMConnectionFailed, Info: map[string]interface{}{ "go_error": err.Error(), }, @@ -531,6 +530,22 @@ func (user *User) HandleEvent(event interface{}) { if user.hackyLoginCommand != nil { user.hackyLoginCommandPrevEvent = user.sendQR(user.hackyLoginCommand, v.URL, user.hackyLoginCommandPrevEvent) } + case *events.ListenFatalError: + user.BridgeState.Send(status.BridgeState{ + StateEvent: status.StateUnknownError, + Error: GMFatalError, + Message: fmt.Sprintf("HTTP %d in long polling loop", v.Resp.StatusCode), + }) + case *events.ListenTemporaryError: + user.BridgeState.Send(status.BridgeState{ + StateEvent: status.StateTransientDisconnect, + Error: GMListenError, + Message: v.Error.Error(), + }) + case *events.ListenRecovered: + user.BridgeState.Send(status.BridgeState{ + StateEvent: status.StateConnected, + }) case *events.PairSuccessful: user.hackyLoginCommand = nil user.hackyLoginCommandPrevEvent = ""