89 lines
3 KiB
Go
89 lines
3 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/iamxvbaba/td/tg"
|
|
"go.uber.org/zap"
|
|
|
|
"telesrv/internal/domain"
|
|
)
|
|
|
|
// tgSelfUserWithUsernames is the narrow single-object projection used by
|
|
// authorization results and self-profile updates. Those constructors already
|
|
// carry a User, so it must include the complete username registry vector and
|
|
// never downgrade a client's collectible usernames to the legacy scalar. Story
|
|
// and bot-verification read models are unrelated and deliberately not queried.
|
|
func (r *Router) tgSelfUserWithUsernames(ctx context.Context, u domain.User) *tg.User {
|
|
self := r.tgSelfUser(u)
|
|
users := []tg.UserClass{self}
|
|
r.applyUsernamesToPeerObjects(ctx, users, nil)
|
|
return self
|
|
}
|
|
|
|
// pushUpdatesReadySelfProfile repairs the current session's cached self user
|
|
// when it first becomes eligible for proactive updates. updateUserName is the
|
|
// authoritative basic-name/username cache write in TDLib and DrKLO. A companion
|
|
// username-complete User remains in updates.users so DrKLO's normal peer merge
|
|
// persists the vector, but no updateUser is sent because it only invalidates
|
|
// userFull (and makes DrKLO clear photo caches).
|
|
//
|
|
// This is an ephemeral cache-convergence update: it allocates no PTS, writes no
|
|
// durable update event and targets only the physical session that just became
|
|
// ready. A username-registry read failure suppresses the refresh instead of
|
|
// replacing a possibly richer client cache with the legacy scalar-only shape.
|
|
func (r *Router) pushUpdatesReadySelfProfile(ctx context.Context, userID int64) {
|
|
updates, err := r.updatesReadySelfProfile(ctx, userID)
|
|
if err != nil {
|
|
r.log.Warn("build updates-ready self profile",
|
|
zap.Int64("user_id", userID),
|
|
zap.Error(err))
|
|
return
|
|
}
|
|
if updates == nil {
|
|
return
|
|
}
|
|
r.pushCurrentSessionMessage(ctx, "push updates-ready self profile", updates)
|
|
}
|
|
|
|
func (r *Router) updatesReadySelfProfile(ctx context.Context, userID int64) (*tg.Updates, error) {
|
|
if userID == 0 || r.deps.Users == nil {
|
|
return nil, nil
|
|
}
|
|
u, err := r.deps.Users.Self(ctx, userID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("load self user: %w", err)
|
|
}
|
|
if u.ID != userID || u.Deleted {
|
|
return nil, fmt.Errorf("invalid self user: requested %d, got %d deleted=%v", userID, u.ID, u.Deleted)
|
|
}
|
|
|
|
self := r.tgSelfUser(u)
|
|
users := []tg.UserClass{self}
|
|
if r.deps.Usernames != nil {
|
|
peer := domain.Peer{Type: domain.PeerTypeUser, ID: userID}
|
|
list, err := r.deps.Usernames.PeerUsernames(ctx, peer)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("load self usernames: %w", err)
|
|
}
|
|
if len(list) != 0 {
|
|
applyUsernamesFromRegistry(users, nil, map[domain.Peer][]domain.Username{peer: list})
|
|
}
|
|
}
|
|
usernames := tgUsernames(u.Username)
|
|
if vector, ok := self.GetUsernames(); ok && len(vector) != 0 {
|
|
usernames = vector
|
|
}
|
|
return &tg.Updates{
|
|
Updates: []tg.UpdateClass{&tg.UpdateUserName{
|
|
UserID: userID,
|
|
FirstName: u.FirstName,
|
|
LastName: u.LastName,
|
|
Usernames: usernames,
|
|
}},
|
|
Users: users,
|
|
Date: int(r.clock.Now().Unix()),
|
|
Seq: 0,
|
|
}, nil
|
|
}
|