-
Notifications
You must be signed in to change notification settings - Fork 42
/
delay.go
129 lines (109 loc) · 3.15 KB
/
delay.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
package command
import (
"errors"
"fmt"
"sync"
"time"
"github.com/slack-go/slack"
"github.com/innogames/slack-bot/v2/bot"
"github.com/innogames/slack-bot/v2/bot/matcher"
"github.com/innogames/slack-bot/v2/bot/msg"
"github.com/innogames/slack-bot/v2/bot/util"
"github.com/innogames/slack-bot/v2/client"
"github.com/innogames/slack-bot/v2/command/queue"
)
// NewDelayCommand delays the command execution by the given time
func NewDelayCommand(base bot.BaseCommand) bot.Command {
return &delayCommand{BaseCommand: base, timers: make([]*time.Timer, 0)}
}
type delayCommand struct {
bot.BaseCommand
timers []*time.Timer
mu sync.Mutex
}
func (c *delayCommand) GetMatcher() matcher.Matcher {
return matcher.NewGroupMatcher(
matcher.NewRegexpMatcher("delay (?P<delay>[\\w]+) (?P<quiet>quiet )?(?P<command>.*)", c.delay),
matcher.NewRegexpMatcher("stop (delay|timer) (?P<timer>\\d+)", c.stop),
)
}
func (c *delayCommand) delay(match matcher.Result, message msg.Message) {
delay, err := util.ParseDuration(match.GetString("delay"))
if err != nil {
c.SendMessage(message, "Invalid duration: "+err.Error())
return
}
quietMode := match.GetString("quiet") != ""
command := match.GetString("command")
c.mu.Lock()
defer c.mu.Unlock()
timer := time.NewTimer(delay)
c.timers = append(c.timers, timer)
if !quietMode {
stopNumber := len(c.timers) - 1
text := fmt.Sprintf(
"I queued the command `%s` for %s. Use `stop timer %d` to stop the timer",
command,
delay,
stopNumber,
)
blocks := []slack.Block{
client.GetTextBlock(text),
}
// add an "Stop timer" button
blocks = append(
blocks,
slack.NewActionBlock(
"",
client.GetInteractionButton("stop_timer", "Stop timer!", fmt.Sprintf("stop timer %d", stopNumber)),
),
)
c.SendBlockMessage(message, blocks)
}
runningCommand := queue.AddRunningCommand(message, "")
go func() {
<-timer.C // todo abort here when it was aborted + more random stop key
runningCommand.Done()
client.HandleMessage(message.WithText(command))
}()
}
func (c *delayCommand) stop(match matcher.Result, message msg.Message) {
// avoid racing conditions when it's used multiple times in parallel
c.mu.Lock()
defer c.mu.Unlock()
timerNr := match.GetInt("timer")
if timerNr < len(c.timers) && c.timers[timerNr] != nil {
c.timers[timerNr].Stop()
c.timers[timerNr] = nil
c.SendMessage(message, "Stopped timer!")
} else {
c.ReplyError(message, errors.New("invalid timer"))
}
}
var delayCategory = bot.Category{
Name: "Delay",
Description: "Delay any command by the given time",
HelpURL: "https://github.com/innogames/slack-bot#delay",
}
func (c *delayCommand) GetHelp() []bot.Help {
return []bot.Help{
{
Command: "delay <duration> <command>",
Description: "delay a command by the given offset",
Examples: []string{
"delay 1h rely remind me to go to toilet",
"delay 15m30s trigger job DeployBeta",
"delay 15min trigger job DeployBeta",
},
Category: delayCategory,
},
{
Command: "stop timer <timerId>",
Description: "cancel a planned delayCommand",
Examples: []string{
"stop timer 1243",
},
Category: delayCategory,
},
}
}