-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheventt.go
137 lines (124 loc) · 4.11 KB
/
eventt.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
package eventt
import (
"encoding/json"
"fmt"
"io"
"net/http"
"golang.org/x/exp/slog"
)
// SonarrTriggers sonarr events or triggers using webhook connection
// see: https://wiki.servarr.com/sonarr/settings#connection-triggers
type SonarrTriggers struct {
// OnGrab notified when episodes are available for download and has been sent to a download client
OnGrab func(event GrabEvent)
// OnDownload or OnImport be notified when episodes are successfully imported
OnDownload func(event DownloadEvent)
// OnRename be notified when episodes are renamed
OnRename func(event RenameEvent)
// OnEpisodeFileDelete be notified when episodes files are deleted
OnEpisodeFileDelete func(event EpisodeFileDeleteEvent)
// OnSeriesDelete be notified when series are deleted
OnSeriesDelete func(event SeriesDeleteEvent)
// OnHealth be notified on health check failures
OnHealth func(event HealthEvent)
// OnApplicationUpdate be notified when Sonarr gets updated to a new version
OnApplicationUpdate func(event ApplicationUpdateEvent)
// OnTest be notified when test payload received
OnTest func(event TestEvent)
// OnUnknown be notified when not implemented or unknown event received.
OnUnknown func(eventType string, event UnknownEvent)
// OnError callback for any error process any event
// the payload represents the received request it can be nil if the error
// reading the payload, other error will include the payload
// this function should return http status code to return to Sonarr.
// if this function not implemented, it will log any error and return 400 to sonarr
OnError func(payload []byte, err error) (httpStatus int)
// LogOnError should we log errors, if true it will use slog.Error to log errors and
// it will include the payload. see SonarrTriggers.handleErrors for more details.
LogOnError bool
b []byte
}
// Monitor http handler to invoke the correct trigger from SonarrTriggers based on
// the received event from Sonarr, see SonarrTriggers all the events and error handling.
func (s *SonarrTriggers) Monitor(w http.ResponseWriter, r *http.Request) {
var err error
s.b, err = io.ReadAll(r.Body)
if err != nil {
status := s.handleErrors(
fmt.Errorf("error while reading request body %w", err),
)
w.WriteHeader(status)
return
}
r.Body.Close()
eventType := &WebhookEvent{}
if err := json.Unmarshal(s.b, eventType); err != nil {
status := s.handleErrors(
fmt.Errorf("error parsing event type: %w", err),
)
w.WriteHeader(status)
return
}
if err := s.handleEvent(eventType.EventType); err != nil {
status := s.handleErrors(
fmt.Errorf("error handle '%s' event: %w", eventType.EventType, err),
)
w.WriteHeader(status)
return
}
w.WriteHeader(http.StatusOK)
}
func (s *SonarrTriggers) handleEvent(eventType string) error {
switch eventType {
case grab:
return handleGenericEvent(s.b, s.OnGrab)
case download:
return handleGenericEvent(s.b, s.OnDownload)
case rename:
return handleGenericEvent(s.b, s.OnRename)
case episodeFileDelete:
return handleGenericEvent(s.b, s.OnEpisodeFileDelete)
case seriesDelete:
return handleGenericEvent(s.b, s.OnSeriesDelete)
case health:
return handleGenericEvent(s.b, s.OnHealth)
case applicationUpdate:
return handleGenericEvent(s.b, s.OnApplicationUpdate)
case test:
return handleGenericEvent(s.b, s.OnTest)
default:
return s.handleUnknown(eventType)
}
}
func (s *SonarrTriggers) handleErrors(err error) int {
status := http.StatusBadRequest
if s.OnError != nil {
status = s.OnError(s.b, err)
}
if s.LogOnError {
slog.Error("error processing new event", err, "payload", string(s.b))
}
return status
}
func handleGenericEvent[T eventType](b []byte, f func(e T)) error {
if f == nil {
return nil
}
var e T
if err := json.Unmarshal(b, &e); err != nil {
return fmt.Errorf("error parsing '%s' event: %w", e.eventName(), err)
}
f(e)
return nil
}
func (s *SonarrTriggers) handleUnknown(eventType string) error {
if s.OnUnknown == nil {
return nil
}
m := make(UnknownEvent)
if err := json.Unmarshal(s.b, &m); err != nil {
return fmt.Errorf("error parsing 'Unknown' event: %w", err)
}
s.OnUnknown(eventType, m)
return nil
}