diff --git a/bus/bus.go b/bus/bus.go deleted file mode 100644 index 7610c98..0000000 --- a/bus/bus.go +++ /dev/null @@ -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 -} diff --git a/go.mod b/go.mod index 72bfbaf..9aa2bed 100644 --- a/go.mod +++ b/go.mod @@ -3,3 +3,12 @@ module git.t-juice.club/torjus/alerttonotify go 1.23.3 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 +) diff --git a/go.sum b/go.sum index 024b269..4feca97 100644 --- a/go.sum +++ b/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/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= diff --git a/main.go b/main.go index f5f5e01..fe77d7c 100644 --- a/main.go +++ b/main.go @@ -6,12 +6,12 @@ import ( "net/http" "os" "os/signal" + "strings" - "git.t-juice.club/torjus/alerttonotify/bus" "git.t-juice.club/torjus/alerttonotify/server" ) -const Version = "v0.1.0" +const Version = "v0.1.1" func main() { // Setup logging @@ -20,33 +20,50 @@ func main() { })) logger.Info("Starting alerttonotify", "version", Version) - // Setup dbus connection - nbus, err := bus.NewNotifyBus() - if err != nil { - logger.Error("Failed to create notify bus", "error", err) + // Setup nats connection + natsURL, ok := os.LookupEnv("NATS_URL") + if !ok { + logger.Error("NATS_URL not set") 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 - info, err := nbus.ServerInfo() - if err != nil { - logger.Error("Failed to get notification server info", "error", err) - os.Exit(1) - return + data, err := os.ReadFile(path) + if err != nil { + logger.Error("unable to read NATS_NKEY_FILE", "error", err) + os.Exit(1) + } + 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) defer cancel() // Setup http server - srv := server.NewServer(nbus, logger) + srv := server.NewServer(ns, logger) srv.Addr = ":5001" + addr, ok := os.LookupEnv("ALERTTONOTIFY_ADDR") + if ok { + srv.Addr = addr + } + // Listen for shutdown signal go func() { <-shutdownCtx.Done() + srv.Close() srv.Shutdown(context.Background()) }() diff --git a/server/notify.go b/server/notify.go new file mode 100644 index 0000000..84b2da6 --- /dev/null +++ b/server/notify.go @@ -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() +} diff --git a/server/server.go b/server/server.go index 2456060..5e7ba4a 100644 --- a/server/server.go +++ b/server/server.go @@ -7,13 +7,11 @@ import ( "net/http" "strings" "time" - - "git.t-juice.club/torjus/alerttonotify/bus" ) type Server struct { logger *slog.Logger - nbus *bus.NotifyBus + ns *NotificationService http.Server } @@ -39,9 +37,8 @@ type AlertMessage struct { Alerts []Alert `json:"alerts"` } -func NewServer(nbus *bus.NotifyBus, logger *slog.Logger) *Server { +func NewServer(ns *NotificationService, logger *slog.Logger) *Server { srv := &Server{ - nbus: nbus, 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), Body: sb.String(), } - s.logger.Debug("Sending notification", "notification", notification) - s.nbus.Notify(notification) + s.logger.Debug("Sending notification", "message", msg) + if err := s.ns.Notify(msg); err != nil { + s.logger.Error("Failed to send notification", "error", err) + + w.WriteHeader(http.StatusInternalServerError) + } }