92 lines
2.1 KiB
Go

package services
import (
"fmt"
"time"
"git.solsynth.dev/hypernet/messaging/pkg/internal/database"
"git.solsynth.dev/hypernet/messaging/pkg/internal/gap"
"git.solsynth.dev/hypernet/messaging/pkg/internal/models"
"git.solsynth.dev/hypernet/nexus/pkg/nex"
"git.solsynth.dev/hypernet/nexus/pkg/nex/cachekit"
"github.com/samber/lo"
"github.com/spf13/viper"
)
type statusQueryCacheEntry struct {
Target []uint64
Data any
}
func KgTypingStatusCache(channelId uint, userId uint) string {
return fmt.Sprintf("chat-typing-status#%d@%d", userId, channelId)
}
func SetTypingStatus(channelId uint, userId uint) error {
var broadcastTarget []uint64
var data any
hitCache := false
if val, err := cachekit.Get[statusQueryCacheEntry](
gap.Ca,
KgTypingStatusCache(channelId, userId),
); err == nil {
broadcastTarget = val.Target
data = val.Data
hitCache = true
}
if !hitCache {
var member models.ChannelMember
if err := database.C.
Where("account_id = ? AND channel_id = ?", userId, channelId).
First(&member).Error; err != nil {
return fmt.Errorf("channel member not found: %v", err)
}
var channel models.Channel
if err := database.C.
Preload("Members").
Where("id = ?", channelId).
First(&channel).Error; err != nil {
return fmt.Errorf("channel not found: %v", err)
}
for _, item := range channel.Members {
broadcastTarget = append(broadcastTarget, uint64(item.AccountID))
}
data = map[string]any{
"user_id": userId,
"member_id": member.ID,
"channel_id": channelId,
"member": member,
"channel": channel,
}
// Cache queries
cachekit.Set(
gap.Ca,
KgTypingStatusCache(channelId, userId),
statusQueryCacheEntry{broadcastTarget, data},
60*time.Minute,
fmt.Sprintf("channel#%d", channelId),
)
}
broadcastTarget = lo.Filter(broadcastTarget, func(item uint64, index int) bool {
if !viper.GetBool("performance.passive_user_optimize") {
// Leave this for backward compatibility
return true
}
return CheckSubscribed(uint(item), channelId)
})
PushCommandBatch(broadcastTarget, nex.WebSocketPackage{
Action: "status.typing",
Payload: data,
})
return nil
}