Skip to content

Commit eed80d0

Browse files
committed
🎨 添加map
1 parent 1212f8e commit eed80d0

File tree

2 files changed

+162
-79
lines changed

2 files changed

+162
-79
lines changed

plugin/chatcount/chatcount.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
)
1616

1717
const (
18-
rankSize = 15
18+
rankSize = 10
1919
)
2020

2121
func init() {
@@ -30,16 +30,16 @@ func init() {
3030
}()
3131
engine.OnMessage(zero.OnlyGroup).SetBlock(false).
3232
Handle(func(ctx *zero.Ctx) {
33-
todayTime, remindFlag := ctdb.updateChatTime(ctx.Event.GroupID, ctx.Event.UserID)
33+
remindTime, remindFlag := ctdb.updateChatTime(ctx.Event.GroupID, ctx.Event.UserID)
3434
if remindFlag {
35-
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("BOT提醒:你今天已经水群%d分钟了!", todayTime)))
35+
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("BOT提醒:你今天已经水群%d分钟了!", remindTime)))
3636
}
3737
})
3838

3939
engine.OnPrefix(`查询水群`, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
4040
name := ctx.NickName()
41-
todayTime, totalTime := ctdb.getChatTime(ctx.Event.GroupID, ctx.Event.UserID)
42-
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf("%s今天水了%d分钟,总计%d分钟。", name, todayTime, totalTime)))
41+
todayTime, todayMessage, totalTime, totalMessage := ctdb.getChatTime(ctx.Event.GroupID, ctx.Event.UserID)
42+
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf("%s今天水了%d分%d秒,发了%d条消息;总计水了%d分%d秒,发了%d条消息。", name, todayTime/60, todayTime%60, todayMessage, totalTime/60, totalTime%60, totalMessage)))
4343
})
4444
engine.OnFullMatch("查看水群排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
4545
Handle(func(ctx *zero.Ctx) {
@@ -52,8 +52,12 @@ func init() {
5252
text.WriteString("名:")
5353
text.WriteString(ctx.CardOrNickName(chatTimeList[i].UserID))
5454
text.WriteString(" - ")
55+
text.WriteString(strconv.FormatInt(chatTimeList[i].TodayMessage, 10))
56+
text.WriteString("条,共")
5557
text.WriteString(strconv.FormatInt(chatTimeList[i].TodayTime/60, 10))
56-
text.WriteString("分钟\n")
58+
text.WriteString("分")
59+
text.WriteString(strconv.FormatInt(chatTimeList[i].TodayTime%60, 10))
60+
text.WriteString("秒\n")
5761
}
5862
ctx.SendChain(message.Text(text.String()))
5963
})

plugin/chatcount/model.go

Lines changed: 152 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package chatcount
22

33
import (
4+
"fmt"
45
"os"
6+
"sort"
7+
"strconv"
8+
"strings"
59
"sync"
610
"time"
711

12+
"github.com/RomiChan/syncx"
13+
814
"github.com/jinzhu/gorm"
915
)
1016

@@ -15,14 +21,23 @@ const (
1521
var (
1622
// ctdb 聊天时长数据库全局变量
1723
ctdb *chattimedb
18-
// levelArray 水群提醒时间提醒段,单位分钟
19-
levelArray = [...]int{15, 30, 60, 120, 240}
20-
// chatmu 读写添加锁
21-
chatmu sync.Mutex
24+
// leveler 水群提醒时间提醒段,单位分钟
25+
leveler = NewLeveler([]int{60, 120, 180, 240, 300})
2226
)
2327

2428
// chattimedb 聊天时长数据库结构体
25-
type chattimedb gorm.DB
29+
type chattimedb struct {
30+
// ctdb.userTimestampMap 每个人发言的时间戳 key=groupID_userID
31+
userTimestampMap syncx.Map[string, int64]
32+
// ctdb.userTodayTimeMap 每个人今日水群时间 key=groupID_userID
33+
userTodayTimeMap syncx.Map[string, int64]
34+
// ctdb.userTodayMessageMap 每个人今日水群次数 key=groupID_userID
35+
userTodayMessageMap syncx.Map[string, int64]
36+
// db 数据库
37+
db *gorm.DB
38+
// chatmu 读写添加锁
39+
chatmu sync.Mutex
40+
}
2641

2742
// initialize 初始化
2843
func initialize(dbpath string) *chattimedb {
@@ -39,105 +54,169 @@ func initialize(dbpath string) *chattimedb {
3954
if err != nil {
4055
panic(err)
4156
}
42-
gdb.AutoMigrate(&ChatTime{})
43-
return (*chattimedb)(gdb)
57+
gdb.AutoMigrate(&chatTime{})
58+
return &chattimedb{
59+
db: gdb,
60+
}
4461
}
4562

4663
// Close 关闭
4764
func (ctdb *chattimedb) Close() error {
48-
db := (*gorm.DB)(ctdb)
65+
db := (*gorm.DB)(ctdb.db)
4966
return db.Close()
5067
}
5168

52-
// ChatTime 聊天时长,时间的单位都是秒
53-
type ChatTime struct {
54-
ID uint `gorm:"primary_key"`
55-
GroupID int64 `gorm:"column:group_id"`
56-
UserID int64 `gorm:"column:user_id"`
57-
LastTime time.Time `gorm:"column:last_time"`
58-
TodayTime int64 `gorm:"column:today_time;default:0"`
59-
TotalTime int64 `gorm:"column:total_time;default:0"`
69+
// chatTime 聊天时长,时间的单位都是秒
70+
type chatTime struct {
71+
ID uint `gorm:"primary_key"`
72+
GroupID int64 `gorm:"column:group_id"`
73+
UserID int64 `gorm:"column:user_id"`
74+
TodayTime int64 `gorm:"-"`
75+
TodayMessage int64 `gorm:"-"`
76+
TotalTime int64 `gorm:"column:total_time;default:0"`
77+
TotalMessage int64 `gorm:"column:total_message;default:0"`
6078
}
6179

6280
// TableName 表名
63-
func (ChatTime) TableName() string {
81+
func (chatTime) TableName() string {
6482
return "chat_time"
6583
}
6684

6785
// updateChatTime 更新发言时间,todayTime的单位是分钟
68-
func (ctdb *chattimedb) updateChatTime(gid, uid int64) (todayTime int64, remindFlag bool) {
69-
chatmu.Lock()
70-
defer chatmu.Unlock()
71-
db := (*gorm.DB)(ctdb)
86+
func (ctdb *chattimedb) updateChatTime(gid, uid int64) (remindTime int64, remindFlag bool) {
87+
ctdb.chatmu.Lock()
88+
defer ctdb.chatmu.Unlock()
89+
db := (*gorm.DB)(ctdb.db)
7290
now := time.Now()
73-
st := ChatTime{
74-
GroupID: gid,
75-
UserID: uid,
76-
LastTime: now,
91+
keyword := fmt.Sprintf("%v_%v", gid, uid)
92+
ts, ok := ctdb.userTimestampMap.Load(keyword)
93+
if !ok {
94+
ctdb.userTimestampMap.Store(keyword, now.Unix())
95+
return
7796
}
78-
if err := db.Model(&ChatTime{}).Where("group_id = ? and user_id = ?", gid, uid).First(&st).Error; err != nil {
79-
if gorm.IsRecordNotFoundError(err) {
80-
db.Model(&ChatTime{}).Create(&st)
81-
}
82-
} else {
83-
// 如果不是同一天,把todayTime重置
84-
if st.LastTime.YearDay() != now.YearDay() {
85-
db.Model(&ChatTime{}).Where("group_id = ? and user_id = ?", gid, uid).Update(
97+
lastTime := time.Unix(ts, 0)
98+
todayTime, _ := ctdb.userTodayTimeMap.Load(keyword)
99+
totayMessage, _ := ctdb.userTodayMessageMap.Load(keyword)
100+
st := chatTime{
101+
GroupID: gid,
102+
UserID: uid,
103+
TotalTime: todayTime,
104+
TotalMessage: totayMessage,
105+
}
106+
107+
// 如果不是同一天,把TotalTime,TotalMessage重置
108+
if lastTime.YearDay() != now.YearDay() {
109+
if err := db.Model(&st).Where("group_id = ? and user_id = ?", gid, uid).First(&st).Error; err != nil {
110+
if gorm.IsRecordNotFoundError(err) {
111+
db.Model(&st).Create(&st)
112+
}
113+
} else {
114+
db.Model(&st).Where("group_id = ? and user_id = ?", gid, uid).Update(
86115
map[string]any{
87-
"last_time": now,
88-
"today_time": 0,
116+
"total_time": st.TotalTime + todayTime,
117+
"total_message": st.TotalMessage + totayMessage,
89118
})
90-
} else {
91-
userChatTime := int64(now.Sub(st.LastTime).Seconds())
92-
// 当聊天时间间隔很大的话,则不计入时长
93-
if userChatTime < chatInterval {
94-
db.Model(&ChatTime{}).Where("group_id = ? and user_id = ?", gid, uid).Update(
95-
map[string]any{
96-
"last_time": now,
97-
"today_time": st.TodayTime + userChatTime,
98-
"total_time": st.TotalTime + userChatTime,
99-
})
100-
todayTime = (st.TodayTime + userChatTime) / 60
101-
remindFlag = getLevel(int(st.TodayTime+userChatTime)/60) > getLevel(int(st.TodayTime/60))
102-
} else {
103-
db.Model(&ChatTime{}).Where("group_id = ? and user_id = ?", gid, uid).Update(
104-
map[string]any{
105-
"last_time": now,
106-
})
107-
}
108-
109119
}
120+
ctdb.userTimestampMap.Store(keyword, now.Unix())
121+
ctdb.userTodayTimeMap.Delete(keyword)
122+
ctdb.userTodayMessageMap.Delete(keyword)
123+
return
124+
}
125+
126+
userChatTime := int64(now.Sub(lastTime).Seconds())
127+
// 当聊天时间在一定范围内的话,则计入时长
128+
if userChatTime < chatInterval {
129+
ctdb.userTodayTimeMap.Store(keyword, todayTime+userChatTime)
130+
ctdb.userTodayMessageMap.Store(keyword, totayMessage+1)
131+
remindTime = (todayTime + userChatTime) / 60
132+
remindFlag = leveler.Level(int((todayTime+userChatTime)/60)) > leveler.Level(int(todayTime/60))
110133
}
134+
ctdb.userTimestampMap.Store(keyword, now.Unix())
111135
return
112136
}
113137

114-
// getChatTime 获得用户聊天时长,todayTime,totalTime的单位是分钟
115-
func (ctdb *chattimedb) getChatTime(gid, uid int64) (todayTime int64, totalTime int64) {
116-
chatmu.Lock()
117-
defer chatmu.Unlock()
118-
db := (*gorm.DB)(ctdb)
119-
st := ChatTime{}
120-
db.Model(&ChatTime{}).Where("group_id = ? and user_id = ?", gid, uid).First(&st)
121-
todayTime = st.TodayTime / 60
122-
totalTime = st.TotalTime / 60
138+
// getChatTime 获得用户聊天时长和消息次数,todayTime,totalTime的单位是秒,todayMessage,totalMessage单位是条数
139+
func (ctdb *chattimedb) getChatTime(gid, uid int64) (todayTime, todayMessage, totalTime, totalMessage int64) {
140+
ctdb.chatmu.Lock()
141+
defer ctdb.chatmu.Unlock()
142+
db := (*gorm.DB)(ctdb.db)
143+
st := chatTime{}
144+
db.Model(&st).Where("group_id = ? and user_id = ?", gid, uid).First(&st)
145+
keyword := fmt.Sprintf("%v_%v", gid, uid)
146+
todayTime, _ = ctdb.userTodayTimeMap.Load(keyword)
147+
todayMessage, _ = ctdb.userTodayMessageMap.Load(keyword)
148+
totalTime = st.TotalTime
149+
totalMessage = st.TotalMessage
123150
return
124151
}
125152

126-
// getChatRank 获得水群排名
127-
func (ctdb *chattimedb) getChatRank(gid int64) (chatTimeList []ChatTime) {
128-
chatmu.Lock()
129-
defer chatmu.Unlock()
130-
db := (*gorm.DB)(ctdb)
131-
db.Model(&ChatTime{}).Where("group_id = ?", gid).Order("today_time DESC").Find(&chatTimeList)
153+
// getChatRank 获得水群排名,时间单位为秒
154+
func (ctdb *chattimedb) getChatRank(gid int64) (chatTimeList []chatTime) {
155+
ctdb.chatmu.Lock()
156+
defer ctdb.chatmu.Unlock()
157+
chatTimeList = make([]chatTime, 0, 100)
158+
keyList := make([]string, 0, 100)
159+
ctdb.userTimestampMap.Range(func(key string, value int64) bool {
160+
t := time.Unix(value, 0)
161+
if strings.Contains(key, strconv.FormatInt(gid, 10)) && t.YearDay() == time.Now().YearDay() {
162+
keyList = append(keyList, key)
163+
}
164+
return true
165+
})
166+
for _, v := range keyList {
167+
_, a, _ := strings.Cut(v, "_")
168+
uid, _ := strconv.ParseInt(a, 10, 64)
169+
todayTime, _ := ctdb.userTodayTimeMap.Load(v)
170+
todayMessage, _ := ctdb.userTodayMessageMap.Load(v)
171+
chatTimeList = append(chatTimeList, chatTime{
172+
GroupID: gid,
173+
UserID: uid,
174+
TodayTime: todayTime,
175+
TodayMessage: todayMessage,
176+
})
177+
}
178+
sort.Sort(ByTotalTimeDescMessageDesc(chatTimeList))
132179
return
133180
}
134181

135-
// getLevel 用时长判断等级
136-
func getLevel(t int) int {
137-
for i := len(levelArray) - 1; i >= 0; i-- {
138-
if t >= levelArray[i] {
182+
// Leveler 结构体,包含一个 levelArray 字段
183+
type Leveler struct {
184+
levelArray []int
185+
}
186+
187+
// NewLeveler 构造函数,用于创建 Leveler 实例
188+
func NewLeveler(levels []int) *Leveler {
189+
return &Leveler{
190+
levelArray: levels,
191+
}
192+
}
193+
194+
// Level 方法,封装了 getLevel 函数的逻辑
195+
func (l *Leveler) Level(t int) int {
196+
for i := len(l.levelArray) - 1; i >= 0; i-- {
197+
if t >= l.levelArray[i] {
139198
return i + 1
140199
}
141200
}
142201
return 0
143202
}
203+
204+
type ByTotalTimeDescMessageDesc []chatTime
205+
206+
// Len 实现 sort.Interface
207+
func (a ByTotalTimeDescMessageDesc) Len() int {
208+
return len(a)
209+
}
210+
211+
// Less 实现 sort.Interface,按 TotalTime 降序,TotalMessage 降序
212+
func (a ByTotalTimeDescMessageDesc) Less(i, j int) bool {
213+
if a[i].TotalTime == a[j].TotalTime {
214+
return a[i].TotalMessage > a[j].TotalMessage
215+
}
216+
return a[i].TotalTime > a[j].TotalTime
217+
}
218+
219+
// Swap 实现 sort.Interface
220+
func (a ByTotalTimeDescMessageDesc) Swap(i, j int) {
221+
a[i], a[j] = a[j], a[i]
222+
}

0 commit comments

Comments
 (0)