This repository has been archived by the owner on Aug 6, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
handlers.go
142 lines (114 loc) · 3.13 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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package pkg
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"text/template"
"github.com/gin-gonic/gin"
"github.com/patrickmn/go-cache"
irc "github.com/thoj/go-ircevent"
"go.uber.org/zap"
)
type MsgIn map[string]interface{}
type Handler struct {
Logger *zap.Logger
Cfg Configuration
IRC *irc.Connection
Token string
Cache *cache.Cache
}
func (h *Handler) MessageHandler(c *gin.Context) {
producer := c.Param("producer")
channelStr := c.Param("channels")
token := c.Param("token")
channels := strings.Split(channelStr, ",")
if token != h.Token {
c.JSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": "bad token"})
return
}
h.Logger.Info("Webhook",
zap.String("type", "webhook"),
zap.String("producer", producer),
)
rs, err := c.GetRawData()
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"status": "fail", "error": err.Error()})
return
}
msgOut := ""
// inbound JSON
msgIn := MsgIn{}
err = json.Unmarshal(rs, &msgIn)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"status": "fail", "error": err.Error()})
return
}
h.Logger.Debug("Inbound Json",
zap.String("type", "inboundJson"),
zap.String("json", string(rs)),
)
// get template for producer
tmpl, err := h.templateProducer(producer, msgIn)
if err != nil {
h.Logger.Info(err.Error(),
zap.String("type", "templateNotFound"),
zap.String("producer", producer),
)
c.JSON(http.StatusBadRequest, gin.H{"status": "ok", "state": "no template found", "msg_out": ""})
return
}
if tmpl != nil {
var tplReturn bytes.Buffer
if err := tmpl.Execute(&tplReturn, msgIn); err != nil {
h.Logger.Error("Template executions failed: " + err.Error())
}
msgOut = tplReturn.String()
}
// regex replacements
for rgx, replace := range h.Cfg.CompiledRegexes {
msgOut = rgx.ReplaceAllString(msgOut, replace)
}
c.JSON(http.StatusOK, gin.H{"status": "ok", "msg_out": msgOut})
// post message to specified channels
if msgOut != "" {
// final cleanup
msgOut = strings.Join(strings.Fields(msgOut), " ")
// prevent duplicate message within time span
// this helps prevent conditions where similar posts produce the
// exact same message
_, found := h.Cache.Get(msgOut)
if !found {
for _, ch := range channels {
h.IRC.SendRaw(fmt.Sprintf("PRIVMSG %s : %s", strings.Replace(ch, "^", "#", -1), msgOut))
}
// add message to cache
h.Cache.Set(msgOut, "sent", cache.DefaultExpiration)
return
}
h.Logger.Info("CACHE HIT", zap.String("msgOut", msgOut))
}
return
}
func (h *Handler) templateProducer(producer string, msgIn MsgIn) (*template.Template, error) {
// find a template for a producer and any content rules
for p, rt := range h.Cfg.ParsedTemplates {
if p == producer {
h.Logger.Debug("Checking producer: " + p)
for cr, t := range rt {
// found empty content rule, so we match and return
if cr.Key == "" && cr.Equals == "" {
h.Logger.Debug("Empty content rule.")
return t, nil
}
if msgIn[cr.Key] == cr.Equals {
h.Logger.Debug("FOUND content rule.")
return t, nil
}
}
}
}
return nil, errors.New("no template found")
}