|
|
@@ -6,6 +6,7 @@ import (
|
|
|
"encoding/json"
|
|
|
"fmt"
|
|
|
"log"
|
|
|
+ "os"
|
|
|
"strconv"
|
|
|
"time"
|
|
|
|
|
|
@@ -22,6 +23,11 @@ var ctx = context.Background()
|
|
|
const (
|
|
|
UnreadMultiplier = 10000.0 // 未读消息数乘数,用于小数部分存储(增大乘数以提高精度)
|
|
|
ContactTTL = 7 * 24 * time.Hour // 最近联系人过期时间(7天)
|
|
|
+
|
|
|
+ // 门店用户类型
|
|
|
+ UserTypeShop = "shop"
|
|
|
+ // 顾客用户类型
|
|
|
+ UserTypeCustomer = "customer"
|
|
|
)
|
|
|
|
|
|
// ContactInfo 表示联系人信息
|
|
|
@@ -32,6 +38,26 @@ type ContactInfo struct {
|
|
|
ContactType string `json:"contact_type"` // 联系人类型(shop/customer)
|
|
|
}
|
|
|
|
|
|
+// 从环境变量初始化Redis连接
|
|
|
+func InitializeRedisFromEnv() error {
|
|
|
+ // 从环境变量获取Redis配置,如果没有设置则使用默认值
|
|
|
+ redisAddr := os.Getenv("REDIS_ADDR")
|
|
|
+ if redisAddr == "" {
|
|
|
+ redisAddr = "localhost:6379" // 默认Redis地址
|
|
|
+ }
|
|
|
+
|
|
|
+ redisPassword := os.Getenv("REDIS_PASSWORD") // 默认为空
|
|
|
+
|
|
|
+ redisDB := 0 // 默认数据库
|
|
|
+ if dbStr := os.Getenv("REDIS_DB"); dbStr != "" {
|
|
|
+ if db, err := strconv.Atoi(dbStr); err == nil {
|
|
|
+ redisDB = db
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return InitRedis(redisAddr, redisPassword, redisDB)
|
|
|
+}
|
|
|
+
|
|
|
// ChatMessage 表示存储在Redis中的聊天消息结构
|
|
|
type ChatMessage struct {
|
|
|
Content string `json:"content"` // 原始消息内容(JSON字符串)
|
|
|
@@ -123,9 +149,9 @@ func UpdateRecentContacts(client *Client) error {
|
|
|
|
|
|
currentTime := time.Now().Unix()
|
|
|
|
|
|
- if client.userInfo.Type == "shop" {
|
|
|
+ if client.userInfo.Type == UserTypeShop {
|
|
|
// 更新门店的联系人列表(客户)
|
|
|
- key := getContactKey("shop", client.userInfo.ShopId) // shop_chats:{ShopId}
|
|
|
+ key := getContactKey(UserTypeShop, client.userInfo.ShopId) // shop_chats:{ShopId}
|
|
|
if key != "" {
|
|
|
// 先获取当前未读消息数
|
|
|
// currentScore, err := redisClient.ZScore(ctx, key, strconv.Itoa(int(client.userInfo.CustomId))).Result()
|
|
|
@@ -145,7 +171,7 @@ func UpdateRecentContacts(client *Client) error {
|
|
|
}
|
|
|
|
|
|
// 更新客户的联系人列表(门店)
|
|
|
- key = getContactKey("customer", client.userInfo.UserId) // customer_chats:{UserId}
|
|
|
+ key = getContactKey(UserTypeCustomer, client.userInfo.UserId) // customer_chats:{UserId}
|
|
|
if key != "" {
|
|
|
// 先获取当前未读消息数
|
|
|
currentScore, err := redisClient.ZScore(ctx, key, strconv.Itoa(int(client.userInfo.ShopId))).Result()
|
|
|
@@ -165,9 +191,9 @@ func UpdateRecentContacts(client *Client) error {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if client.userInfo.Type == "customer" {
|
|
|
+ if client.userInfo.Type == UserTypeCustomer {
|
|
|
// 更新客户的联系人列表(门店)
|
|
|
- key := getContactKey("customer", client.userInfo.UserId) // customer_chats:{UserId}
|
|
|
+ key := getContactKey(UserTypeCustomer, client.userInfo.UserId) // customer_chats:{UserId}
|
|
|
if key != "" {
|
|
|
// 先获取当前未读消息数
|
|
|
// currentScore, err := redisClient.ZScore(ctx, key, strconv.Itoa(int(client.userInfo.ShopId))).Result()
|
|
|
@@ -187,7 +213,7 @@ func UpdateRecentContacts(client *Client) error {
|
|
|
}
|
|
|
|
|
|
// 更新门店的联系人列表(客户)
|
|
|
- key = getContactKey("shop", client.userInfo.ShopId) // shop_chats:{ShopId}
|
|
|
+ key = getContactKey(UserTypeShop, client.userInfo.ShopId) // shop_chats:{ShopId}
|
|
|
if key != "" {
|
|
|
// 先获取当前未读消息数
|
|
|
currentScore, err := redisClient.ZScore(ctx, key, strconv.Itoa(int(client.userInfo.CustomId))).Result()
|
|
|
@@ -224,14 +250,14 @@ func IncrementUnreadCount(sender *Client, count int) error {
|
|
|
var receiverID int32
|
|
|
var senderMember string
|
|
|
|
|
|
- if sender.userInfo.Type == "shop" {
|
|
|
+ if sender.userInfo.Type == UserTypeShop {
|
|
|
// 门店发送消息给客户,接收者是客户
|
|
|
- receiverType = "customer"
|
|
|
+ receiverType = UserTypeCustomer
|
|
|
receiverID = sender.userInfo.UserId
|
|
|
senderMember = strconv.Itoa(int(sender.userInfo.ShopId))
|
|
|
- } else if sender.userInfo.Type == "customer" {
|
|
|
+ } else if sender.userInfo.Type == UserTypeCustomer {
|
|
|
// 客户发送消息给门店,接收者是门店
|
|
|
- receiverType = "shop"
|
|
|
+ receiverType = UserTypeShop
|
|
|
receiverID = sender.userInfo.ShopId
|
|
|
senderMember = strconv.Itoa(int(sender.userInfo.CustomId))
|
|
|
} else {
|
|
|
@@ -339,12 +365,17 @@ func parseScore(score float64) (timestamp int64, unreadCount int) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
-// getContactKey 生成联系人的Redis键
|
|
|
-func getContactKey(userType string, userID int32) string {
|
|
|
- if userType == "shop" {
|
|
|
- return "shop_chats:" + strconv.Itoa(int(userID))
|
|
|
- } else if userType == "customer" {
|
|
|
- return "customer_chats:" + strconv.Itoa(int(userID))
|
|
|
+/**
|
|
|
+* 生成联系人的Redis键
|
|
|
+* @param userType 用户类型
|
|
|
+* @param id 用户ID -- shopId 或 userId
|
|
|
+* @return 联系人的Redis键
|
|
|
+*/
|
|
|
+func getContactKey(userType string, id int32) string {
|
|
|
+ if userType == UserTypeShop {
|
|
|
+ return "shop_chats:" + strconv.Itoa(int(id))
|
|
|
+ } else if userType == UserTypeCustomer {
|
|
|
+ return "customer_chats:" + strconv.Itoa(int(id))
|
|
|
}
|
|
|
return ""
|
|
|
}
|
|
|
@@ -380,9 +411,9 @@ func GetRecentContacts(userType string, userID int32, limit int64) ([]ContactInf
|
|
|
timestamp, unreadCount := parseScore(item.Score)
|
|
|
|
|
|
// 确定联系人的类型
|
|
|
- contactType := "customer"
|
|
|
- if userType == "customer" {
|
|
|
- contactType = "shop"
|
|
|
+ contactType := UserTypeCustomer
|
|
|
+ if userType == UserTypeCustomer {
|
|
|
+ contactType = UserTypeShop
|
|
|
}
|
|
|
|
|
|
contact := ContactInfo{
|
|
|
@@ -425,23 +456,44 @@ func GetTotalUnreadCount(userType string, userID int32) (int, error) {
|
|
|
return totalUnread, nil
|
|
|
}
|
|
|
|
|
|
-// ClearUnreadCount 清除指定联系人的未读消息数
|
|
|
-func ClearUnreadCount(userType string, userID int32, contactID int32) error {
|
|
|
+/**
|
|
|
+* 清除指定联系人的未读消息数
|
|
|
+* @param client 客户端
|
|
|
+* @return 错误
|
|
|
+*/
|
|
|
+func ClearUnreadCount(client *Client) error {
|
|
|
+ id := client.userInfo.ShopId
|
|
|
+ contactID := client.userInfo.UserId
|
|
|
+ if client.userInfo.Type == UserTypeCustomer {
|
|
|
+ id = client.userInfo.UserId
|
|
|
+ contactID = client.userInfo.ShopId
|
|
|
+ }
|
|
|
+
|
|
|
if redisClient == nil {
|
|
|
log.Println("Redis客户端未初始化")
|
|
|
- return nil
|
|
|
+ return fmt.Errorf("redis client is not initialized")
|
|
|
}
|
|
|
|
|
|
- key := getContactKey(userType, userID)
|
|
|
+ key := getContactKey(client.userInfo.Type, id)
|
|
|
if key == "" {
|
|
|
- return fmt.Errorf("无效的用户类型: %s", userType)
|
|
|
+ log.Printf("无效的用户类型: %s", client.userInfo.Type)
|
|
|
+ return fmt.Errorf("invalid user type: %s", client.userInfo.Type)
|
|
|
}
|
|
|
|
|
|
+ contactIDStr := strconv.Itoa(int(contactID))
|
|
|
// 获取当前分数
|
|
|
- currentScore, err := redisClient.ZScore(ctx, key, strconv.Itoa(int(contactID))).Result()
|
|
|
+ currentScore, err := redisClient.ZScore(ctx, key, contactIDStr).Result()
|
|
|
if err != nil {
|
|
|
- // 如果联系人不存在,不需要清理
|
|
|
- return nil
|
|
|
+ if err == redis.Nil {
|
|
|
+ // 如果联系人不存在,这并非一个错误,只是无需清理。
|
|
|
+ log.Printf("Contact not found, no unread count to clear - UserType: %s, UserID: %d, ContactID: %d",
|
|
|
+ client.userInfo.Type, id, contactID)
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ // 对于其他类型的错误(如连接问题),则返回错误。
|
|
|
+ log.Printf("failed to get score for contact - UserType: %s, UserID: %d, ContactID: %d, Error: %v",
|
|
|
+ client.userInfo.Type, id, contactID, err)
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
// 解析当前分数,保留时间戳,清除未读消息数
|
|
|
@@ -449,12 +501,16 @@ func ClearUnreadCount(userType string, userID int32, contactID int32) error {
|
|
|
newScore := calculateScore(timestamp, 0)
|
|
|
|
|
|
// 更新分数
|
|
|
- redisClient.ZAdd(ctx, key, redis.Z{
|
|
|
+ if err := redisClient.ZAdd(ctx, key, redis.Z{
|
|
|
Score: newScore,
|
|
|
- Member: strconv.Itoa(int(contactID)),
|
|
|
- })
|
|
|
+ Member: contactIDStr,
|
|
|
+ }).Err(); err != nil {
|
|
|
+ log.Printf("failed to clear unread count - UserType: %s, UserID: %d, ContactID: %d, Error: %v",
|
|
|
+ client.userInfo.Type, id, contactID, err)
|
|
|
+ return err
|
|
|
+ }
|
|
|
|
|
|
log.Printf("未读消息数已清除 - 用户类型: %s, 用户ID: %d, 联系人ID: %d",
|
|
|
- userType, userID, contactID)
|
|
|
+ client.userInfo.Type, id, contactID)
|
|
|
return nil
|
|
|
}
|