Skip to content

Commit c14b41e

Browse files
authored
Merge pull request #1490 from crazy-max/pushover-http
switch to http client for pushover notifier
2 parents 5f67b0d + cf2edc7 commit c14b41e

File tree

20 files changed

+106
-1115
lines changed

20 files changed

+106
-1115
lines changed

docs/notif/pushover.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ You can send notifications using [Pushover](https://pushover.net/).
1212
recipient: gznej3rKEVAvPUxu9vvNnqpmZpokzF
1313
priority: -2
1414
sound: none
15+
timeout: 10s
1516
templateTitle: "{{ .Entry.Image }} released"
1617
templateBody: |
1718
Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released.
@@ -25,6 +26,7 @@ You can send notifications using [Pushover](https://pushover.net/).
2526
| `recipientFile` | | Use content of secret file as User key if `recipient` not defined |
2627
| `priority` | | Priority of the notification |
2728
| `sound` | | Notification sound to be used |
29+
| `timeout` | `10s` | Timeout specifies a time limit for the request to be made |
2830
| `templateTitle`[^1] | See [below](#default-templatetitle) | [Notification template](../faq.md#notification-template) for message title |
2931
| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body |
3032

@@ -35,6 +37,7 @@ You can send notifications using [Pushover](https://pushover.net/).
3537
* `DIUN_NOTIF_PUSHOVER_RECIPIENTFILE`
3638
* `DIUN_NOTIF_PUSHOVER_PRIORITY`
3739
* `DIUN_NOTIF_PUSHOVER_SOUND`
40+
* `DIUN_NOTIF_PUSHOVER_TIMEOUT`
3841
* `DIUN_NOTIF_PUSHOVER_TEMPLATETITLE`
3942
* `DIUN_NOTIF_PUSHOVER_TEMPLATEBODY`
4043

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ require (
2121
github.com/eclipse/paho.mqtt.golang v1.5.0
2222
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
2323
github.com/go-playground/validator/v10 v10.27.0
24-
github.com/gregdel/pushover v1.3.1
2524
github.com/hashicorp/nomad/api v0.0.0-20231213195942-64e3dca9274b // v1.7.2
2625
github.com/jedib0t/go-pretty/v6 v6.6.8
2726
github.com/matcornic/hermes/v2 v2.1.0

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,6 @@ github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWS
167167
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
168168
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
169169
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
170-
github.com/gregdel/pushover v1.3.1 h1:4bMLITOZ15+Zpi6qqoGqOPuVHCwSUvMCgVnN5Xhilfo=
171-
github.com/gregdel/pushover v1.3.1/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to=
172170
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
173171
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
174172
github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A=

internal/config/config_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ for <code>{{ .Entry.Manifest.Platform }}</code> platform.
160160
Pushover: &model.NotifPushover{
161161
Token: "uQiRzpo4DXghDmr9QzzfQu27cmVRsG",
162162
Recipient: "gznej3rKEVAvPUxu9vvNnqpmZpokzF",
163+
Timeout: utl.NewDuration(10 * time.Second),
163164
TemplateTitle: model.NotifDefaultTemplateTitle,
164165
TemplateBody: model.NotifDefaultTemplateBody,
165166
},

internal/model/notif_pushover.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
package model
22

3+
import (
4+
"time"
5+
6+
"github.com/crazy-max/diun/v4/pkg/utl"
7+
)
8+
39
// NotifPushover holds Pushover notification configuration details
410
type NotifPushover struct {
5-
Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"`
6-
TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"`
7-
Recipient string `yaml:"recipient,omitempty" json:"recipient,omitempty" validate:"omitempty"`
8-
RecipientFile string `yaml:"recipientFile,omitempty" json:"recipientFile,omitempty" validate:"omitempty,file"`
9-
Priority int `yaml:"priority,omitempty" json:"priority,omitempty" validate:"omitempty,min=-2,max=2"`
10-
Sound string `yaml:"sound,omitempty" json:"sound,omitempty" validate:"omitempty"`
11-
TemplateTitle string `yaml:"templateTitle,omitempty" json:"templateTitle,omitempty" validate:"required"`
12-
TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"`
11+
Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"`
12+
TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"`
13+
Recipient string `yaml:"recipient,omitempty" json:"recipient,omitempty" validate:"omitempty"`
14+
RecipientFile string `yaml:"recipientFile,omitempty" json:"recipientFile,omitempty" validate:"omitempty,file"`
15+
Priority int `yaml:"priority,omitempty" json:"priority,omitempty" validate:"omitempty,min=-2,max=2"`
16+
Sound string `yaml:"sound,omitempty" json:"sound,omitempty" validate:"omitempty"`
17+
Timeout *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty" validate:"required"`
18+
TemplateTitle string `yaml:"templateTitle,omitempty" json:"templateTitle,omitempty" validate:"required"`
19+
TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"`
1320
}
1421

1522
// GetDefaults gets the default values
@@ -21,6 +28,7 @@ func (s *NotifPushover) GetDefaults() *NotifPushover {
2128

2229
// SetDefaults sets the default values
2330
func (s *NotifPushover) SetDefaults() {
31+
s.Timeout = utl.NewDuration(10 * time.Second)
2432
s.TemplateTitle = NotifDefaultTemplateTitle
2533
s.TemplateBody = NotifDefaultTemplateBody
2634
}

internal/notif/pushover/client.go

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
package pushover
22

33
import (
4+
"context"
5+
"encoding/json"
6+
"net/http"
7+
"net/url"
8+
"strconv"
9+
"strings"
410
"time"
511

612
"github.com/crazy-max/diun/v4/internal/model"
713
"github.com/crazy-max/diun/v4/internal/msg"
814
"github.com/crazy-max/diun/v4/internal/notif/notifier"
915
"github.com/crazy-max/diun/v4/pkg/utl"
10-
"github.com/gregdel/pushover"
1116
"github.com/pkg/errors"
17+
"github.com/rs/zerolog/log"
1218
)
1319

20+
const pushoverAPIURL = "https://api.pushover.net/1/messages.json"
21+
1422
// Client represents an active Pushover notification object
1523
type Client struct {
1624
*notifier.Notifier
@@ -38,11 +46,15 @@ func (c *Client) Send(entry model.NotifEntry) error {
3846
token, err := utl.GetSecret(c.cfg.Token, c.cfg.TokenFile)
3947
if err != nil {
4048
return errors.Wrap(err, "cannot retrieve token secret for Pushover notifier")
49+
} else if token == "" {
50+
return errors.New("Pushover API token cannot be empty")
4151
}
4252

4353
recipient, err := utl.GetSecret(c.cfg.Recipient, c.cfg.RecipientFile)
4454
if err != nil {
4555
return errors.Wrap(err, "cannot retrieve recipient secret for Pushover notifier")
56+
} else if recipient == "" {
57+
return errors.New("Pushover recipient cannot be empty")
4658
}
4759

4860
message, err := msg.New(msg.Options{
@@ -60,16 +72,77 @@ func (c *Client) Send(entry model.NotifEntry) error {
6072
return err
6173
}
6274

63-
_, err = pushover.New(token).SendMessage(&pushover.Message{
64-
Title: string(title),
65-
Message: string(body),
66-
Priority: c.cfg.Priority,
67-
Sound: c.cfg.Sound,
68-
URL: c.meta.URL,
69-
URLTitle: c.meta.Name,
70-
Timestamp: time.Now().Unix(),
71-
HTML: true,
72-
}, pushover.NewRecipient(recipient))
73-
74-
return err
75+
cancelCtx, cancel := context.WithCancelCause(context.Background())
76+
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
77+
defer func() { cancel(errors.WithStack(context.Canceled)) }()
78+
79+
form := url.Values{}
80+
form.Add("token", token)
81+
form.Add("user", recipient)
82+
form.Add("title", string(title))
83+
form.Add("message", string(body))
84+
form.Add("priority", strconv.Itoa(c.cfg.Priority))
85+
if c.cfg.Sound != "" {
86+
form.Add("sound", c.cfg.Sound)
87+
}
88+
if c.meta.URL != "" {
89+
form.Add("url", c.meta.URL)
90+
}
91+
if c.meta.Name != "" {
92+
form.Add("url_title", c.meta.Name)
93+
}
94+
form.Add("timestamp", strconv.FormatInt(time.Now().Unix(), 10))
95+
form.Add("html", "1")
96+
97+
hc := http.Client{}
98+
req, err := http.NewRequestWithContext(timeoutCtx, "POST", pushoverAPIURL, strings.NewReader(form.Encode()))
99+
if err != nil {
100+
return err
101+
}
102+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
103+
req.Header.Set("User-Agent", c.meta.UserAgent)
104+
105+
resp, err := hc.Do(req)
106+
if err != nil {
107+
return err
108+
}
109+
defer resp.Body.Close()
110+
111+
if resp.Header != nil {
112+
var appLimit, appRemaining int
113+
var appReset time.Time
114+
if limit := resp.Header.Get("X-Limit-App-Limit"); limit != "" {
115+
if i, err := strconv.Atoi(limit); err == nil {
116+
appLimit = i
117+
}
118+
}
119+
if remaining := resp.Header.Get("X-Limit-App-Remaining"); remaining != "" {
120+
if i, err := strconv.Atoi(remaining); err == nil {
121+
appRemaining = i
122+
}
123+
}
124+
if reset := resp.Header.Get("X-Limit-App-Reset"); reset != "" {
125+
if i, err := strconv.Atoi(reset); err == nil {
126+
appReset = time.Unix(int64(i), 0)
127+
}
128+
}
129+
log.Debug().Msgf("Pushover app limit: %d, remaining: %d, reset: %s", appLimit, appRemaining, appReset)
130+
}
131+
132+
var respBody struct {
133+
Status int `json:"status"`
134+
Request string `json:"request"`
135+
Errors []string `json:"errors"`
136+
User string `json:"user"`
137+
Token string `json:"token"`
138+
}
139+
140+
if err = json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
141+
return errors.Wrapf(err, "cannot decode JSON body response for HTTP %d %s status: %+v", resp.StatusCode, http.StatusText(resp.StatusCode), respBody)
142+
}
143+
if respBody.Status != 1 {
144+
return errors.Errorf("Pushover API call failed with status %d: %v", respBody.Status, respBody.Errors)
145+
}
146+
147+
return nil
75148
}

vendor/github.com/gregdel/pushover/.travis.yml

Lines changed: 0 additions & 9 deletions
This file was deleted.

vendor/github.com/gregdel/pushover/LICENSE

Lines changed: 0 additions & 21 deletions
This file was deleted.

vendor/github.com/gregdel/pushover/README.md

Lines changed: 0 additions & 134 deletions
This file was deleted.

0 commit comments

Comments
 (0)