Add automatic connection retries

This commit is contained in:
Tulir Asokan
2019-05-17 23:53:57 +03:00
parent 38540d8efb
commit 23747d4917
4 changed files with 73 additions and 14 deletions

69
user.go
View File

@ -44,6 +44,8 @@ type User struct {
Admin bool
Whitelisted bool
Connected bool
ConnectionErrors int
}
func (bridge *Bridge) GetUserByMXID(userID types.MatrixUserID) *User {
@ -182,6 +184,7 @@ func (user *User) RestoreSession() bool {
return false
}
user.Connected = true
user.ConnectionErrors = 0
user.SetSession(&sess)
user.log.Debugln("Session restored successfully")
}
@ -236,6 +239,7 @@ func (user *User) Login(ce *CommandEvent) {
return
}
user.Connected = true
user.ConnectionErrors = 0
user.JID = strings.Replace(user.Conn.Info.Wid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, 1)
user.SetSession(&session)
ce.Reply("Successfully logged in. Now, you may ask for `sync [--create]`.")
@ -243,22 +247,63 @@ func (user *User) Login(ce *CommandEvent) {
func (user *User) HandleError(err error) {
user.log.Errorln("WhatsApp error:", err)
closed, ok := err.(*whatsapp.ErrConnectionClosed)
if ok {
if closed.Code != 1000 {
msg := fmt.Sprintf("\u26a0 Your WhatsApp connection was closed with websocket status code %d.\n\n"+
"Use the `reconnect` command to reconnect.", closed.Code)
_, _ = user.bridge.Bot.SendMessageEvent(user.ManagementRoom, mautrix.EventMessage, format.RenderMarkdown(msg))
var msg string
if closed, ok := err.(*whatsapp.ErrConnectionClosed); ok {
user.Connected = false
if closed.Code == 1000 {
// Normal closure
return
}
user.ConnectionErrors++
msg = 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++
msg = fmt.Sprintf("Your WhatsApp connection failed: %v", failed.Err)
} else {
// Unknown error, probably mostly harmless
return
}
failed, ok := err.(*whatsapp.ErrConnectionFailed)
if ok {
msg := fmt.Sprintf("\u26a0 Your WhatsApp connection failed: %v.\n\n"+
"Use the `reconnect` command to reconnect.", failed.Err)
_, _ = user.bridge.Bot.SendMessageEvent(user.ManagementRoom, mautrix.EventMessage, format.RenderMarkdown(msg))
user.Connected = false
if user.ConnectionErrors > user.bridge.Config.Bridge.MaxConnectionAttempts {
content := format.RenderMarkdown(fmt.Sprintf("%s. Use the `reconnect` command to reconnect.", msg))
_, _ = user.bridge.Bot.SendMessageEvent(user.ManagementRoom, mautrix.EventMessage, content)
return
}
if user.bridge.Config.Bridge.ReportConnectionRetry {
_, _ = user.bridge.Bot.SendNotice(user.ManagementRoom, fmt.Sprintf("%s. Reconnecting...", msg))
// Don't want the same error to be repeated
msg = ""
}
tries := 0
for user.ConnectionErrors <= user.bridge.Config.Bridge.MaxConnectionAttempts {
err = user.Conn.Restore()
if err == nil {
user.ConnectionErrors = 0
user.Connected = true
_, _ = user.bridge.Bot.SendNotice(user.ManagementRoom, "Reconnected successfully")
return
}
user.log.Errorln("Error while trying to reconnect after disconnection:", err)
tries++
user.ConnectionErrors++
if user.ConnectionErrors <= user.bridge.Config.Bridge.MaxConnectionAttempts {
if user.bridge.Config.Bridge.ReportConnectionRetry {
_, _ = user.bridge.Bot.SendNotice(user.ManagementRoom,
fmt.Sprintf("Reconnection attempt failed: %v. Retrying in 10 seconds...", err))
}
time.Sleep(10 * time.Second)
}
}
if user.bridge.Config.Bridge.ReportConnectionRetry {
msg = fmt.Sprintf("%d reconnection attempts failed. Use the `reconnect` command to try to reconnect manually.", tries)
} else {
msg = fmt.Sprintf("\u26a0 %sAdditionally, %d reconnection attempts failed. "+
"Use the `reconnect` command to try to reconnect.", msg, tries)
}
content := format.RenderMarkdown(msg)
_, _ = user.bridge.Bot.SendMessageEvent(user.ManagementRoom, mautrix.EventMessage, content)
}
func (user *User) HandleJSONParseError(err error) {