display notifications
This commit is contained in:
1 parent
0052822e49
commit
5d8bbcd756
5 files changed
+143
-1
No files matched your search
@@ -0,0 +1,93 @@
|
||||
package alerts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AlwaysOnDisplay sends each alert to the session API used by the wall
|
||||
// display. A session is created for the alert and then given a status and log
|
||||
// entry so the display can show both the current incident and its details.
|
||||
type AlwaysOnDisplay struct {
|
||||
URL string
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
func (a *AlwaysOnDisplay) Name() string { return "always-on-display" }
|
||||
|
||||
type aodSession struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
func (a *AlwaysOnDisplay) Send(ctx context.Context, alert Alert) error {
|
||||
client := a.Client
|
||||
if client == nil {
|
||||
client = &http.Client{Timeout: 15 * time.Second}
|
||||
}
|
||||
base := strings.TrimRight(a.URL, "/")
|
||||
|
||||
var session aodSession
|
||||
name := fmt.Sprintf("%s alert: %s", strings.ToUpper(string(alert.Priority())), alert.Spike.Service)
|
||||
if alert.Test {
|
||||
name = "TEST alert: " + alert.Spike.Service
|
||||
}
|
||||
if err := postJSONDecode(ctx, client, base+"/api/sessions", nil, map[string]string{"name": name}, &session); err != nil {
|
||||
return err
|
||||
}
|
||||
if session.ID == "" {
|
||||
return fmt.Errorf("always-on-display: session response did not include an id")
|
||||
}
|
||||
|
||||
status := firstLine(alert.Text(""))
|
||||
if err := postJSON(ctx, client, base+"/api/sessions/"+session.ID+"/status", nil, map[string]string{"status": status}); err != nil {
|
||||
return err
|
||||
}
|
||||
level := "info"
|
||||
if alert.Priority() == PriorityHigh {
|
||||
level = "error"
|
||||
} else if alert.Priority() == PriorityMedium {
|
||||
level = "warning"
|
||||
}
|
||||
return postJSON(ctx, client, base+"/api/sessions/"+session.ID+"/log", nil, map[string]string{
|
||||
"level": level,
|
||||
"message": alert.Text(""),
|
||||
})
|
||||
}
|
||||
|
||||
func firstLine(s string) string {
|
||||
if i := strings.IndexByte(s, '\n'); i >= 0 {
|
||||
return s[:i]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func postJSONDecode(ctx context.Context, client *http.Client, target string, headers map[string]string, body any, out any) error {
|
||||
raw, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, target, strings.NewReader(string(raw)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("always-on-display: invalid request")
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("always-on-display: request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode/100 != 2 {
|
||||
return fmt.Errorf("always-on-display: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(out); err != nil {
|
||||
return fmt.Errorf("always-on-display: invalid session response: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user