Skip to content

Commit

Permalink
Merge pull request #58 from mautrix/feature/periodic-refresh
Browse files Browse the repository at this point in the history
Add periodic refresh for connection
  • Loading branch information
javiercr authored May 15, 2024
2 parents e19e48f + dd7ca95 commit 0390840
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 10 deletions.
10 changes: 6 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ type Config struct {
*bridgeconfig.BaseConfig `yaml:",inline"`

Meta struct {
Mode BridgeMode `yaml:"mode"`
IGE2EE bool `yaml:"ig_e2ee"`
Proxy string `yaml:"proxy"`
GetProxyFrom string `yaml:"get_proxy_from"`
Mode BridgeMode `yaml:"mode"`
IGE2EE bool `yaml:"ig_e2ee"`
Proxy string `yaml:"proxy"`
GetProxyFrom string `yaml:"get_proxy_from"`
MinFullReconnectIntervalSeconds int `yaml:"min_full_reconnect_interval_seconds"`
ForceRefreshIntervalSeconds int `yaml:"force_refresh_interval_seconds"`
} `yaml:"meta"`

Bridge BridgeConfig `yaml:"bridge"`
Expand Down
4 changes: 4 additions & 0 deletions example-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ meta:
# HTTP endpoint to request new proxy address from, for dynamically assigned proxies.
# The endpoint must return a JSON body with a string field called proxy_url.
get_proxy_from:
# Minimum interval between full reconnects in seconds, default is 1 hour
min_full_reconnect_interval_seconds: 3600
# Interval to force refresh the connection (full reconnect), default is 1 day. Set 0 to disable force refreshes.
force_refresh_interval_seconds: 86400

# Bridge config
bridge:
Expand Down
2 changes: 1 addition & 1 deletion portal.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ func (portal *Portal) handleMatrixMessage(ctx context.Context, sender *User, evt
} else {
ctx = context.WithValue(ctx, msgconvContextKeyClient, sender.Client)
tasks, otid, err = portal.MsgConv.ToMeta(ctx, evt, content, relaybotFormatted)
if errors.Is(err, metaTypes.ErrPleaseReloadPage) && time.Since(sender.lastFullReconnect) > MinFullReconnectInterval {
if errors.Is(err, metaTypes.ErrPleaseReloadPage) && sender.canReconnect() {
log.Err(err).Msg("Got please reload page error while converting message, reloading page in background")
go sender.FullReconnect()
err = errReloading
Expand Down
30 changes: 25 additions & 5 deletions user.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ var (
ErrNotLoggedIn = errors.New("not logged in")
)

const MinFullReconnectInterval = 1 * time.Hour
const setDisconnectStateAfterConnectAttempts = 10

func (br *MetaBridge) GetUserByMXID(userID id.UserID) *User {
Expand Down Expand Up @@ -240,6 +239,7 @@ type User struct {
incomingTables chan *table.LSTable

lastFullReconnect time.Time
forceRefreshTimer *time.Timer
}

var (
Expand Down Expand Up @@ -541,6 +541,19 @@ func (user *User) unlockedConnect() {
})
}
go user.sendMarkdownBridgeAlert(context.TODO(), "Failed to connect to %s: %v", user.bridge.ProtocolName, err)
return
}

refreshInterval := time.Duration(user.bridge.Config.Meta.ForceRefreshIntervalSeconds) * time.Second
if refreshInterval > 0 {
go func() {
user.log.Debug().Time("next_refresh", time.Now().Add(refreshInterval)).Msg("Setting force refresh timer")
user.forceRefreshTimer = time.NewTimer(refreshInterval)

<-user.forceRefreshTimer.C
user.log.Info().Msg("Refreshing connection")
user.FullReconnect()
}()
}
}

Expand Down Expand Up @@ -1014,7 +1027,7 @@ func (user *User) e2eeEventHandler(rawEvt any) {
}
user.BridgeState.Send(user.waState)
case *events.CATRefreshError:
if errors.Is(evt.Error, types.ErrPleaseReloadPage) && time.Since(user.lastFullReconnect) > MinFullReconnectInterval {
if errors.Is(evt.Error, types.ErrPleaseReloadPage) && user.canReconnect() {
user.log.Err(evt.Error).Msg("Got CATRefreshError, reloading page")
go user.FullReconnect()
return
Expand All @@ -1028,7 +1041,7 @@ func (user *User) e2eeEventHandler(rawEvt any) {
go user.sendMarkdownBridgeAlert(context.TODO(), "Error in WhatsApp connection: %s", evt.PermanentDisconnectDescription())
case events.PermanentDisconnect:
cf, ok := evt.(*events.ConnectFailure)
if ok && cf.Reason == events.ConnectFailureLoggedOut && time.Since(user.lastFullReconnect) > MinFullReconnectInterval {
if ok && cf.Reason == events.ConnectFailureLoggedOut && user.canReconnect() {
user.log.Debug().Msg("Doing full reconnect after WhatsApp 401 error")
go user.FullReconnect()
}
Expand Down Expand Up @@ -1133,7 +1146,7 @@ func (user *User) eventHandler(rawEvt any) {
StateEvent: status.StateUnknownError,
Error: MetaServerUnavailable,
}
if time.Since(user.lastFullReconnect) > MinFullReconnectInterval {
if user.canReconnect() {
user.log.Debug().Msg("Doing full reconnect after server unavailable error")
go user.FullReconnect()
}
Expand All @@ -1153,6 +1166,9 @@ func (user *User) eventHandler(rawEvt any) {
user.BridgeState.Send(user.metaState)
go user.sendMarkdownBridgeAlert(context.TODO(), "Error in %s connection: %v", user.bridge.ProtocolName, evt.Err)
user.StopBackfillLoop()
if user.forceRefreshTimer != nil {
user.forceRefreshTimer.Stop()
}
default:
user.log.Warn().Type("event_type", evt).Msg("Unrecognized event type from messagix")
}
Expand Down Expand Up @@ -1183,10 +1199,14 @@ func (user *User) unlockedDisconnect() {
user.metaState = status.BridgeState{}
}

func (user *User) canReconnect() bool {
return time.Since(user.lastFullReconnect) > time.Duration(user.bridge.Config.Meta.MinFullReconnectIntervalSeconds)*time.Second
}

func (user *User) FullReconnect() {
user.Lock()
defer user.Unlock()
if time.Since(user.lastFullReconnect) < MinFullReconnectInterval {
if !user.canReconnect() {
return
}
user.unlockedDisconnect()
Expand Down

0 comments on commit 0390840

Please sign in to comment.