Fix a race between connect and disconnect

If we get an auth error during connect we did deadlock.
This commit is contained in:
Toni Spets
2025-06-06 10:33:50 +03:00
parent c96a241794
commit e7b87835b6
+25 -8
View File
@@ -66,7 +66,7 @@ type TelegramClient struct {
updatesCloseC chan struct{} updatesCloseC chan struct{}
clientCtx context.Context clientCtx context.Context
clientCancel context.CancelFunc clientCancel context.CancelFunc
clientCloseC <-chan struct{} clientCloseC chan struct{}
initialized chan struct{} initialized chan struct{}
mu sync.Mutex mu sync.Mutex
@@ -491,25 +491,34 @@ func (t *TelegramClient) Connect(ctx context.Context) {
t.mu.Lock() t.mu.Lock()
defer t.mu.Unlock() defer t.mu.Unlock()
log := zerolog.Ctx(ctx).With().Int64("user_id", t.telegramUserID).Logger()
if !t.userLogin.Metadata.(*UserLoginMetadata).Session.HasAuthKey() { if !t.userLogin.Metadata.(*UserLoginMetadata).Session.HasAuthKey() {
zerolog.Ctx(ctx).Warn().Msg("user does not have an auth key, sending bad credentials state") log.Warn().Msg("user does not have an auth key, sending bad credentials state")
t.sendBadCredentialsOrUnknownError(ErrNoAuthKey) t.sendBadCredentialsOrUnknownError(ErrNoAuthKey)
return return
} }
zerolog.Ctx(ctx).Info().Int64("user_id", t.telegramUserID).Msg("Connecting client") log.Info().Msg("Connecting client")
var err error
t.clientCtx, t.clientCancel = context.WithCancel(ctx) t.clientCtx, t.clientCancel = context.WithCancel(ctx)
t.clientCloseC = make(chan struct{})
t.updatesCloseC = make(chan struct{}) t.updatesCloseC = make(chan struct{})
go func() { go func() {
defer close(t.initialized) defer close(t.initialized)
if t.clientCloseC, err = connectTelegramClient(t.clientCtx, t.clientCancel, t.client); err != nil { connectClientCloseC, err := connectTelegramClient(t.clientCtx, t.clientCancel, t.client)
if err != nil {
t.sendBadCredentialsOrUnknownError(err) t.sendBadCredentialsOrUnknownError(err)
close(t.updatesCloseC) close(t.updatesCloseC)
return return
} }
// awful hack to prevent assigning clientCloseC from racing Disconnect()
go func() {
<-connectClientCloseC
close(t.clientCloseC)
}()
go func() { go func() {
defer close(t.updatesCloseC) defer close(t.updatesCloseC)
for { for {
@@ -554,19 +563,24 @@ func (t *TelegramClient) Disconnect() {
t.mu.Lock() t.mu.Lock()
defer t.mu.Unlock() defer t.mu.Unlock()
t.userLogin.Log.Info().Msg("disconnecting client") t.userLogin.Log.Info().Msg("Disconnecting client")
if t.clientCancel != nil { if t.clientCancel != nil {
t.clientCancel() t.clientCancel()
t.clientCancel = nil t.clientCancel = nil
} }
if t.clientCloseC != nil { if t.clientCloseC != nil {
t.userLogin.Log.Debug().Msg("Waiting for client to finish")
<-t.clientCloseC <-t.clientCloseC
t.clientCloseC = nil t.clientCloseC = nil
} }
if t.updatesCloseC != nil { if t.updatesCloseC != nil {
t.userLogin.Log.Debug().Msg("Waiting for updates to finish")
<-t.updatesCloseC <-t.updatesCloseC
t.updatesCloseC = nil t.updatesCloseC = nil
} }
t.userLogin.Log.Info().Msg("Disconnect complete")
} }
func (t *TelegramClient) getInputUser(ctx context.Context, id int64) (*tg.InputUser, error) { func (t *TelegramClient) getInputUser(ctx context.Context, id int64) (*tg.InputUser, error) {
@@ -726,7 +740,8 @@ func (t *TelegramClient) LogoutRemote(ctx context.Context) {
Str("action", "logout_remote"). Str("action", "logout_remote").
Int64("user_id", t.telegramUserID). Int64("user_id", t.telegramUserID).
Logger() Logger()
log.Info().Msg("Logging out")
log.Info().Msg("Logging out and disconnecting")
if t.userLogin.Metadata.(*UserLoginMetadata).Session.HasAuthKey() { if t.userLogin.Metadata.(*UserLoginMetadata).Session.HasAuthKey() {
log.Info().Msg("User has an auth key, logging out") log.Info().Msg("User has an auth key, logging out")
@@ -743,6 +758,8 @@ func (t *TelegramClient) LogoutRemote(ctx context.Context) {
t.Disconnect() t.Disconnect()
log.Info().Msg("Deleting user state")
err := t.ScopedStore.DeleteUserState(ctx) err := t.ScopedStore.DeleteUserState(ctx)
if err != nil { if err != nil {
log.Err(err).Msg("failed to delete user state") log.Err(err).Msg("failed to delete user state")
@@ -758,7 +775,7 @@ func (t *TelegramClient) LogoutRemote(ctx context.Context) {
log.Err(err).Msg("failed to delete access hashes for user") log.Err(err).Msg("failed to delete access hashes for user")
} }
log.Info().Msg("successfully logged out and deleted user state") log.Info().Msg("Logged out and deleted user state")
} }
func (t *TelegramClient) IsThisUser(ctx context.Context, userID networkid.UserID) bool { func (t *TelegramClient) IsThisUser(ctx context.Context, userID networkid.UserID) bool {