forked from skycoin/skyaway
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathschedule.go
156 lines (134 loc) · 3.61 KB
/
schedule.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
package skyaway
import (
"fmt"
"log"
"time"
)
type task int
const (
nothing task = iota
announceEventStart
startEvent
announceEventEnd
endEvent
)
// Returns what to do next (start, stop or nothing) and when
func (bot *Bot) schedule() (task, time.Time) {
event := bot.db.GetCurrentEvent()
if event == nil {
return nothing, time.Time{}
}
if event.StartedAt.Valid {
return endEvent, event.StartedAt.Time.Add(event.Duration.Duration)
} else if event.ScheduledAt.Valid {
return startEvent, event.ScheduledAt.Time
}
log.Print("The current event is not scheduled, not started and not ended. That should not have happened.")
return nothing, time.Time{}
}
// Returns a more detailed version than `schedule()`
// of what to do next (including announcements).
func (bot *Bot) subSchedule() (task, time.Time) {
tsk, future := bot.schedule()
if tsk == nothing {
return nothing, time.Time{}
}
every := bot.config.AnnounceEvery.Duration
announcements := time.Until(future) / every
if announcements <= 0 {
return tsk, future
}
nearFuture := future.Add(-announcements * every)
switch tsk {
case startEvent:
return announceEventStart, nearFuture
case endEvent:
return announceEventEnd, nearFuture
default:
log.Print("unsupported task to subSchedule")
return nothing, time.Time{}
}
}
func (bot *Bot) perform(tsk task) {
event := bot.db.GetCurrentEvent()
if event == nil {
log.Print("failed to perform the scheduled task: no current event")
return
}
noctx := &Context{}
switch tsk {
case announceEventStart:
if event.Surprise {
log.Printf("not announcing the future start of a surprise event")
break
}
log.Print("announcing the event future start")
if err := bot.AnnounceEventWithTitle(event, "Event is scheduled"); err != nil {
log.Printf("failed to announce event future start: %v", err)
}
case announceEventEnd:
log.Print("announcing the event future end")
if err := bot.AnnounceEventWithTitle(event, "Event is ongoing"); err != nil {
log.Printf("failed to announce event future end: %v", err)
}
case startEvent:
log.Print("starting the event")
startedEvent, err := bot.StartCurrentEvent()
if err != nil {
log.Printf("failed to start event: %v", err)
break
}
md := formatEventAsMarkdown(startedEvent, true)
md = fmt.Sprintf("*%s*\n%s", "Event has started!", md)
if err := bot.Send(noctx, "yell", "markdown", md); err != nil {
log.Printf("failed to announce event started: %v", err)
}
case endEvent:
log.Print("ending the event")
endedEvent, err := bot.EndCurrentEvent()
if err != nil {
log.Printf("failed to end event: %v", err)
break
}
md := formatEventAsMarkdown(endedEvent, true)
md = fmt.Sprintf("*%s*\n%s", "Event has ended!", md)
if err := bot.Send(noctx, "yell", "markdown", md); err != nil {
log.Printf("failed to announce event ended: %v", err)
}
default:
log.Printf("unsupported task to perform: %v", tsk)
}
}
func (bot *Bot) maintain() {
bot.rescheduleChan = make(chan int)
defer func() {
close(bot.rescheduleChan)
}()
var timer *time.Timer
for {
tsk, future := bot.subSchedule()
if tsk == nothing {
<-bot.rescheduleChan
continue
}
if timer == nil {
timer = time.NewTimer(time.Until(future))
} else {
timer.Reset(time.Until(future))
}
select {
case <-timer.C:
bot.perform(tsk)
case <-bot.rescheduleChan:
if !timer.Stop() {
<-timer.C
}
}
}
}
// Cause a reschedule to happen. Call this if you modify events, so that the
// bot could wake itself up at correct times for automatic announcements and
// event starting/stopping.
func (bot *Bot) Reschedule() {
bot.rescheduleChan <- 1
}