/
handlers.go
125 lines (113 loc) · 2.89 KB
/
handlers.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
package maimai
import (
"fmt"
"net/http"
"regexp"
"strings"
"euphoria.io/heim/proto"
"github.com/cpalone/gobot"
"golang.org/x/net/html"
)
var linkMatcher = regexp.MustCompile("(https?://)?[\\S]+\\.[\\S][\\S]+[\\S^\\.]")
var commandMatcher = regexp.MustCompile("![\\S]+ @[\\S]+")
func getCommandAndUser(text string) (string, string, error) {
matches := commandMatcher.FindAllString(text, -1)
if matches == nil {
return "", "", fmt.Errorf("getCommandAndUser: no matches found")
}
// Take first match only
s := matches[0]
splits := strings.Split(s, " ")
if len(splits) != 2 {
return "", "", fmt.Errorf("getCommandAndUser: invalid command")
}
return splits[0], splits[1][1:], nil
}
func isCommand(text string) bool {
if commandMatcher.FindAllString(text, -1) == nil {
return false
}
return true
}
// LinkTitleHandler searches each SendEvent for urls and posts the link title
// (if available) for the first valid link it finds.
//
// It is an empty struct because it does not need to maintain state.
type LinkTitleHandler struct{}
func extractTitleFromTree(z *html.Tokenizer) string {
depth := 0
for {
tt := z.Next()
switch tt {
case html.ErrorToken:
return ""
case html.TextToken:
if depth > 0 {
title := strings.TrimSpace(string(z.Text()))
lower := strings.ToLower(title)
if strings.HasPrefix(lower, "imgur") {
return ""
}
return title
}
case html.StartTagToken:
tn, _ := z.TagName()
if string(tn) == "title" {
depth++
}
}
}
}
func getLinkTitle(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("Bad response code: %v", resp.StatusCode)
}
z := html.NewTokenizer(resp.Body)
return extractTitleFromTree(z), nil
}
// HandleIncoming checks incoming SendEvents for URLs and posts the link title
// for the first URL returning a valid title.
func (l *LinkTitleHandler) HandleIncoming(r *gobot.Room, p *proto.Packet) (*proto.Packet, error) {
if p.Type != proto.SendEventType {
return nil, nil
}
r.Logger.Debugf("Handler received SendEvent")
payload, err := p.Payload()
if err != nil {
return nil, err
}
msg, ok := payload.(*proto.SendEvent)
if !ok {
return nil, fmt.Errorf("Could not assert SendEvent as such.")
}
if msg.Sender.Name == "euphoriabot" {
return nil, nil
}
r.Logger.Debugf("Received message with content: %s", msg.Content)
urls := linkMatcher.FindAllString(msg.Content, -1)
for _, url := range urls {
r.Logger.Debugf("Trying URL %s", url)
if !strings.HasPrefix(url, "http") {
url = "http://" + url
}
title, err := getLinkTitle(url)
if err == nil && title != "" {
r.SendText(&msg.ID, "Link title: "+title)
break
}
}
return nil, nil
}
// Run is a no-op.
func (l *LinkTitleHandler) Run(r *gobot.Room) {
return
}
// Stop is a no-op.
func (l *LinkTitleHandler) Stop(r *gobot.Room) {
return
}