diff --git a/pkg/connector/client.go b/pkg/connector/client.go index b0fc05e2..83fba889 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -47,6 +47,7 @@ type TelegramClient struct { userLogin *bridgev2.UserLogin client *telegram.Client updatesManager *updates.Manager + clientCtx context.Context clientCancel context.CancelFunc appConfigLock sync.Mutex @@ -225,7 +226,7 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge OnDead: client.onDead, OnSession: client.onConnectionStateChange("session"), OnConnected: client.onConnectionStateChange("connected"), - PingCallback: client.onConnectionStateChange("ping"), + PingCallback: client.onPing, OnAuthError: func(err error) { client.onAuthError(context.Background(), err) }, PingTimeout: time.Duration(tc.Config.Ping.TimeoutSeconds) * time.Second, PingInterval: time.Duration(tc.Config.Ping.IntervalSeconds) * time.Second, @@ -412,6 +413,14 @@ func (t *TelegramClient) sendBadCredentialsOrUnknownError(err error) { } } +func (t *TelegramClient) onPing() { + if t.userLogin.BridgeState.GetPrev().StateEvent == status.StateConnected { + t.main.Bridge.Log.Info().Msg("Got ping, not checking connectivity because we are already connected") + } else { + t.onConnectionStateChange("ping while not connected") + } +} + func (t *TelegramClient) onConnectionStateChange(reason string) func() { return func() { log := t.main.Bridge.Log.With(). @@ -423,15 +432,21 @@ func (t *TelegramClient) onConnectionStateChange(reason string) func() { ctx := log.WithContext(context.Background()) if t.client == nil { + log.Warn().Msg("client is nil") return } authStatus, err := t.client.Auth().Status(ctx) if err != nil { if errors.Is(err, syscall.EPIPE) { - // This is a pipe error, try reconnecting + // This is a pipe error, try disconnecting which will force the + // updatesManager to fail and cause the client to reconnect. + t.userLogin.BridgeState.Send(status.BridgeState{ + StateEvent: status.StateTransientDisconnect, + Error: "pipe-error", + Message: humanise.Error(err), + }) t.Disconnect() - t.Connect(t.main.Bridge.Log.WithContext(context.Background())) } else { t.sendBadCredentialsOrUnknownError(err) } @@ -460,15 +475,15 @@ func (t *TelegramClient) Connect(ctx context.Context) { } var err error - ctx, t.clientCancel, err = connectTelegramClient(ctx, t.client) + t.clientCtx, t.clientCancel, err = connectTelegramClient(ctx, t.client) if err != nil { t.sendBadCredentialsOrUnknownError(err) return } go func() { - err = t.updatesManager.Run(ctx, t.client.API(), t.telegramUserID, updates.AuthOptions{}) + err = t.updatesManager.Run(t.clientCtx, t.client.API(), t.telegramUserID, updates.AuthOptions{}) if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("failed to run updates manager") + zerolog.Ctx(t.clientCtx).Err(err).Msg("failed to run updates manager") t.Disconnect() t.Connect(t.main.Bridge.Log.WithContext(context.Background())) } @@ -476,9 +491,9 @@ func (t *TelegramClient) Connect(ctx context.Context) { // Update the logged-in user's ghost info (this also updates the user // login's remote name and profile). - if me, err := t.client.Self(ctx); err != nil { + if me, err := t.client.Self(t.clientCtx); err != nil { t.sendBadCredentialsOrUnknownError(err) - } else if _, err := t.updateGhost(ctx, t.telegramUserID, me); err != nil { + } else if _, err := t.updateGhost(t.clientCtx, t.telegramUserID, me); err != nil { t.sendBadCredentialsOrUnknownError(err) } else { t.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) @@ -496,6 +511,7 @@ func (t *TelegramClient) Connect(ctx context.Context) { } func (t *TelegramClient) Disconnect() { + t.userLogin.Log.Info().Msg("disconnecting client") if t.clientCancel != nil { t.clientCancel() } @@ -642,11 +658,19 @@ func (t *TelegramClient) IsLoggedIn() bool { if t == nil { return false } - t.main.Bridge.Log.Debug(). - Bool("has_client", t.client != nil). - Bool("has_auth_key", t.userLogin.Metadata.(*UserLoginMetadata).Session.HasAuthKey()). - Msg("Checking if user is logged in") - return t.client != nil && t.userLogin.Metadata.(*UserLoginMetadata).Session.HasAuthKey() + select { + case <-t.clientCtx.Done(): + t.main.Bridge.Log.Debug(). + Bool("client_context_done", true). + Msg("Checking if user is logged in") + return false + default: + t.main.Bridge.Log.Debug(). + Bool("has_client", t.client != nil). + Bool("has_auth_key", t.userLogin.Metadata.(*UserLoginMetadata).Session.HasAuthKey()). + Msg("Checking if user is logged in") + return t.client != nil && t.userLogin.Metadata.(*UserLoginMetadata).Session.HasAuthKey() + } } func (t *TelegramClient) LogoutRemote(ctx context.Context) { diff --git a/pkg/connector/loginphone.go b/pkg/connector/loginphone.go index 8a1762d8..5c136518 100644 --- a/pkg/connector/loginphone.go +++ b/pkg/connector/loginphone.go @@ -68,7 +68,7 @@ func (p *PhoneLogin) SubmitUserInput(ctx context.Context, input map[string]strin }) var err error authClientContext, _ := context.WithTimeoutCause(log.WithContext(context.Background()), time.Hour, errors.New("phone login took over one hour")) - _, p.authClientCancel, err = connectTelegramClient(authClientContext, p.authClient) + ctx, p.authClientCancel, err = connectTelegramClient(authClientContext, p.authClient) if err != nil { return nil, err }