forked from brettbuddin/victor
/
brain.go
109 lines (92 loc) · 2.2 KB
/
brain.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
package victor
import (
"github.com/brettbuddin/victor/adapter"
"log"
"regexp"
"strings"
"sync"
)
type Brain struct {
*sync.RWMutex
name string
identity adapter.User
listeners []ListenerFunc
cache *Cache
}
func NewBrain(name string) *Brain {
return &Brain{
RWMutex: &sync.RWMutex{},
name: name,
listeners: []ListenerFunc{},
cache: NewCache(),
}
}
func (b *Brain) Cache() adapter.Cacher {
return b.cache
}
func (b *Brain) Name() string {
b.RLock()
defer b.RUnlock()
return b.name
}
func (b *Brain) Identity() adapter.User {
b.RLock()
defer b.RUnlock()
return b.identity
}
func (b *Brain) SetIdentity(u adapter.User) {
b.Lock()
defer b.Unlock()
b.identity = u
}
// Respond registers a listener that matches a direct message to
// the robot. This means "@botname command", "botname command" or
// "/command" forms
func (b *Brain) Respond(exp string, f func(adapter.Message)) (err error) {
exp = strings.Join([]string{
"(?i)", // flags
"\\A", // begin
"(?:(?:@)?" + b.Name() + "[:,]?\\s*|/)", // bot name
"(?:" + exp + ")", // expression
"\\z", // end
}, "")
return b.Hear(exp, f)
}
// Hear registers a listener that matches any instance of the
// phrase in the room. Excluding from itself.
func (b *Brain) Hear(exp string, f func(adapter.Message)) (err error) {
pattern, err := regexp.Compile(exp)
if err != nil {
return err
}
log.Printf("LISTENER: %s\n", exp)
b.register(listenerFunc(pattern, f))
return
}
func (b *Brain) register(l ListenerFunc) {
b.Lock()
defer b.Unlock()
b.listeners = append(b.listeners, l)
}
// Receive accepts an incoming message and applies
// it to all listeners.
func (b *Brain) Receive(m adapter.Message) {
b.RLock()
defer b.RUnlock()
for _, l := range b.listeners {
go l(m)
}
}
type ListenerFunc func(adapter.Message)
func listenerFunc(pattern *regexp.Regexp, f ListenerFunc) ListenerFunc {
return func(m adapter.Message) {
results := pattern.FindAllStringSubmatch(m.Body(), -1)
if len(results) > 0 {
m.SetParams(results[0][1:])
log.Printf("TRIGGER: %s\n", pattern)
log.Printf("TRIGGER: %s\n", pattern)
log.Printf("PARAMS: %s\n", m.Params())
f(m)
}
}
}