-
Notifications
You must be signed in to change notification settings - Fork 2
/
dmswebhooks.go
92 lines (74 loc) · 2.43 KB
/
dmswebhooks.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
// Package dmswebhooks provides an http.Handler that makes it easy to receive
// webhooks from Dead Man's Snitch's webhook integration. This makes building
// custom integrations easier.
package dmswebhooks
import (
"encoding/json"
"net/http"
"time"
)
const (
TypeSnitchReporting = "snitch.reporting"
TypeSnitchErrored = "snitch.errored"
TypeSnitchMissing = "snitch.missing"
StatusPending = "pending"
StatusHealthy = "healthy"
StatusMissing = "missing"
StatusErrored = "errored"
)
// Alert provides information about updates to Snitch state.
type Alert struct {
// Type gives information about what kind of alert occurred.
Type string `json:"type"`
// Timestamp is when the alert occurred.
Timestamp time.Time `json:"timestamp"`
// Data contains information about the Snitch
Data struct {
Snitch struct {
Token string `json:"token"`
Name string `json:"name"`
Notes string `json:"notes"`
Tags []string `json:"tags"`
status string `json:"status"`
previous_status string `json:"previous_status"`
} `json:"snitch"`
} `json:"data"`
}
type handler struct {
callback func(*Alert) error
}
// NewHandler returns an http.Handler that parses incoming webhooks from Dead
// Man's Snitch's webhook integration and calls the given callback handler.
// Errors returned from the callback are sent back to the calling server
// causing the request to be retried.
func NewHandler(callback func(*Alert) error) http.Handler {
return &handler{
callback: callback,
}
}
func (h *handler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
alert := &Alert{}
// Dead Man's Snitch will always use POST for webhooks
if req.Method != "POST" {
res.WriteHeader(http.StatusMethodNotAllowed)
return
}
dec := json.NewDecoder(req.Body)
if err := dec.Decode(alert); err != nil {
res.WriteHeader(http.StatusInternalServerError)
// This error is internal to the library so it should be safe to send back
// without exposing any internal data. It may mean we can correct it server
// side as well.
res.Write([]byte(err.Error()))
return
}
if err := h.callback(alert); err != nil {
res.WriteHeader(http.StatusInternalServerError)
// Avoid sending client error information back to the server to avoid
// possibly exposing anything sensitive.
res.Write([]byte("Error in callback"))
return
}
// Yeah! Everything worked!
res.WriteHeader(http.StatusNoContent)
}