-
Notifications
You must be signed in to change notification settings - Fork 27
/
reply.go
138 lines (115 loc) · 3.11 KB
/
reply.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
package slick
import (
"log"
"time"
"github.com/nlopes/slack"
)
// Reply
//
type Reply struct {
*slack.OutgoingMessage
bot *Bot
}
func (r *Reply) AddReaction(emoji string) *Reply {
r.OnAck(func(ev *slack.AckMessage) {
go r.bot.Slack.AddReaction(emoji, slack.NewRefToMessage(r.Channel, ev.Timestamp))
})
return r
}
func (r *Reply) DeleteAfter(duration string) *Reply {
timeDur := parseAutodestructDuration("DeleteAfter", duration)
r.OnAck(func(ev *slack.AckMessage) {
go func() {
time.Sleep(timeDur)
r.bot.Slack.DeleteMessage(r.Channel, ev.Timestamp)
}()
})
return r
}
func (r *Reply) ListenReaction(reactListen *ReactionListener) {
r.OnAck(func(ackEv *slack.AckMessage) {
listen := reactListen.newListener()
listen.EventHandlerFunc = func(_ *Listener, event interface{}) {
re := ParseReactionEvent(event)
if re == nil {
return
}
if ackEv.Timestamp != re.Item.Timestamp {
return
}
if re.User == r.bot.Myself.ID {
return
}
if !reactListen.filterReaction(re) {
return
}
re.OriginalReply = r
re.OriginalAckMessage = ackEv
re.Listener = reactListen
reactListen.HandlerFunc(reactListen, re)
}
r.bot.Listen(listen)
})
}
// OnAck allows you to catch the message_id of the message you
// replied. Call it immediately after sending a reply to be sure to
// catch the confirmation message with the message_id.
//
// With the message_id, you can modify your reply, add reactions to it
// or delete it.
func (r *Reply) OnAck(f func(ack *slack.AckMessage)) {
r.bot.Listen(&Listener{
ListenDuration: 20 * time.Second,
EventHandlerFunc: func(subListen *Listener, event interface{}) {
if ev, ok := event.(*slack.AckMessage); ok {
if ev.ReplyTo == r.ID {
f(ev)
subListen.Close()
}
}
},
TimeoutFunc: func(subListen *Listener) {
log.Println("OnAck Listener dropped, because no corresponding AckMessage was received before timeout")
subListen.Close()
},
})
}
// Updateable returns an instance of UpdateableReply, which has a few
// methods to update a message after the fact. It is safe to use in
// different goroutines no matter when.
func (r *Reply) Updateable() *UpdateableReply {
updt := &UpdateableReply{
reply: r,
}
r.OnAck(func(ack *slack.AckMessage) {
updt.lock.Lock()
defer updt.lock.Unlock()
updt.msgTimestamp = ack.Timestamp
go updt.dispatch()
})
return updt
}
// Listen here on Reply is the same as Bot.Listen except that
// ReplyAck() will be filled with the slack.AckMessage before any
// event is dispatched to this listener.
func (r *Reply) Listen(listen *Listener) error {
listen.Bot = r.bot
err := listen.checkParams()
if err != nil {
log.Println("Reply.Listen(): Invalid Listener: ", err)
return err
}
r.OnAck(func(ev *slack.AckMessage) {
listen.replyAck = ev
r.bot.addListener(listen)
})
return nil
}
func parseAutodestructDuration(funcName string, duration string) time.Duration {
timeDur, err := time.ParseDuration(duration)
if err != nil {
log.Printf("error: %s called with invalid `duration`: %q, using 1 second instead.\n", funcName, duration)
timeDur = 1 * time.Second
}
return timeDur
}