mirror of
https://github.com/crazy-max/diun.git
synced 2025-12-21 13:23:09 +01:00
switch to http client for pushover notifier
This commit is contained in:
@@ -160,6 +160,7 @@ for <code>{{ .Entry.Manifest.Platform }}</code> platform.
|
||||
Pushover: &model.NotifPushover{
|
||||
Token: "uQiRzpo4DXghDmr9QzzfQu27cmVRsG",
|
||||
Recipient: "gznej3rKEVAvPUxu9vvNnqpmZpokzF",
|
||||
Timeout: utl.NewDuration(10 * time.Second),
|
||||
TemplateTitle: model.NotifDefaultTemplateTitle,
|
||||
TemplateBody: model.NotifDefaultTemplateBody,
|
||||
},
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/crazy-max/diun/v4/pkg/utl"
|
||||
)
|
||||
|
||||
// NotifPushover holds Pushover notification configuration details
|
||||
type NotifPushover struct {
|
||||
Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"`
|
||||
TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"`
|
||||
Recipient string `yaml:"recipient,omitempty" json:"recipient,omitempty" validate:"omitempty"`
|
||||
RecipientFile string `yaml:"recipientFile,omitempty" json:"recipientFile,omitempty" validate:"omitempty,file"`
|
||||
Priority int `yaml:"priority,omitempty" json:"priority,omitempty" validate:"omitempty,min=-2,max=2"`
|
||||
Sound string `yaml:"sound,omitempty" json:"sound,omitempty" validate:"omitempty"`
|
||||
TemplateTitle string `yaml:"templateTitle,omitempty" json:"templateTitle,omitempty" validate:"required"`
|
||||
TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"`
|
||||
Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"`
|
||||
TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"`
|
||||
Recipient string `yaml:"recipient,omitempty" json:"recipient,omitempty" validate:"omitempty"`
|
||||
RecipientFile string `yaml:"recipientFile,omitempty" json:"recipientFile,omitempty" validate:"omitempty,file"`
|
||||
Priority int `yaml:"priority,omitempty" json:"priority,omitempty" validate:"omitempty,min=-2,max=2"`
|
||||
Sound string `yaml:"sound,omitempty" json:"sound,omitempty" validate:"omitempty"`
|
||||
Timeout *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty" validate:"required"`
|
||||
TemplateTitle string `yaml:"templateTitle,omitempty" json:"templateTitle,omitempty" validate:"required"`
|
||||
TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"`
|
||||
}
|
||||
|
||||
// GetDefaults gets the default values
|
||||
@@ -21,6 +28,7 @@ func (s *NotifPushover) GetDefaults() *NotifPushover {
|
||||
|
||||
// SetDefaults sets the default values
|
||||
func (s *NotifPushover) SetDefaults() {
|
||||
s.Timeout = utl.NewDuration(10 * time.Second)
|
||||
s.TemplateTitle = NotifDefaultTemplateTitle
|
||||
s.TemplateBody = NotifDefaultTemplateBody
|
||||
}
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
package pushover
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/crazy-max/diun/v4/internal/model"
|
||||
"github.com/crazy-max/diun/v4/internal/msg"
|
||||
"github.com/crazy-max/diun/v4/internal/notif/notifier"
|
||||
"github.com/crazy-max/diun/v4/pkg/utl"
|
||||
"github.com/gregdel/pushover"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const pushoverAPIURL = "https://api.pushover.net/1/messages.json"
|
||||
|
||||
// Client represents an active Pushover notification object
|
||||
type Client struct {
|
||||
*notifier.Notifier
|
||||
@@ -38,11 +46,15 @@ func (c *Client) Send(entry model.NotifEntry) error {
|
||||
token, err := utl.GetSecret(c.cfg.Token, c.cfg.TokenFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot retrieve token secret for Pushover notifier")
|
||||
} else if token == "" {
|
||||
return errors.New("Pushover API token cannot be empty")
|
||||
}
|
||||
|
||||
recipient, err := utl.GetSecret(c.cfg.Recipient, c.cfg.RecipientFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot retrieve recipient secret for Pushover notifier")
|
||||
} else if recipient == "" {
|
||||
return errors.New("Pushover recipient cannot be empty")
|
||||
}
|
||||
|
||||
message, err := msg.New(msg.Options{
|
||||
@@ -60,16 +72,77 @@ func (c *Client) Send(entry model.NotifEntry) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pushover.New(token).SendMessage(&pushover.Message{
|
||||
Title: string(title),
|
||||
Message: string(body),
|
||||
Priority: c.cfg.Priority,
|
||||
Sound: c.cfg.Sound,
|
||||
URL: c.meta.URL,
|
||||
URLTitle: c.meta.Name,
|
||||
Timestamp: time.Now().Unix(),
|
||||
HTML: true,
|
||||
}, pushover.NewRecipient(recipient))
|
||||
cancelCtx, cancel := context.WithCancelCause(context.Background())
|
||||
timeoutCtx, _ := context.WithTimeoutCause(cancelCtx, *c.cfg.Timeout, errors.WithStack(context.DeadlineExceeded)) //nolint:govet // no need to manually cancel this context as we already rely on parent
|
||||
defer func() { cancel(errors.WithStack(context.Canceled)) }()
|
||||
|
||||
return err
|
||||
form := url.Values{}
|
||||
form.Add("token", token)
|
||||
form.Add("user", recipient)
|
||||
form.Add("title", string(title))
|
||||
form.Add("message", string(body))
|
||||
form.Add("priority", strconv.Itoa(c.cfg.Priority))
|
||||
if c.cfg.Sound != "" {
|
||||
form.Add("sound", c.cfg.Sound)
|
||||
}
|
||||
if c.meta.URL != "" {
|
||||
form.Add("url", c.meta.URL)
|
||||
}
|
||||
if c.meta.Name != "" {
|
||||
form.Add("url_title", c.meta.Name)
|
||||
}
|
||||
form.Add("timestamp", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
form.Add("html", "1")
|
||||
|
||||
hc := http.Client{}
|
||||
req, err := http.NewRequestWithContext(timeoutCtx, "POST", pushoverAPIURL, strings.NewReader(form.Encode()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("User-Agent", c.meta.UserAgent)
|
||||
|
||||
resp, err := hc.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.Header != nil {
|
||||
var appLimit, appRemaining int
|
||||
var appReset time.Time
|
||||
if limit := resp.Header.Get("X-Limit-App-Limit"); limit != "" {
|
||||
if i, err := strconv.Atoi(limit); err == nil {
|
||||
appLimit = i
|
||||
}
|
||||
}
|
||||
if remaining := resp.Header.Get("X-Limit-App-Remaining"); remaining != "" {
|
||||
if i, err := strconv.Atoi(remaining); err == nil {
|
||||
appRemaining = i
|
||||
}
|
||||
}
|
||||
if reset := resp.Header.Get("X-Limit-App-Reset"); reset != "" {
|
||||
if i, err := strconv.Atoi(reset); err == nil {
|
||||
appReset = time.Unix(int64(i), 0)
|
||||
}
|
||||
}
|
||||
log.Debug().Msgf("Pushover app limit: %d, remaining: %d, reset: %s", appLimit, appRemaining, appReset)
|
||||
}
|
||||
|
||||
var respBody struct {
|
||||
Status int `json:"status"`
|
||||
Request string `json:"request"`
|
||||
Errors []string `json:"errors"`
|
||||
User string `json:"user"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
if err = json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
|
||||
return errors.Wrapf(err, "cannot decode JSON body response for HTTP %d %s status: %+v", resp.StatusCode, http.StatusText(resp.StatusCode), respBody)
|
||||
}
|
||||
if respBody.Status != 1 {
|
||||
return errors.Errorf("Pushover API call failed with status %d: %v", respBody.Status, respBody.Errors)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user