Switch to using nats for notifications
This commit is contained in:
parent
d941260e38
commit
360109d684
76
bus/bus.go
76
bus/bus.go
@ -1,76 +0,0 @@
|
|||||||
package bus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/godbus/dbus/v5"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NotifyBus struct {
|
|
||||||
conn *dbus.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
type BusNotification struct {
|
|
||||||
ID uint32
|
|
||||||
Summary string
|
|
||||||
Body string
|
|
||||||
Timeout time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotifyServerInfo struct {
|
|
||||||
Name string
|
|
||||||
Vendor string
|
|
||||||
Version string
|
|
||||||
SpecVersion string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNotifyBus() (*NotifyBus, error) {
|
|
||||||
conn, err := dbus.ConnectSessionBus()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &NotifyBus{conn: conn}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifyBus) Close() {
|
|
||||||
n.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifyBus) ServerInfo() (*NotifyServerInfo, error) {
|
|
||||||
obj := n.conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
|
|
||||||
call := obj.Call(
|
|
||||||
"org.freedesktop.Notifications.GetServerInformation", // Method
|
|
||||||
0, // Flags
|
|
||||||
)
|
|
||||||
if call.Err != nil {
|
|
||||||
return nil, call.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
srvInfo := &NotifyServerInfo{}
|
|
||||||
call.Store(&srvInfo.Name, &srvInfo.Vendor, &srvInfo.Version, &srvInfo.SpecVersion)
|
|
||||||
return srvInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NotifyBus) Notify(notification BusNotification) (uint32, error) {
|
|
||||||
obj := n.conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
|
|
||||||
var ret uint32
|
|
||||||
call := obj.Call(
|
|
||||||
"org.freedesktop.Notifications.Notify", // Method
|
|
||||||
0, // Flags
|
|
||||||
"alerttonotify", // App name
|
|
||||||
notification.ID, // Notification ID
|
|
||||||
"", // Icon
|
|
||||||
notification.Summary, // Summary
|
|
||||||
notification.Body, // Body
|
|
||||||
[]string{}, // Actions
|
|
||||||
map[string]dbus.Variant{}, // Hints
|
|
||||||
int32(notification.Timeout.Milliseconds()), // Timeout
|
|
||||||
)
|
|
||||||
if call.Err != nil {
|
|
||||||
return ret, call.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
call.Store(&ret)
|
|
||||||
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
9
go.mod
9
go.mod
@ -3,3 +3,12 @@ module git.t-juice.club/torjus/alerttonotify
|
|||||||
go 1.23.3
|
go 1.23.3
|
||||||
|
|
||||||
require github.com/godbus/dbus/v5 v5.1.0
|
require github.com/godbus/dbus/v5 v5.1.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
|
github.com/nats-io/nats.go v1.39.0 // indirect
|
||||||
|
github.com/nats-io/nkeys v0.4.10 // indirect
|
||||||
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
|
golang.org/x/crypto v0.33.0 // indirect
|
||||||
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
|
)
|
||||||
|
12
go.sum
12
go.sum
@ -1,2 +1,14 @@
|
|||||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
|
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||||
|
github.com/nats-io/nats.go v1.39.0 h1:2/yg2JQjiYYKLwDuBzV0FbB2sIV+eFNkEevlRi4n9lI=
|
||||||
|
github.com/nats-io/nats.go v1.39.0/go.mod h1:MgRb8oOdigA6cYpEPhXJuRVH6UE/V4jblJ2jQ27IXYM=
|
||||||
|
github.com/nats-io/nkeys v0.4.10 h1:glmRrpCmYLHByYcePvnTBEAwawwapjCPMjy2huw20wc=
|
||||||
|
github.com/nats-io/nkeys v0.4.10/go.mod h1:OjRrnIKnWBFl+s4YK5ChQfvHP2fxqZexrKJoVVyWB3U=
|
||||||
|
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||||
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
|
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||||
|
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
47
main.go
47
main.go
@ -6,12 +6,12 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.t-juice.club/torjus/alerttonotify/bus"
|
|
||||||
"git.t-juice.club/torjus/alerttonotify/server"
|
"git.t-juice.club/torjus/alerttonotify/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Version = "v0.1.0"
|
const Version = "v0.1.1"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Setup logging
|
// Setup logging
|
||||||
@ -20,33 +20,50 @@ func main() {
|
|||||||
}))
|
}))
|
||||||
logger.Info("Starting alerttonotify", "version", Version)
|
logger.Info("Starting alerttonotify", "version", Version)
|
||||||
|
|
||||||
// Setup dbus connection
|
// Setup nats connection
|
||||||
nbus, err := bus.NewNotifyBus()
|
natsURL, ok := os.LookupEnv("NATS_URL")
|
||||||
if err != nil {
|
if !ok {
|
||||||
logger.Error("Failed to create notify bus", "error", err)
|
logger.Error("NATS_URL not set")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer nbus.Close()
|
nkey, ok := os.LookupEnv("NATS_NKEY")
|
||||||
|
if !ok {
|
||||||
|
path, ok := os.LookupEnv("NATS_NKEY_FILE")
|
||||||
|
if !ok {
|
||||||
|
logger.Error("NATS_NKEY and NATS_NKEY_FILE not set")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
// Verify connection and server
|
data, err := os.ReadFile(path)
|
||||||
info, err := nbus.ServerInfo()
|
if err != nil {
|
||||||
if err != nil {
|
logger.Error("unable to read NATS_NKEY_FILE", "error", err)
|
||||||
logger.Error("Failed to get notification server info", "error", err)
|
os.Exit(1)
|
||||||
os.Exit(1)
|
}
|
||||||
return
|
nkey = strings.TrimSpace(string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
ns, err := server.NewNotificationService(natsURL, nkey)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to create notification service", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
logger.Info("Connected to notification daemon", "server", info.Name, "version", info.Version)
|
|
||||||
|
|
||||||
shutdownCtx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
shutdownCtx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Setup http server
|
// Setup http server
|
||||||
srv := server.NewServer(nbus, logger)
|
srv := server.NewServer(ns, logger)
|
||||||
srv.Addr = ":5001"
|
srv.Addr = ":5001"
|
||||||
|
|
||||||
|
addr, ok := os.LookupEnv("ALERTTONOTIFY_ADDR")
|
||||||
|
if ok {
|
||||||
|
srv.Addr = addr
|
||||||
|
}
|
||||||
|
|
||||||
// Listen for shutdown signal
|
// Listen for shutdown signal
|
||||||
go func() {
|
go func() {
|
||||||
<-shutdownCtx.Done()
|
<-shutdownCtx.Done()
|
||||||
|
srv.Close()
|
||||||
srv.Shutdown(context.Background())
|
srv.Shutdown(context.Background())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
63
server/notify.go
Normal file
63
server/notify.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/nats-io/nats.go"
|
||||||
|
"github.com/nats-io/nkeys"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DEFAULT_SUBJECT = "home2rjusnet.notifications"
|
||||||
|
|
||||||
|
type BusNotification struct {
|
||||||
|
ID uint32 `json:"id,omitempty"`
|
||||||
|
Summary string `json:"summary"`
|
||||||
|
Body string `json:"body,omitempty"`
|
||||||
|
Timeout time.Duration `json:"timeout,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotificationService struct {
|
||||||
|
Subject string
|
||||||
|
nc *nats.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNotificationService(url, nkey string) (*NotificationService, error) {
|
||||||
|
kp, err := nkeys.FromSeed([]byte(nkey))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error creating nkey: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub, err := kp.PublicKey()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting public key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opt := nats.Nkey(pub, kp.Sign)
|
||||||
|
|
||||||
|
nc, err := nats.Connect(url, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error connecting to nats: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &NotificationService{nc: nc, Subject: DEFAULT_SUBJECT}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NotificationService) Notify(msg *BusNotification) error {
|
||||||
|
data, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error marshalling notification: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = n.nc.Publish(n.Subject, data)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error publishing notification: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NotificationService) Close() {
|
||||||
|
n.nc.Close()
|
||||||
|
}
|
@ -7,13 +7,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.t-juice.club/torjus/alerttonotify/bus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
nbus *bus.NotifyBus
|
ns *NotificationService
|
||||||
http.Server
|
http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,9 +37,8 @@ type AlertMessage struct {
|
|||||||
Alerts []Alert `json:"alerts"`
|
Alerts []Alert `json:"alerts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(nbus *bus.NotifyBus, logger *slog.Logger) *Server {
|
func NewServer(ns *NotificationService, logger *slog.Logger) *Server {
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
nbus: nbus,
|
|
||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,10 +79,14 @@ func (s *Server) handleAlert(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notification := bus.BusNotification{
|
msg := &BusNotification{
|
||||||
Summary: fmt.Sprintf("%d alerts %s", len(alertMessage.Alerts), alertMessage.Status),
|
Summary: fmt.Sprintf("%d alerts %s", len(alertMessage.Alerts), alertMessage.Status),
|
||||||
Body: sb.String(),
|
Body: sb.String(),
|
||||||
}
|
}
|
||||||
s.logger.Debug("Sending notification", "notification", notification)
|
s.logger.Debug("Sending notification", "message", msg)
|
||||||
s.nbus.Notify(notification)
|
if err := s.ns.Notify(msg); err != nil {
|
||||||
|
s.logger.Error("Failed to send notification", "error", err)
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user