Implemented rudimentary notification with NTFY and acknowledgement

This commit is contained in:
Magnus Åhall 2024-03-29 20:24:53 +01:00
parent c2555a1d35
commit afcadc8ae1
9 changed files with 346 additions and 69 deletions

15
notification/factory.go Normal file
View file

@ -0,0 +1,15 @@
package notification
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
)
func ServiceFactory(t string, config []byte, prio int, ackURL string) (Service, error) {
switch t {
case "NTFY":
return NewNTFY(config, prio, ackURL)
}
return nil, werr.New("Unknown notification service, '%s'", t).WithCode("002-0000")
}

View file

@ -1,26 +1,70 @@
package notification
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
// Standard
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
type NTFY struct {
URL string
URL string
Prio int
AcknowledgeURL string
}
func NewNTFY(config []byte) (instance NTFY, err error) {
func NewNTFY(config []byte, prio int, ackURL string) (instance NTFY, err error) {
err = json.Unmarshal(config, &instance)
if err != nil {
return
err = werr.Wrap(err).WithCode("002-0001").WithData(config)
return
}
instance.Prio = prio
instance.AcknowledgeURL = ackURL
return instance, nil
}
func (ntfy NTFY) Send(msg []byte) (err error) {
http.NewRequest("POST", ntfy.URL, bytes.NewReader(msg))
func (ntfy NTFY) GetPrio() int {
return ntfy.Prio
}
func (ntfy NTFY) Send(uuid string, msg []byte) (err error) {
var req *http.Request
var res *http.Response
req, err = http.NewRequest("POST", ntfy.URL, bytes.NewReader(msg))
if err != nil {
err = werr.Wrap(err).WithCode("002-0002").WithData(ntfy.URL)
return
}
ackURL := fmt.Sprintf("http, OK, %s/notification/ack?uuid=%s", ntfy.AcknowledgeURL, uuid)
req.Header.Add("X-Actions", ackURL)
res, err = http.DefaultClient.Do(req)
if err != nil {
err = werr.Wrap(err).WithCode("002-0003")
return
}
body, _ := io.ReadAll(res.Body)
if res.StatusCode != 200 {
err = werr.New("Invalid NTFY response").WithCode("002-0004").WithData(body)
return
}
ntfyResp := struct {
ID string
}{}
err = json.Unmarshal(body, &ntfyResp)
if err != nil {
err = werr.Wrap(err).WithCode("002-0005").WithData(body)
return
}
return
}

View file

@ -1,5 +1,59 @@
package notification
type Notification interface {
Send([]byte) error
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
// Standard
_ "fmt"
"slices"
)
type Service interface {
GetPrio() int
Send(string, []byte) error
}
type Manager struct {
services map[int][]Service
}
func NewManager() (nm Manager) {
nm.services = make(map[int][]Service, 32)
return
}
func (nm *Manager) AddService(userID int, service Service) {
var services []Service
var found bool
if services, found = nm.services[userID]; !found {
services = []Service{}
}
services = append(services, service)
slices.SortFunc(services, func(a, b Service) int {
if a.GetPrio() < b.GetPrio() {
return -1
}
if a.GetPrio() > b.GetPrio() {
return 1
}
return 0
})
nm.services[userID] = services
}
func (nm *Manager) Send(userID int, uuid string, msg []byte) (err error) {
services, found := nm.services[userID]
if !found {
return werr.New("No notification services defined for user ID %d", userID).WithCode("002-0008")
}
for _, service := range services {
if err = service.Send(uuid, msg); err == nil {
break
}
}
return
}