package peers import ( "context" "github.com/go-faster/errors" "go.uber.org/zap" "go.mau.fi/mautrix-telegram/pkg/gotd/tg" ) func (m *Manager) getIDFromInputUser(p tg.InputUserClass) (int64, bool) { switch p := p.(type) { case *tg.InputUserSelf: return m.myID() case *tg.InputUser: return p.UserID, true case *tg.InputUserFromMessage: return p.UserID, true default: return 0, false } } // getUser gets tg.User using given tg.InputUserClass. func (m *Manager) getUser(ctx context.Context, p tg.InputUserClass) (*tg.User, error) { switch p := p.(type) { case *tg.InputUserSelf: u, ok := m.me.Load() if ok && !m.needsUpdate(userPeerID(u.ID)) { return u, nil } default: userID, ok := m.getIDFromInputUser(p) if !ok || m.needsUpdate(userPeerID(userID)) { break } if me, ok := m.me.Load(); ok && me.GetID() == userID { return me, nil } u, found, err := m.cache.FindUser(ctx, userID) if err == nil && found { u.SetFlags() return u, nil } if err != nil { m.logger.Warn("Find user error", zap.Int64("user_id", userID), zap.Error(err)) } } return m.updateUser(ctx, p) } // updateUser forcibly updates tg.User using given tg.InputUserClass. func (m *Manager) updateUser(ctx context.Context, p tg.InputUserClass) (*tg.User, error) { // TODO(tdakkota): batch requests. users, err := m.api.UsersGetUsers(ctx, []tg.InputUserClass{p}) if err != nil { return nil, errors.Wrap(err, "get users") } if len(users) < 1 { return nil, errors.Errorf("got empty result for %+v", p) } if err := m.applyUsers(ctx, users...); err != nil { return nil, errors.Wrap(err, "update users") } user, ok := users[0].AsNotEmpty() if !ok { return nil, errors.New("got empty user") } if user.Self { m.me.Store(user) } return user, nil } // getChat gets tg.Chat using given id. func (m *Manager) getChat(ctx context.Context, p int64) (*tg.Chat, error) { if !m.needsUpdate(chatPeerID(p)) { c, found, err := m.cache.FindChat(ctx, p) if err == nil && found { c.SetFlags() return c, nil } if err != nil { m.logger.Warn("Find chat error", zap.Int64("chat_id", p), zap.Error(err)) } } return m.updateChat(ctx, p) } // updateChat forcibly updates tg.Chat using given id. func (m *Manager) updateChat(ctx context.Context, id int64) (*tg.Chat, error) { r, err := m.api.MessagesGetChats(ctx, []int64{id}) if err != nil { return nil, errors.Wrap(err, "get chats") } chats := r.GetChats() if len(chats) < 1 { return nil, errors.Errorf("got empty result for chat %d", id) } if err := m.applyChats(ctx, chats...); err != nil { return nil, errors.Wrap(err, "update chats") } var found tg.ChatClass for _, chat := range chats { switch chat := chat.(type) { case *tg.Chat: if chat.ID == id { found = chat break } } } ch, ok := found.(*tg.Chat) if !ok { // TODO(tdakkota): get better error for forbidden. return nil, errors.Errorf("got unexpected type %T", found) } return ch, nil } func getIDFromInputChannel(p tg.InputChannelClass) (int64, bool) { switch p := p.(type) { case *tg.InputChannel: return p.ChannelID, true case *tg.InputChannelFromMessage: return p.ChannelID, true default: return 0, false } } // getChannel gets tg.Channel using given tg.InputChannelClass. func (m *Manager) getChannel(ctx context.Context, p tg.InputChannelClass) (*tg.Channel, error) { if id, ok := getIDFromInputChannel(p); ok && !m.needsUpdate(channelPeerID(id)) { c, found, err := m.cache.FindChannel(ctx, id) if err == nil && found { c.SetFlags() return c, nil } if err != nil { m.logger.Warn("Find channel error", zap.Int64("channel_id", id), zap.Error(err)) } } return m.updateChannel(ctx, p) } // updateChannel forcibly updates tg.Channel using given tg.InputChannelClass. func (m *Manager) updateChannel(ctx context.Context, p tg.InputChannelClass) (*tg.Channel, error) { r, err := m.api.ChannelsGetChannels(ctx, []tg.InputChannelClass{p}) if err != nil { return nil, errors.Wrap(err, "get channels") } chats := r.GetChats() if len(chats) < 1 { return nil, errors.Errorf("got empty result for %+v", p) } if err := m.applyChats(ctx, chats...); err != nil { return nil, errors.Wrap(err, "update chats") } var found tg.ChatClass if inputHasID, ok := p.AsNotEmpty(); ok { id := inputHasID.GetChannelID() for _, chat := range chats { switch chat := chat.(type) { case *tg.Channel: if chat.ID == id { found = chat break } } } } else { found = chats[0] } ch, ok := found.(*tg.Channel) if !ok { // TODO(tdakkota): get better error for forbidden. return nil, errors.Errorf("got unexpected type %T", found) } return ch, nil }