1
1
package chatcount
2
2
3
3
import (
4
+ "fmt"
4
5
"os"
6
+ "sort"
7
+ "strconv"
8
+ "strings"
5
9
"sync"
6
10
"time"
7
11
12
+ "github.com/RomiChan/syncx"
13
+
8
14
"github.com/jinzhu/gorm"
9
15
)
10
16
@@ -15,14 +21,23 @@ const (
15
21
var (
16
22
// ctdb 聊天时长数据库全局变量
17
23
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 })
22
26
)
23
27
24
28
// 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
+ }
26
41
27
42
// initialize 初始化
28
43
func initialize (dbpath string ) * chattimedb {
@@ -39,105 +54,169 @@ func initialize(dbpath string) *chattimedb {
39
54
if err != nil {
40
55
panic (err )
41
56
}
42
- gdb .AutoMigrate (& ChatTime {})
43
- return (* chattimedb )(gdb )
57
+ gdb .AutoMigrate (& chatTime {})
58
+ return & chattimedb {
59
+ db : gdb ,
60
+ }
44
61
}
45
62
46
63
// Close 关闭
47
64
func (ctdb * chattimedb ) Close () error {
48
- db := (* gorm .DB )(ctdb )
65
+ db := (* gorm .DB )(ctdb . db )
49
66
return db .Close ()
50
67
}
51
68
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"`
60
78
}
61
79
62
80
// TableName 表名
63
- func (ChatTime ) TableName () string {
81
+ func (chatTime ) TableName () string {
64
82
return "chat_time"
65
83
}
66
84
67
85
// 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 )
72
90
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
77
96
}
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 (
86
115
map [string ]any {
87
- "last_time " : now ,
88
- "today_time " : 0 ,
116
+ "total_time " : st . TotalTime + todayTime ,
117
+ "total_message " : st . TotalMessage + totayMessage ,
89
118
})
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
-
109
119
}
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 ))
110
133
}
134
+ ctdb .userTimestampMap .Store (keyword , now .Unix ())
111
135
return
112
136
}
113
137
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
123
150
return
124
151
}
125
152
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 ))
132
179
return
133
180
}
134
181
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 ] {
139
198
return i + 1
140
199
}
141
200
}
142
201
return 0
143
202
}
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