owpengram-server/internal/rpc/update_peer_refs.go
2026-06-04 01:37:39 +08:00

283 lines
8.1 KiB
Go

package rpc
import (
"context"
"telesrv/internal/domain"
)
func (r *Router) enrichUpdateEvents(ctx context.Context, viewerUserID int64, events []domain.UpdateEvent) []domain.UpdateEvent {
if len(events) == 0 {
return events
}
out := append([]domain.UpdateEvent(nil), events...)
for i := range out {
if out[i].Type == domain.UpdateEventMessageReactions {
out[i] = r.enrichMessageReactionEvent(ctx, viewerUserID, out[i])
}
userIDs := make(map[int64]struct{})
channelIDs := make(map[int64]struct{})
addDomainPeerRef(out[i].Peer, 0, userIDs, channelIDs)
for _, peer := range out[i].Peers {
addDomainPeerRef(peer, 0, userIDs, channelIDs)
}
collectMessagePeerRefs(out[i].Message, 0, userIDs, channelIDs)
out[i].Users = r.withUsersPresence(mergeDomainUsers(out[i].Users, r.domainUsersForIDs(ctx, viewerUserID, mapKeys(userIDs))...))
out[i].Channels = mergeDomainChannels(out[i].Channels, r.domainChannelsForIDs(ctx, viewerUserID, mapKeys(channelIDs))...)
}
return out
}
func (r *Router) enrichMessageReactionEvent(ctx context.Context, viewerUserID int64, event domain.UpdateEvent) domain.UpdateEvent {
if r.deps.Messages == nil || event.Message.ID <= 0 {
return event
}
peer := event.Message.Peer
if peer.Type == "" || peer.ID == 0 {
peer = event.Peer
}
if peer.Type != domain.PeerTypeUser || peer.ID == 0 {
return event
}
res, err := r.deps.Messages.GetMessageReactions(ctx, viewerUserID, domain.PrivateMessageReactionsRequest{
OwnerUserID: viewerUserID,
Peer: peer,
IDs: []int{event.Message.ID},
})
if err != nil {
return event
}
for _, msg := range res.Messages {
if msg.OwnerUserID == viewerUserID && msg.ID == event.Message.ID {
msg.Pts = event.Pts
event.Message = msg
event.Peer = msg.Peer
return event
}
}
return event
}
func (r *Router) enrichChannelDifference(ctx context.Context, viewerUserID int64, diff domain.ChannelDifference) domain.ChannelDifference {
userIDs := make(map[int64]struct{})
channelIDs := make(map[int64]struct{})
for _, event := range diff.Events {
collectChannelUpdatePeerRefs(event, diff.Channel.ID, userIDs, channelIDs)
}
for _, msg := range diff.NewMessages {
collectChannelMessagePeerRefs(msg, diff.Channel.ID, userIDs, channelIDs)
}
for _, event := range diff.OtherUpdates {
collectChannelUpdatePeerRefs(event, diff.Channel.ID, userIDs, channelIDs)
}
diff.Users = r.withUsersPresence(mergeDomainUsers(diff.Users, r.domainUsersForIDs(ctx, viewerUserID, mapKeys(userIDs))...))
diff.Channels = mergeDomainChannels(diff.Channels, r.domainChannelsForIDs(ctx, viewerUserID, mapKeys(channelIDs))...)
return diff
}
func (r *Router) enrichChannelHistory(ctx context.Context, viewerUserID int64, history domain.ChannelHistory) domain.ChannelHistory {
userIDs := make(map[int64]struct{})
channelIDs := make(map[int64]struct{})
for _, msg := range history.Messages {
collectChannelMessagePeerRefs(msg, history.Channel.ID, userIDs, channelIDs)
}
for _, topic := range history.Topics {
if topic.CreatorUserID != 0 {
userIDs[topic.CreatorUserID] = struct{}{}
}
}
history.Users = r.withUsersPresence(mergeDomainUsers(history.Users, r.domainUsersForIDs(ctx, viewerUserID, mapKeys(userIDs))...))
history.Channels = mergeDomainChannels(history.Channels, r.domainChannelsForIDs(ctx, viewerUserID, mapKeys(channelIDs))...)
return history
}
func collectMessagePeerRefs(msg domain.Message, currentChannelID int64, userIDs, channelIDs map[int64]struct{}) {
addDomainPeerRef(msg.From, currentChannelID, userIDs, channelIDs)
addDomainPeerRef(msg.Peer, currentChannelID, userIDs, channelIDs)
if msg.Forward != nil {
addDomainPeerRef(msg.Forward.From, currentChannelID, userIDs, channelIDs)
}
if msg.ReplyTo != nil {
addDomainPeerRef(msg.ReplyTo.Peer, currentChannelID, userIDs, channelIDs)
}
if msg.Reactions != nil {
for _, reaction := range msg.Reactions.Recent {
if reaction.UserID != 0 {
userIDs[reaction.UserID] = struct{}{}
}
}
}
}
func collectChannelUpdatePeerRefs(event domain.ChannelUpdateEvent, currentChannelID int64, userIDs, channelIDs map[int64]struct{}) {
if event.SenderUserID != 0 {
userIDs[event.SenderUserID] = struct{}{}
}
for _, id := range event.UserIDs {
if id != 0 {
userIDs[id] = struct{}{}
}
}
for _, member := range []domain.ChannelMember{event.Previous, event.Participant} {
if member.UserID != 0 {
userIDs[member.UserID] = struct{}{}
}
if member.InviterUserID != 0 {
userIDs[member.InviterUserID] = struct{}{}
}
}
collectChannelMessagePeerRefs(event.Message, currentChannelID, userIDs, channelIDs)
}
func collectChannelMessagePeerRefs(msg domain.ChannelMessage, currentChannelID int64, userIDs, channelIDs map[int64]struct{}) {
if msg.SenderUserID != 0 {
userIDs[msg.SenderUserID] = struct{}{}
}
addDomainPeerRef(msg.From, currentChannelID, userIDs, channelIDs)
if msg.SendAs != nil {
addDomainPeerRef(*msg.SendAs, currentChannelID, userIDs, channelIDs)
}
if msg.Forward != nil {
addDomainPeerRef(msg.Forward.From, currentChannelID, userIDs, channelIDs)
}
if msg.ReplyTo != nil {
addDomainPeerRef(msg.ReplyTo.Peer, currentChannelID, userIDs, channelIDs)
}
if msg.Action != nil {
for _, id := range msg.Action.UserIDs {
if id != 0 {
userIDs[id] = struct{}{}
}
}
}
if msg.Reactions != nil {
for _, reaction := range msg.Reactions.Recent {
if reaction.UserID != 0 {
userIDs[reaction.UserID] = struct{}{}
}
}
}
}
func addDomainPeerRef(peer domain.Peer, currentChannelID int64, userIDs, channelIDs map[int64]struct{}) {
switch peer.Type {
case domain.PeerTypeUser:
if peer.ID != 0 {
userIDs[peer.ID] = struct{}{}
}
case domain.PeerTypeChannel:
if peer.ID != 0 && peer.ID != currentChannelID {
channelIDs[peer.ID] = struct{}{}
}
}
}
func (r *Router) domainUsersForIDs(ctx context.Context, currentUserID int64, ids []int64) []domain.User {
if len(ids) == 0 {
return nil
}
out := make([]domain.User, 0, len(ids))
seen := make(map[int64]struct{}, len(ids))
for _, id := range ids {
if id == 0 {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
switch {
case id == domain.OfficialSystemUserID:
out = append(out, r.withUserPresence(domain.OfficialSystemUser()))
case r.deps.Users == nil:
continue
case id == currentUserID:
if u, err := r.deps.Users.Self(ctx, currentUserID); err == nil && u.ID != 0 {
out = append(out, r.withUserPresence(u))
}
default:
if u, found, err := r.deps.Users.ByID(ctx, currentUserID, id); err == nil && found {
out = append(out, r.withUserPresence(u))
}
}
}
return out
}
func (r *Router) domainChannelsForIDs(ctx context.Context, currentUserID int64, ids []int64) []domain.Channel {
if r.deps.Channels == nil || len(ids) == 0 {
return nil
}
out := make([]domain.Channel, 0, len(ids))
seen := make(map[int64]struct{}, len(ids))
for _, id := range ids {
if id == 0 {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
view, err := r.deps.Channels.GetChannel(ctx, currentUserID, id)
if err != nil || view.Channel.ID == 0 {
continue
}
out = append(out, view.Channel)
}
return out
}
func mergeDomainUsers(base []domain.User, extra ...domain.User) []domain.User {
out := append([]domain.User(nil), base...)
seen := make(map[int64]struct{}, len(out)+len(extra))
for _, u := range out {
if u.ID != 0 {
seen[u.ID] = struct{}{}
}
}
for _, u := range extra {
if u.ID == 0 {
continue
}
if _, ok := seen[u.ID]; ok {
continue
}
seen[u.ID] = struct{}{}
out = append(out, u)
}
return out
}
func mergeDomainChannels(base []domain.Channel, extra ...domain.Channel) []domain.Channel {
out := append([]domain.Channel(nil), base...)
seen := make(map[int64]struct{}, len(out)+len(extra))
for _, ch := range out {
if ch.ID != 0 {
seen[ch.ID] = struct{}{}
}
}
for _, ch := range extra {
if ch.ID == 0 {
continue
}
if _, ok := seen[ch.ID]; ok {
continue
}
seen[ch.ID] = struct{}{}
out = append(out, ch)
}
return out
}
func mapKeys(items map[int64]struct{}) []int64 {
if len(items) == 0 {
return nil
}
out := make([]int64, 0, len(items))
for id := range items {
if id != 0 {
out = append(out, id)
}
}
return out
}