forked from brocaar/chirpstack-application-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
http_handler.go
164 lines (137 loc) · 4.4 KB
/
http_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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Package httphandler implements a HTTP handler
package httphandler
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"regexp"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/brocaar/lora-app-server/internal/handler"
)
var headerNameValidator = regexp.MustCompile(`^[A-Za-z0-9-]+$`)
// HandlerConfig contains the configuration for a HTTP handler.
type HandlerConfig struct {
Headers map[string]string `json:"headers"`
DataUpURL string `json:"dataUpURL"`
JoinNotificationURL string `json:"joinNotificationURL"`
ACKNotificationURL string `json:"ackNotificationURL"`
ErrorNotificationURL string `json:"errorNotificationURL"`
StatusNotificationURL string `json:"statusNotificationURL"`
LocationNotificationURL string `json:"locationNotificationURL"`
}
// Validate validates the HandlerConfig data.
func (c HandlerConfig) Validate() error {
for k := range c.Headers {
if !headerNameValidator.MatchString(k) {
return ErrInvalidHeaderName
}
}
return nil
}
// Handler implements a HTTP handler for sending and notifying a HTTP
// endpoint.
type Handler struct {
config HandlerConfig
}
// NewHandler creates a new HTTPHandler.
func NewHandler(conf HandlerConfig) (*Handler, error) {
return &Handler{
config: conf,
}, nil
}
func (h *Handler) send(url string, payload interface{}) error {
b, err := json.Marshal(payload)
if err != nil {
return errors.Wrap(err, "marshal json error")
}
req, err := http.NewRequest("POST", url, bytes.NewReader(b))
if err != nil {
return errors.Wrap(err, "new request error")
}
req.Header.Set("Content-Type", "application/json")
for k, v := range h.config.Headers {
req.Header.Set(k, v)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return errors.Wrap(err, "http request error")
}
defer resp.Body.Close()
// check that response is in 200 range
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("expected 2XX response, got: %d", resp.StatusCode)
}
return nil
}
// Close closes the handler.
func (h *Handler) Close() error {
return nil
}
// SendDataUp sends a data-up payload.
func (h *Handler) SendDataUp(pl handler.DataUpPayload) error {
if h.config.DataUpURL == "" {
return nil
}
log.WithFields(log.Fields{
"url": h.config.DataUpURL,
"dev_eui": pl.DevEUI,
}).Info("handler/http: publishing data-up payload")
return h.send(h.config.DataUpURL, pl)
}
// SendJoinNotification sends a join notification.
func (h *Handler) SendJoinNotification(pl handler.JoinNotification) error {
if h.config.JoinNotificationURL == "" {
return nil
}
log.WithFields(log.Fields{
"url": h.config.JoinNotificationURL,
"dev_eui": pl.DevEUI,
}).Info("handler/http: publishing join notification")
return h.send(h.config.JoinNotificationURL, pl)
}
// SendACKNotification sends an ACK notification.
func (h *Handler) SendACKNotification(pl handler.ACKNotification) error {
if h.config.ACKNotificationURL == "" {
return nil
}
log.WithFields(log.Fields{
"url": h.config.ACKNotificationURL,
"dev_eui": pl.DevEUI,
}).Info("handler/http: publishing ack notification")
return h.send(h.config.ACKNotificationURL, pl)
}
// SendErrorNotification sends an error notification.
func (h *Handler) SendErrorNotification(pl handler.ErrorNotification) error {
if h.config.ErrorNotificationURL == "" {
return nil
}
log.WithFields(log.Fields{
"url": h.config.ErrorNotificationURL,
"dev_eui": pl.DevEUI,
}).Info("handler/http: publishing error notification")
return h.send(h.config.ErrorNotificationURL, pl)
}
// SendStatusNotification sends a status notification.
func (h *Handler) SendStatusNotification(pl handler.StatusNotification) error {
if h.config.StatusNotificationURL == "" {
return nil
}
log.WithFields(log.Fields{
"url": h.config.StatusNotificationURL,
"dev_eui": pl.DevEUI,
}).Info("handler/http: publishing status notification")
return h.send(h.config.StatusNotificationURL, pl)
}
// SendLocationNotification sends a location notification.
func (h *Handler) SendLocationNotification(pl handler.LocationNotification) error {
if h.config.LocationNotificationURL == "" {
return nil
}
log.WithFields(log.Fields{
"url": h.config.LocationNotificationURL,
"dev_eui": pl.DevEUI,
}).Info("handler/http: publishing location notification")
return h.send(h.config.LocationNotificationURL, pl)
}