owpengram-server/internal/rpc/channel_interest.go
2026-07-24 14:50:17 +08:00

207 lines
5.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rpc
import (
"context"
"time"
"go.uber.org/zap"
"telesrv/internal/domain"
)
const channelMembershipSyncPageSize = domain.MaxSynchronousChannelDialogFanout
const publicChannelSubscriptionTTL = 75 * time.Second
func (r *Router) trackChannelInterest(ctx context.Context, userID int64, channelIDs ...int64) {
if userID == 0 || r.deps.Sessions == nil {
return
}
provider, ok := r.deps.Sessions.(OnlineUserProvider)
if !ok {
return
}
rawAuthKeyID, ok := RawAuthKeyIDFrom(ctx)
if !ok {
return
}
sessionID, ok := SessionIDFrom(ctx)
if !ok {
return
}
if len(channelIDs) == 0 {
provider.ClearChannelInterest(rawAuthKeyID, sessionID, userID)
return
}
provider.TrackChannelInterest(rawAuthKeyID, sessionID, userID, channelIDs)
}
func (r *Router) clearChannelInterest(ctx context.Context, userID int64) {
r.trackChannelInterest(ctx, userID)
}
func (r *Router) refreshPublicChannelSubscription(ctx context.Context, userID, channelID int64) {
if userID == 0 || channelID == 0 || r.deps.Sessions == nil {
return
}
provider, ok := r.deps.Sessions.(ChannelSubscriptionProvider)
if !ok {
return
}
rawAuthKeyID, ok := RawAuthKeyIDFrom(ctx)
if !ok {
return
}
sessionID, ok := SessionIDFrom(ctx)
if !ok {
return
}
provider.RefreshChannelSubscription(rawAuthKeyID, sessionID, userID, channelID, publicChannelSubscriptionTTL)
}
func (r *Router) syncSessionChannelMemberships(ctx context.Context, userID int64) {
if userID == 0 || r.deps.Sessions == nil || r.deps.Channels == nil {
return
}
provider, ok := r.deps.Sessions.(OnlineUserProvider)
if !ok {
return
}
rawAuthKeyID, ok := RawAuthKeyIDFrom(ctx)
if !ok {
return
}
sessionID, ok := SessionIDFrom(ctx)
if !ok {
return
}
// 在读取持久成员列表之前采样修订号:读取窗口内若发生增量 join/leave
// AddUserChannelMembership/RemoveUserChannelMembership全量替换会覆盖增量
// SetSessionChannelMemberships 据此改走合并路径并保持未就绪重试。
expectedGen := provider.ChannelMembershipGeneration(rawAuthKeyID, sessionID)
channelIDs := make([]int64, 0, channelMembershipSyncPageSize)
after := int64(0)
for {
page, err := r.deps.Channels.ActiveChannelIDsForUser(ctx, userID, after, channelMembershipSyncPageSize)
if err != nil {
r.log.Warn("sync session channel memberships failed",
zap.Int64("user_id", userID),
zap.Int64("after_channel_id", after),
zap.Error(err))
return
}
if len(page) == 0 {
break
}
progressed := false
for _, channelID := range page {
if channelID == 0 {
continue
}
channelIDs = append(channelIDs, channelID)
if channelID > after {
after = channelID
progressed = true
}
}
if !progressed || len(page) < channelMembershipSyncPageSize {
break
}
}
provider.SetSessionChannelMemberships(rawAuthKeyID, sessionID, userID, channelIDs, expectedGen)
}
func (r *Router) addOnlineChannelMemberships(channelID int64, userIDs ...int64) {
if channelID == 0 || len(userIDs) == 0 || r.deps.Sessions == nil {
return
}
provider, ok := r.deps.Sessions.(OnlineUserProvider)
if !ok {
return
}
seen := make(map[int64]struct{}, len(userIDs))
for _, userID := range userIDs {
if userID == 0 {
continue
}
if _, ok := seen[userID]; ok {
continue
}
seen[userID] = struct{}{}
provider.AddUserChannelMembership(userID, channelID)
}
}
func (r *Router) removeOnlineChannelMemberships(channelID int64, userIDs ...int64) {
if channelID == 0 || len(userIDs) == 0 || r.deps.Sessions == nil {
return
}
provider, ok := r.deps.Sessions.(OnlineUserProvider)
if !ok {
return
}
seen := make(map[int64]struct{}, len(userIDs))
for _, userID := range userIDs {
if userID == 0 {
continue
}
if _, ok := seen[userID]; ok {
continue
}
seen[userID] = struct{}{}
provider.RemoveUserChannelMembership(userID, channelID)
}
}
func (r *Router) removeOnlineChannelMembershipsForOnlineMembers(channelID int64) {
if channelID == 0 || r.deps.Sessions == nil {
return
}
provider, ok := r.deps.Sessions.(OnlineUserProvider)
if !ok {
return
}
r.removeOnlineChannelMemberships(channelID, provider.OnlineChannelMemberUserIDs(channelID, 0)...)
}
func channelMemberUserIDs(members []domain.ChannelMember) []int64 {
if len(members) == 0 {
return nil
}
ids := make([]int64, 0, len(members))
for _, member := range members {
if member.UserID == 0 || member.Status != domain.ChannelMemberActive {
continue
}
ids = append(ids, member.UserID)
}
return ids
}
func channelIDsFromDialogs(list domain.DialogList) []int64 {
if len(list.Dialogs) == 0 && len(list.Channels) == 0 {
return nil
}
ids := make([]int64, 0, len(list.Dialogs)+len(list.Channels))
seen := make(map[int64]struct{}, len(list.Dialogs)+len(list.Channels))
for _, d := range list.Dialogs {
if d.Peer.Type != domain.PeerTypeChannel || d.Peer.ID == 0 {
continue
}
if _, ok := seen[d.Peer.ID]; ok {
continue
}
seen[d.Peer.ID] = struct{}{}
ids = append(ids, d.Peer.ID)
}
for _, ch := range list.Channels {
if ch.ID == 0 {
continue
}
if _, ok := seen[ch.ID]; ok {
continue
}
seen[ch.ID] = struct{}{}
ids = append(ids, ch.ID)
}
return ids
}