From c9095928d270a7b2727bacb25d843d4e82c9aeb3 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 17 Jun 2024 14:16:33 +0200 Subject: [PATCH] http_notif: implement HTTP notifications --- http_notif.go | 108 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 3 deletions(-) diff --git a/http_notif.go b/http_notif.go index 0284883..bfb5605 100644 --- a/http_notif.go +++ b/http_notif.go @@ -1,17 +1,119 @@ package main +import ( + "bytes" + "fmt" + "io" + "net/http" + "text/template" +) + +type encoding string + +func (e encoding) AddHeader(header http.Header) { + header.Add("Content-Type", string(e)) +} + +func (e encoding) EscapeValue(value string) string { + switch e { + case EncodingForm: + return template.URLQueryEscaper(value) + + case EncodingJson: + return template.JSEscapeString(value) + + default: + return value + } +} + +const ( + EncodingForm encoding = "application/x-www-form-urlencoded" + EncodingJson encoding = "application/json" +) + type httpNotificator struct { - URL string + URL string + Method string + Encoding encoding + BodyTemplate string } var _ notificator = (*httpNotificator)(nil) func NewHttpNotificator(cfg notificatorConfig) *httpNotificator { - return &httpNotificator{URL: cfg.Params["Target"]} + return &httpNotificator{ + URL: cfg.Params["Target"], + Method: cfg.Params["Method"], + Encoding: encoding(cfg.Params["Encoding"]), + BodyTemplate: cfg.Params["BodyTemplate"], + } } func (h *httpNotificator) Notify(amount uint64, comment string) error { - return nil // currently not implemented + bodyData := &struct { + Amount uint64 + Message string + }{ + Amount: amount, + Message: h.Encoding.EscapeValue(comment), + } + + urlTemplate, err := template.New("url").Parse(h.URL) + if err != nil { + return fmt.Errorf("error building URL template: %w", err) + } + + bodyTemplate, err := template.New("body").Parse(h.BodyTemplate) + if err != nil { + return fmt.Errorf("error building body template: %w", err) + } + + var buf bytes.Buffer + err = urlTemplate.Execute(&buf, bodyData) + if err != nil { + return fmt.Errorf("error executing URL template: %w", err) + } + url := buf.String() + + buf.Reset() + err = bodyTemplate.Execute(&buf, bodyData) + if err != nil { + return fmt.Errorf("error executing body template: %w", err) + } + + var bodyReader io.Reader + if h.Method == http.MethodPost { + bodyReader = &buf + } + + req, err := http.NewRequest(h.Method, url, bodyReader) + if err != nil { + return fmt.Errorf("error creating request: %w", err) + } + + h.Encoding.AddHeader(req.Header) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return fmt.Errorf("error sending request: %w", err) + } + + defer func() { + _ = resp.Body.Close() + }() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("error reading response body: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code: %d (%s)", + resp.StatusCode, body) + } + + return nil } func (h *httpNotificator) Target() string {