diff --git a/commands.go b/commands.go index 99190ba..537f98b 100644 --- a/commands.go +++ b/commands.go @@ -90,6 +90,8 @@ func (handler *CommandHandler) Handle(roomID types.MatrixRoomID, user *User, mes handler.CommandReconnect(ce) case "disconnect": handler.CommandDisconnect(ce) + case "ping": + handler.CommandPing(ce) case "delete-connection": handler.CommandDeleteConnection(ce) case "delete-session": @@ -98,11 +100,13 @@ func (handler *CommandHandler) Handle(roomID types.MatrixRoomID, user *User, mes handler.CommandDeletePortal(ce) case "delete-all-portals": handler.CommandDeleteAllPortals(ce) + case "dev-test": + handler.CommandDevTest(ce) case "login-matrix", "logout", "sync", "list", "open", "pm": if ce.User.Conn == nil { ce.Reply("You are not logged in. Use the `login` command to log into WhatsApp.") return - } else if !ce.User.Connected { + } else if !ce.User.IsConnected() { ce.Reply("You are not connected to WhatsApp. Use the `reconnect` command to reconnect.") return } @@ -126,6 +130,10 @@ func (handler *CommandHandler) Handle(roomID types.MatrixRoomID, user *User, mes } } +func (handler *CommandHandler) CommandDevTest(ce *CommandEvent) { + +} + const cmdLoginHelp = `login - Authenticate this Bridge as WhatsApp Web Client` // CommandLogin handles login command @@ -157,7 +165,6 @@ func (handler *CommandHandler) CommandLogout(ce *CommandEvent) { if err != nil { ce.User.log.Warnln("Error while disconnecting after logout:", err) } - ce.User.Connected = false ce.User.Conn.RemoveHandlers() ce.User.Conn = nil ce.User.SetSession(nil) @@ -167,12 +174,11 @@ func (handler *CommandHandler) CommandLogout(ce *CommandEvent) { const cmdDeleteSessionHelp = `delete-session - Delete session information and disconnect from WhatsApp without sending a logout request` func (handler *CommandHandler) CommandDeleteSession(ce *CommandEvent) { - if ce.User.Session == nil && !ce.User.Connected && ce.User.Conn == nil { + if ce.User.Session == nil && ce.User.Conn == nil { ce.Reply("Nothing to purge: no session information stored and no active connection.") return } ce.User.SetSession(nil) - ce.User.Connected = false if ce.User.Conn != nil { _, _ = ce.User.Conn.Disconnect() ce.User.Conn.RemoveHandlers() @@ -213,13 +219,7 @@ func (handler *CommandHandler) CommandReconnect(ce *CommandEvent) { if err != nil { ce.User.log.Warnln("Error while reconnecting:", err) if err == whatsapp.ErrAlreadyLoggedIn { - if ce.User.Connected { - ce.Reply("You were already connected.") - } else { - ce.User.Connected = true - ce.User.ConnectionErrors = 0 - ce.Reply("You were already connected, but the bridge hadn't noticed. Fixed that now.") - } + ce.Reply("You were already connected.") } else if err.Error() == "restore session connection timed out" { ce.Reply("Reconnection timed out. Is WhatsApp on your phone reachable?") } else { @@ -227,7 +227,6 @@ func (handler *CommandHandler) CommandReconnect(ce *CommandEvent) { } return } - ce.User.Connected = true ce.User.ConnectionErrors = 0 ce.Reply("Reconnected successfully.") ce.User.PostLogin() @@ -242,7 +241,6 @@ func (handler *CommandHandler) CommandDeleteConnection(ce *CommandEvent) { if err == nil && len(sess.Wid) > 0 { ce.User.SetSession(&sess) } - ce.User.Connected = false ce.User.Conn.RemoveHandlers() ce.User.Conn = nil ce.Reply("Successfully disconnected. Use the `reconnect` command to reconnect.") @@ -256,7 +254,6 @@ func (handler *CommandHandler) CommandDisconnect(ce *CommandEvent) { return } sess, err := ce.User.Conn.Disconnect() - ce.User.Connected = false if err == whatsapp.ErrNotConnected { ce.Reply("You were not connected.") return @@ -269,6 +266,23 @@ func (handler *CommandHandler) CommandDisconnect(ce *CommandEvent) { ce.Reply("Successfully disconnected. Use the `reconnect` command to reconnect.") } +const cmdPingHelp = `ping - Check your connection to WhatsApp.` + +func (handler *CommandHandler) CommandPing(ce *CommandEvent) { + if ce.User.Conn == nil { + ce.Reply("You don't have a WhatsApp connection.") + return + } + ok, err := ce.User.Conn.AdminTest() + if err != nil { + ce.Reply("Connection not OK: %v", err) + } else if !ok { + ce.Reply("Connection not OK, but no error received") + } else { + ce.Reply("Connection to WhatsApp OK") + } +} + const cmdHelpHelp = `help - Prints this help` // CommandHelp handles help command @@ -285,6 +299,9 @@ func (handler *CommandHandler) CommandHelp(ce *CommandEvent) { cmdPrefix + cmdDeleteSessionHelp, cmdPrefix + cmdReconnectHelp, cmdPrefix + cmdDisconnectHelp, + cmdPrefix + cmdPingHelp, + cmdPrefix + cmdLoginMatrixHelp, + cmdPrefix + cmdLogoutMatrixHelp, cmdPrefix + cmdSyncHelp, cmdPrefix + cmdListHelp, cmdPrefix + cmdOpenHelp, diff --git a/custompuppet.go b/custompuppet.go index ce68194..0c43778 100644 --- a/custompuppet.go +++ b/custompuppet.go @@ -136,8 +136,8 @@ func (puppet *Puppet) stopSyncing() { } func (puppet *Puppet) ProcessResponse(resp *mautrix.RespSync, since string) error { - if !puppet.customUser.Connected { - puppet.log.Warnln("Skipping sync processing: custom user not connected to whatsapp") + if !puppet.customUser.IsConnected() { + puppet.log.Debugln("Skipping sync processing: custom user not connected to whatsapp") return nil } for roomID, events := range resp.Rooms.Join { diff --git a/matrix.go b/matrix.go index 69e0e75..ff2b5f6 100644 --- a/matrix.go +++ b/matrix.go @@ -118,7 +118,7 @@ func (mx *MatrixHandler) HandleMembership(evt *mautrix.Event) { } user := mx.bridge.GetUserByMXID(types.MatrixUserID(evt.Sender)) - if user == nil || !user.Whitelisted || !user.IsLoggedIn() { + if user == nil || !user.Whitelisted || !user.IsConnected() { return } @@ -135,7 +135,7 @@ func (mx *MatrixHandler) HandleMembership(evt *mautrix.Event) { func (mx *MatrixHandler) HandleRoomMetadata(evt *mautrix.Event) { user := mx.bridge.GetUserByMXID(types.MatrixUserID(evt.Sender)) - if user == nil || !user.Whitelisted || !user.IsLoggedIn() || !user.Connected { + if user == nil || !user.Whitelisted || !user.IsConnected() { return } @@ -190,9 +190,9 @@ func (mx *MatrixHandler) HandleMessage(evt *mautrix.Event) { } } - if !user.IsLoggedIn() { + if !user.HasSession() { return - } else if !user.Connected { + } else if !user.IsConnected() { msg := format.RenderMarkdown(fmt.Sprintf("\u26a0 You are not connected to WhatsApp, so your message was not bridged. " + "Use `%s reconnect` to reconnect.", mx.bridge.Config.Bridge.CommandPrefix)) msg.MsgType = mautrix.MsgNotice @@ -218,9 +218,9 @@ func (mx *MatrixHandler) HandleRedaction(evt *mautrix.Event) { return } - if !user.IsLoggedIn() { + if !user.HasSession() { return - } else if !user.Connected { + } else if !user.IsConnected() { msg := format.RenderMarkdown(fmt.Sprintf("[%[1]s](https://matrix.to/#/%[1]s): \u26a0 " + "You are not connected to WhatsApp, so your redaction was not bridged. " + "Use `%[2]s reconnect` to reconnect.", user.MXID, mx.bridge.Config.Bridge.CommandPrefix)) diff --git a/user.go b/user.go index 97c2eb7..80a77c4 100644 --- a/user.go +++ b/user.go @@ -49,7 +49,6 @@ type User struct { Admin bool Whitelisted bool - Connected bool ConnectionErrors int CommunityID string @@ -208,7 +207,6 @@ func (user *User) RestoreSession() bool { _, _ = user.bridge.Bot.SendMessageEvent(user.ManagementRoom, mautrix.EventMessage, msg) return false } - user.Connected = true user.ConnectionErrors = 0 user.SetSession(&sess) user.log.Debugln("Session restored successfully") @@ -217,8 +215,12 @@ func (user *User) RestoreSession() bool { return true } -func (user *User) IsLoggedIn() bool { - return user.Session != nil || user.Conn != nil +func (user *User) HasSession() bool { + return user.Session != nil +} + +func (user *User) IsConnected() bool { + return user.Conn != nil && user.Conn.IsConnected() && user.Conn.IsLoggedIn() } func (user *User) loginQrChannel(ce *CommandEvent, qrChan <-chan string, eventIDChan chan<- string) { @@ -310,7 +312,6 @@ func (user *User) Login(ce *CommandEvent) { _, _ = ce.Bot.SendMessageEvent(ce.RoomID, mautrix.EventMessage, &msg) return } - user.Connected = true user.ConnectionErrors = 0 user.JID = strings.Replace(user.Conn.Info.Wid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, 1) user.SetSession(&session) @@ -432,7 +433,6 @@ func (user *User) HandleError(err error) { user.log.Errorln("WhatsApp error:", err) } if closed, ok := err.(*whatsapp.ErrConnectionClosed); ok { - user.Connected = false if closed.Code == 1000 && user.cleanDisconnection { user.cleanDisconnection = false user.log.Infoln("Clean disconnection by server") @@ -440,7 +440,6 @@ func (user *User) HandleError(err error) { } go user.tryReconnect(fmt.Sprintf("Your WhatsApp connection was closed with websocket status code %d", closed.Code)) } else if failed, ok := err.(*whatsapp.ErrConnectionFailed); ok { - user.Connected = false user.ConnectionErrors++ go user.tryReconnect(fmt.Sprintf("Your WhatsApp connection failed: %v", failed.Err)) } @@ -470,10 +469,18 @@ func (user *User) tryReconnect(msg string) { err := user.Conn.Restore() if err == nil { user.ConnectionErrors = 0 - user.Connected = true _, _ = user.bridge.Bot.SendNotice(user.ManagementRoom, "Reconnected successfully") user.PostLogin() return + } else if err.Error() == "init responded with 400" { + user.log.Infoln("Got init 400 error when trying to reconnect, resetting connection...") + sess, err := user.Conn.Disconnect() + if err != nil { + user.log.Debugln("Error while disconnecting for connection reset:", err) + } + if len(sess.Wid) > 0 { + user.SetSession(&sess) + } } user.log.Errorln("Error while trying to reconnect after disconnection:", err) tries++