/
timer.go
201 lines (189 loc) · 4.29 KB
/
timer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// Package timer 群管定时器
package timer
import (
"strconv"
"strings"
"sync"
"time"
"github.com/FloatTech/floatbox/process"
sql "github.com/FloatTech/sqlite"
"github.com/fumiama/cron"
"github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
// Clock 时钟
type Clock struct {
db *sql.Sqlite
timers *(map[uint32]*Timer)
timersmu sync.RWMutex
// cron 定时器
cron *cron.Cron
// entries key <-> cron
entries map[uint32]cron.EntryID
entmu sync.Mutex
}
var (
// @全体成员
atall = message.MessageSegment{
Type: "at",
Data: map[string]string{
"qq": "all",
},
}
)
// NewClock 添加一个新时钟
func NewClock(db *sql.Sqlite) (c Clock) {
c.cron = cron.New()
c.entries = make(map[uint32]cron.EntryID)
c.timers = &map[uint32]*Timer{}
c.loadTimers(db)
c.cron.Start()
return
}
// RegisterTimer 注册计时器
func (c *Clock) RegisterTimer(ts *Timer, save, isinit bool) bool {
var key uint32
if save {
key = ts.GetTimerID()
ts.ID = key
} else {
key = ts.ID
}
t, ok := c.GetTimer(key)
if t != ts && ok { // 避免重复注册定时器
t.SetEn(false)
}
logrus.Infoln("[群管]注册计时器", key)
if ts.Cron != "" {
var ctx *zero.Ctx
if isinit {
process.GlobalInitMutex.Lock()
}
if ts.SelfID != 0 {
ctx = zero.GetBot(ts.SelfID)
} else {
zero.RangeBot(func(id int64, c *zero.Ctx) bool {
ctx = c
ts.SelfID = id
return false
})
}
if isinit {
process.GlobalInitMutex.Unlock()
}
eid, err := c.cron.AddFunc(ts.Cron, func() { ts.sendmsg(ts.GrpID, ctx) })
if err == nil {
c.entmu.Lock()
c.entries[key] = eid
c.entmu.Unlock()
if save {
err = c.AddTimerIntoDB(ts)
}
if err == nil {
err = c.AddTimerIntoMap(ts)
}
return err == nil
}
ts.Alert = err.Error()
} else {
if save {
_ = c.AddTimerIntoDB(ts)
}
_ = c.AddTimerIntoMap(ts)
for ts.En() {
nextdate := ts.nextWakeTime()
sleepsec := time.Until(nextdate)
logrus.Printf("[群管]计时器%08x将睡眠%ds", key, sleepsec/time.Second)
time.Sleep(sleepsec)
if ts.En() {
if ts.Month() < 0 || ts.Month() == time.Now().Month() {
if ts.Day() < 0 || ts.Day() == time.Now().Day() {
ts.judgeHM()
} else if ts.Day() == 0 {
if ts.Week() < 0 || ts.Week() == time.Now().Weekday() {
ts.judgeHM()
}
}
}
}
}
}
return false
}
// CancelTimer 取消计时器
func (c *Clock) CancelTimer(key uint32) bool {
t, ok := c.GetTimer(key)
if ok {
if t.Cron != "" {
c.entmu.Lock()
e := c.entries[key]
c.cron.Remove(e)
delete(c.entries, key)
c.entmu.Unlock()
} else {
t.SetEn(false)
}
c.timersmu.Lock()
delete(*c.timers, key) // 避免重复取消
e := c.db.Del("timer", "where id = "+strconv.Itoa(int(key)))
c.timersmu.Unlock()
return e == nil
}
return false
}
// ListTimers 列出本群所有计时器
func (c *Clock) ListTimers(grpID int64) []string {
// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高
if c.timers != nil {
c.timersmu.RLock()
keys := make([]string, 0, len(*c.timers))
for _, v := range *c.timers {
if v.GrpID == grpID {
k := v.GetTimerInfo()
start := strings.Index(k, "]")
msg := strings.ReplaceAll(k[start+1:]+"\n", "-1", "每")
msg = strings.ReplaceAll(msg, "月0日0周", "月周天")
msg = strings.ReplaceAll(msg, "月0日", "月")
msg = strings.ReplaceAll(msg, "日0周", "日")
keys = append(keys, msg)
}
}
c.timersmu.RUnlock()
return keys
}
return nil
}
// GetTimer 获得定时器
func (c *Clock) GetTimer(key uint32) (t *Timer, ok bool) {
c.timersmu.RLock()
t, ok = (*c.timers)[key]
c.timersmu.RUnlock()
return
}
// AddTimerIntoDB 添加定时器
func (c *Clock) AddTimerIntoDB(t *Timer) (err error) {
c.timersmu.Lock()
err = c.db.Insert("timer", t)
c.timersmu.Unlock()
return
}
// AddTimerIntoMap 添加定时器到缓存
func (c *Clock) AddTimerIntoMap(t *Timer) (err error) {
c.timersmu.Lock()
(*c.timers)[t.ID] = t
c.timersmu.Unlock()
return
}
func (c *Clock) loadTimers(db *sql.Sqlite) {
c.db = db
err := c.db.Create("timer", &Timer{})
if err == nil {
var t Timer
_ = c.db.FindFor("timer", &t, "", func() error {
tescape := t
go c.RegisterTimer(&tescape, false, true)
return nil
})
}
}