fix(rpc): sync preserve complete username projections

This commit is contained in:
iamxvbaba 2026-07-31 20:42:25 +08:00
parent 464d4edb4a
commit ee74d941bb
10 changed files with 411 additions and 22 deletions

View file

@ -955,6 +955,23 @@ func channelMessageFanoutOwnerIDs(res domain.SendChannelMessageResult, extraUser
// channelMessagesFanoutOwnerIDs 同上,但取多条结果(批量转发汇成一个 job)的 owner id 并集。
func channelMessagesFanoutOwnerIDs(results []domain.SendChannelMessageResult, extraUserIDs []int64) []int64 {
userIDs, _ := channelMessagesFanoutPeerRefs(results, extraUserIDs)
return peerIDMapKeys(userIDs)
}
func channelMessagesFanoutUsernamePeers(results []domain.SendChannelMessageResult, extraUserIDs []int64) []domain.Peer {
userIDs, channelIDs := channelMessagesFanoutPeerRefs(results, extraUserIDs)
peers := make([]domain.Peer, 0, len(userIDs)+len(channelIDs))
for userID := range userIDs {
peers = append(peers, domain.Peer{Type: domain.PeerTypeUser, ID: userID})
}
for channelID := range channelIDs {
peers = append(peers, domain.Peer{Type: domain.PeerTypeChannel, ID: channelID})
}
return peers
}
func channelMessagesFanoutPeerRefs(results []domain.SendChannelMessageResult, extraUserIDs []int64) (map[int64]struct{}, map[int64]struct{}) {
userIDs := make(map[int64]struct{}, len(results)+len(extraUserIDs)+4)
channelIDs := make(map[int64]struct{})
for _, id := range extraUserIDs {
@ -966,7 +983,7 @@ func channelMessagesFanoutOwnerIDs(results []domain.SendChannelMessageResult, ex
collectChannelUpdatePeerRefs(res.Event, res.Channel.ID, userIDs, channelIDs)
collectChannelMessagePeerRefs(res.Message, res.Channel.ID, userIDs, channelIDs)
}
return peerIDMapKeys(userIDs)
return userIDs, channelIDs
}
// enqueueChannelMessageFanout 异步 fan-out 单条频道消息并预热跨 viewer 投影(「频道里出现一条新消息」
@ -976,11 +993,14 @@ func (r *Router) enqueueChannelMessageFanout(ctx context.Context, originUserID i
r.enqueueBotAPIChannelMessageUpdate(ctx, originUserID, res)
fanoutCache := newViewerPeerCache(r)
ownerIDs := channelMessageFanoutOwnerIDs(res, extraUserIDs)
usernamePeers := channelMessagesFanoutUsernamePeers([]domain.SendChannelMessageResult{res}, extraUserIDs)
var usernames map[domain.Peer][]domain.Username
skip := skipDeliverySet(res.SkipDeliveryUserIDs)
r.enqueueChannelFanoutWithPrefetch(ctx, channelFanoutMessageBox, originUserID, res.Channel.ID, res.Event.Pts, res.Recipients,
0,
func(bgCtx context.Context, viewers []int64) {
r.prefetchChannelFanoutUsers(bgCtx, fanoutCache, viewers, ownerIDs)
usernames = r.usernameRegistryMap(bgCtx, usernamePeers)
},
func(bgCtx context.Context, viewerUserID int64) *tg.Updates {
// privacy bot 在 send 时被 SkipDeliveryUserIDs 排除(命令/@/回复以外的消息不可见)。
@ -991,7 +1011,7 @@ func (r *Router) enqueueChannelMessageFanout(ctx context.Context, originUserID i
if _, skipped := skip[viewerUserID]; skipped {
return nil
}
return r.channelMessageUpdatesWithPeerCache(bgCtx, viewerUserID, res, 0, fanoutCache)
return r.channelMessageUpdatesWithPeerCacheAndUsernames(bgCtx, viewerUserID, res, 0, fanoutCache, usernames)
})
}
@ -1030,6 +1050,23 @@ func skipDeliverySet(ids []int64) map[int64]struct{} {
// ServiceEvent/ServiceMessage 仅 ServiceEvent.Pts!=0 时收,对应 todo 编辑的服务消息第二容器),使预热
// owner 集与 build 实际下发的 Users 集恰好一致——多收只会无害多预热,但镜像门控让等价测试最紧。
func channelEditMessageFanoutOwnerIDs(res domain.EditChannelMessageResult) []int64 {
userIDs, _ := channelEditMessageFanoutPeerRefs(res)
return peerIDMapKeys(userIDs)
}
func channelEditMessageFanoutUsernamePeers(res domain.EditChannelMessageResult) []domain.Peer {
userIDs, channelIDs := channelEditMessageFanoutPeerRefs(res)
peers := make([]domain.Peer, 0, len(userIDs)+len(channelIDs))
for userID := range userIDs {
peers = append(peers, domain.Peer{Type: domain.PeerTypeUser, ID: userID})
}
for channelID := range channelIDs {
peers = append(peers, domain.Peer{Type: domain.PeerTypeChannel, ID: channelID})
}
return peers
}
func channelEditMessageFanoutPeerRefs(res domain.EditChannelMessageResult) (map[int64]struct{}, map[int64]struct{}) {
userIDs := make(map[int64]struct{}, 4)
channelIDs := make(map[int64]struct{})
if res.Event.Pts != 0 {
@ -1040,7 +1077,7 @@ func channelEditMessageFanoutOwnerIDs(res domain.EditChannelMessageResult) []int
collectChannelUpdatePeerRefs(res.ServiceEvent, res.Channel.ID, userIDs, channelIDs)
collectChannelMessagePeerRefs(res.ServiceMessage, res.Channel.ID, userIDs, channelIDs)
}
return peerIDMapKeys(userIDs)
return userIDs, channelIDs
}
// enqueueChannelEditMessageFanout 异步 fan-out 一条频道编辑并预热跨 viewer 投影(editMessage/geolive/
@ -1057,14 +1094,17 @@ func (r *Router) enqueueChannelEditMessageFanout(ctx context.Context, originUser
r.enqueueBotAPIChannelEditMessageUpdate(ctx, originUserID, res)
fanoutCache := newViewerPeerCache(r)
ownerIDs := channelEditMessageFanoutOwnerIDs(res)
usernamePeers := channelEditMessageFanoutUsernamePeers(res)
var usernames map[domain.Peer][]domain.Username
nudgePts := max(res.Event.Pts, res.ServiceEvent.Pts)
r.enqueueChannelFanoutWithPrefetch(ctx, channelFanoutMessageBox, originUserID, res.Channel.ID, nudgePts, res.Recipients,
0,
func(bgCtx context.Context, viewers []int64) {
r.prefetchChannelFanoutUsers(bgCtx, fanoutCache, viewers, ownerIDs)
usernames = r.usernameRegistryMap(bgCtx, usernamePeers)
},
func(bgCtx context.Context, viewerUserID int64) *tg.Updates {
return r.channelEditMessageUpdatesWithPeerCache(bgCtx, viewerUserID, res, fanoutCache)
return r.channelEditMessageUpdatesWithPeerCacheAndUsernames(bgCtx, viewerUserID, res, fanoutCache, usernames)
})
}
@ -1075,13 +1115,16 @@ func (r *Router) enqueueChannelMessagesFanout(ctx context.Context, originUserID,
r.enqueueBotAPIChannelMessagesUpdate(ctx, originUserID, results)
fanoutCache := newViewerPeerCache(r)
ownerIDs := channelMessagesFanoutOwnerIDs(results, extraUserIDs)
usernamePeers := channelMessagesFanoutUsernamePeers(results, extraUserIDs)
var usernames map[domain.Peer][]domain.Username
r.enqueueChannelFanoutWithPrefetch(ctx, channelFanoutMessageBox, originUserID, channelID, pts, recipients,
int64(len(results))*(64<<10),
func(bgCtx context.Context, viewers []int64) {
r.prefetchChannelFanoutUsers(bgCtx, fanoutCache, viewers, ownerIDs)
usernames = r.usernameRegistryMap(bgCtx, usernamePeers)
},
func(bgCtx context.Context, viewerUserID int64) *tg.Updates {
return r.channelMessagesUpdatesWithPeerCache(bgCtx, viewerUserID, results, nil, false, extraUserIDs, fanoutCache)
return r.channelMessagesUpdatesWithPeerCacheAndUsernames(bgCtx, viewerUserID, results, nil, false, extraUserIDs, fanoutCache, usernames)
})
}