package chat import ( "bet24.com/log" "bet24.com/redis" user "bet24.com/servers/micros/userservices/proto" "encoding/json" "fmt" "sort" "strconv" "strings" "time" ) func SplitToString(a []int, sep string) string { if len(a) == 0 { return "" } b := make([]string, len(a)) for i, v := range a { b[i] = strconv.Itoa(v) } return strings.Join(b, sep) } func getChannelKey(userIds []int) string { sort.Slice(userIds, func(i, j int) bool { return userIds[i] < userIds[j] }) return SplitToString(userIds, "+") } const CHAT_TIME_OUT = 1800 const MAX_ARCHIVE_MESSAGE = 20 const MAX_ARCHIVE_TIME = 432000 // 5天 const MAX_MESSAGE_LEN = 256 const ONE_DAY = 86400 type ChannelUser struct { UserId int NickName string FaceId int FaceUrl string ReadIndex int // 实际读到哪条了 getIndex int // 取内容标签,用户退出重进后,需要拉所有记录 ClearIndex int Decorations []user.UserDecoration Vip int VipPoint int VipExpire int } type chatMsg struct { Sender int Message string SendTime string Index int MsgType int } type channel struct { //userIds []int // 参与的用户 Key string Users []*ChannelUser MessageList []chatMsg lastAck time.Time ChatIndex int } func newChannel(users []*ChannelUser) *channel { c := new(channel) c.Users = users if len(c.Users) >= 2 { var userIds []int for _, v := range users { userIds = append(userIds, v.UserId) } c.Key = getChannelKey(userIds) c.restore() for _, v := range users { c.updateUser(v) } } c.touch() return c } func createChannelByKey(key string) *channel { c := new(channel) c.Key = key if !c.restore() { return nil } return c } func (c *channel) isUserExist(userId int) bool { for _, v := range c.Users { if v.UserId == userId { return true } } return false } func (c *channel) isIdle() bool { return int(time.Now().Sub(c.lastAck).Seconds()) >= CHAT_TIME_OUT } func (c *channel) addUser(userId int, nickName string, faceId int, faceUrl string) { if c.isUserExist(userId) { log.Release("channel.addUser userId[%d] exist", userId) return } channelUser := &ChannelUser{ UserId: userId, NickName: nickName, FaceId: faceId, FaceUrl: faceUrl, } usr := user.GetUserInfo(userId) if usr != nil { channelUser.Vip = usr.Vip channelUser.VipPoint = usr.VipPoint channelUser.VipExpire = usr.VipExpire channelUser.Decorations = usr.Decorations } c.Users = append(c.Users, channelUser) if len(c.Users) >= 2 { var userIds []int for _, v := range c.Users { userIds = append(userIds, v.UserId) } c.Key = getChannelKey(userIds) c.restore() } c.touch() } func (c *channel) updateUser(userInfo *ChannelUser) { if userInfo.NickName == "" { return } for _, v := range c.Users { if v.UserId == userInfo.UserId { v.NickName = userInfo.NickName v.FaceId = userInfo.FaceId v.FaceUrl = userInfo.FaceUrl } } } func (c *channel) touch() { c.lastAck = time.Now() } func (c *channel) addChat(userId int, message string, msgType int) { if !c.isUserExist(userId) { log.Release("channel.addChat userId %d not exist", userId) return } if len(message) > MAX_MESSAGE_LEN && msgType == 0 { message = message[:MAX_MESSAGE_LEN] } c.MessageList = append(c.MessageList, chatMsg{ Sender: userId, Message: message, SendTime: time.Now().Format("2006-01-02 15:04:05"), Index: c.ChatIndex, MsgType: msgType, }) c.ChatIndex++ c.touch() } func (c *channel) getClearReadIndex(clearIndex, readIndex int) int { if clearIndex == 0 { return readIndex } ret := len(c.MessageList) for i := 0; i < len(c.MessageList); i++ { if c.MessageList[i].Index >= clearIndex { ret = i break } } if ret > readIndex { return ret } return readIndex } func (c *channel) getChatByUser(userId int) string { // 获取用户当前读取 var ch channel ch.Key = c.Key readIndex := 0 needUserInfo := false for _, v := range c.Users { if v.UserId == userId { readIndex = v.getIndex needUserInfo = readIndex == 0 // 判断一下是否Clear readIndex = c.getClearReadIndex(v.ClearIndex, readIndex) v.ReadIndex = len(c.MessageList) v.getIndex = v.ReadIndex } } // 是否需要玩家信息? if needUserInfo { for _, v := range c.Users { if v.UserId == userId { continue } ch.Users = append(ch.Users, v) } } if readIndex > len(c.MessageList) { readIndex = len(c.MessageList) } ch.MessageList = c.MessageList[readIndex:] d, _ := json.Marshal(ch) return string(d) } func (c *channel) dump() { log.Release("channel.dump[%s] ChatIndex[%d] ----------", c.Key, c.ChatIndex) defer log.Release("channel.dump end ++++++++++++++++") log.Release(" userlist") for _, v := range c.Users { log.Release(" [%d]%s ReadIndex[%d] ClearIndex[%d]Vip[%d]", v.UserId, v.NickName, v.ReadIndex, v.ClearIndex, v.Vip) } log.Release(" chatlist") for _, v := range c.MessageList { log.Release(" [%d][%d]%s", v.Index, v.Sender, v.Message) } } func (c *channel) isInvolved(userId int) bool { for _, v := range c.Users { if v.UserId == userId { return true } } return false } func (c *channel) release() { count := len(c.MessageList) - MAX_ARCHIVE_MESSAGE if count > 0 { c.MessageList = c.MessageList[count:] for _, v := range c.Users { v.ReadIndex -= count if v.ReadIndex < 0 { v.ReadIndex = 0 } //v.getIndex = v.ReadIndex } } c.archive() } func (c *channel) getRedisKey() string { return fmt.Sprintf("channel:%s", c.Key) } func (c *channel) archive() { d, _ := json.Marshal(c) redis.String_SetEx(c.getRedisKey(), string(d), MAX_ARCHIVE_TIME) } func (c *channel) removeFromRedis() { redis.Key_Del(c.getRedisKey()) } func (c *channel) restore() bool { data, ok := redis.String_Get(c.getRedisKey()) if !ok || data == "" { return false } json.Unmarshal([]byte(data), &c) for _, v := range c.Users { usr := user.GetUserInfo(v.UserId) if usr != nil { v.Vip = usr.Vip v.VipPoint = usr.VipPoint v.VipExpire = usr.VipExpire v.Decorations = usr.Decorations } v.ReadIndex = 0 v.getIndex = 0 } c.touch() return true } func (c *channel) onUserExit(userId int) { for _, v := range c.Users { if v.UserId == userId { v.getIndex = 0 return } } log.Release("channel.onUserExit user[%d] not involve", userId) } func (c *channel) getNewChatCount(userId int) int { ret := 0 for _, v := range c.Users { if v.UserId == userId { v.ReadIndex = c.getClearReadIndex(v.ClearIndex, v.ReadIndex) ret = len(c.MessageList) - v.ReadIndex } } if ret < 0 { ret = 0 } return ret } func (c *channel) getLatestMessage() string { if len(c.MessageList) == 0 { return "" } return c.MessageList[len(c.MessageList)-1].Message } func (c *channel) getLatestTime() string { if len(c.MessageList) == 0 { return "" } return c.MessageList[len(c.MessageList)-1].SendTime } func (c *channel) getLatestMessageType() int { if len(c.MessageList) == 0 { return 0 } return c.MessageList[len(c.MessageList)-1].MsgType } func (c *channel) getInfo() string { var ch channel ch.Key = c.Key for _, v := range c.Users { ch.Users = append(ch.Users, v) } d, _ := json.Marshal(ch) return string(d) } func (c *channel) userClear(userId int) { log.Debug("channel.userClear %d", userId) for _, v := range c.Users { if v.UserId == userId { v.ClearIndex = c.ChatIndex return } } }