forked from danryan/hal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler.go
130 lines (111 loc) · 3.28 KB
/
handler.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
package hal
import (
"fmt"
"regexp"
"strings"
)
var (
// RespondRegexp is used to determine whether a received message should be processed as a response
respondRegexp = fmt.Sprintf(`^(?:@?(?:%s|%s)[:,]?)\s+(?:(.+))`, Config.Alias, Config.Name)
// RespondRegexpTemplate expands the RespondRegexp
respondRegexpTemplate = fmt.Sprintf(`^(?:@?(?:%s|%s)[:,]?)\s+(?:${1})`, Config.Alias, Config.Name)
// ErrNotMatched error to flag the case when there has been no match in the current handler
ErrNotMatched = fmt.Errorf("Handler not matched")
)
// handler is an interface for objects to implement in order to respond to messages.
type handler interface {
Handle(res *Response) error
}
// Handlers is a map of registered handlers
var Handlers = map[string]handler{}
func handlerMatch(r *regexp.Regexp, text string) bool {
if !r.MatchString(text) {
return false
}
return true
}
func handlerRegexp(method, pattern string) *regexp.Regexp {
if method == RESPOND {
return regexp.MustCompile(strings.Replace(respondRegexpTemplate, "${1}", pattern, 1))
}
return regexp.MustCompile(pattern)
}
// NewHandler checks whether h implements the handler interface, wrapping it in a FullHandler
func NewHandler(h interface{}) (handler, error) {
switch v := h.(type) {
case fullHandler:
return &FullHandler{handler: v}, nil
case handler:
return v, nil
default:
return nil, fmt.Errorf("%v does not implement the handler interface", v)
}
}
// Handler type
type Handler struct {
Method string
Pattern string
Usage string
Run func(res *Response) error
}
// Handle func
func (h *Handler) Handle(res *Response) error {
switch {
// handle the response without matching
case h.Pattern == "":
return h.Run(res)
// handle the response after finding matches
case h.match(res):
res.Match = h.regexp().FindAllStringSubmatch(res.Message.Text, -1)[0]
return h.Run(res)
// if we don't find a match, return
default:
return ErrNotMatched
}
}
// IsRespond func checks whether a Message is addressing the bot (RESPOND) or not
func (h *Handler) IsRespond(res *Response) bool {
r := regexp.MustCompile(respondRegexp)
return r.Match([]byte(res.Message.Text))
}
func (h *Handler) regexp() *regexp.Regexp {
return handlerRegexp(h.Method, h.Pattern)
}
// Match func
func (h *Handler) match(res *Response) bool {
return handlerMatch(h.regexp(), res.Message.Text)
}
// fullHandler is an interface for objects that wish to supply their own define methods
type fullHandler interface {
Run(*Response) error
Usage() string
Pattern() string
Method() string
}
// FullHandler declares common functions shared by all handlers
type FullHandler struct {
handler fullHandler
}
// Regexp func
func (h *FullHandler) Regexp() *regexp.Regexp {
return handlerRegexp(h.handler.Method(), h.handler.Pattern())
}
// Match func
func (h *FullHandler) Match(res *Response) bool {
return handlerMatch(h.Regexp(), res.Message.Text)
}
// Handle func
func (h *FullHandler) Handle(res *Response) error {
switch {
// handle the response without matching
case h.handler.Pattern() == "":
return h.handler.Run(res)
// handle the response after finding matches
case h.Match(res):
res.Match = h.Regexp().FindAllStringSubmatch(res.Text(), -1)[0]
return h.handler.Run(res)
// if we don't find a match, return
default:
return ErrNotMatched
}
}