Initial version
This commit is contained in:
parent
328790b281
commit
686a322f00
76
bus/bus.go
Normal file
76
bus/bus.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
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
|
||||||
|
}
|
@ -48,7 +48,7 @@
|
|||||||
version = version;
|
version = version;
|
||||||
pname = "alerttonotify";
|
pname = "alerttonotify";
|
||||||
src = src;
|
src = src;
|
||||||
vendorHash = pkgs.lib.fakeHash;
|
vendorHash = "sha256-1ejnJykXY+j/xddFupLII2SXGsbxBSUaAe20YpcMzgQ=";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
2
go.mod
2
go.mod
@ -1,3 +1,5 @@
|
|||||||
module git.t-juice.club/torjus/alerttonotify
|
module git.t-juice.club/torjus/alerttonotify
|
||||||
|
|
||||||
go 1.23.3
|
go 1.23.3
|
||||||
|
|
||||||
|
require github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
|
2
go.sum
Normal file
2
go.sum
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
54
main.go
54
main.go
@ -1,9 +1,59 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"context"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"git.t-juice.club/torjus/alerttonotify/bus"
|
||||||
|
"git.t-juice.club/torjus/alerttonotify/server"
|
||||||
|
)
|
||||||
|
|
||||||
const Version = "v0.1.0"
|
const Version = "v0.1.0"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("Hello!")
|
// Setup logging
|
||||||
|
logger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
|
||||||
|
Level: slog.LevelDebug,
|
||||||
|
}))
|
||||||
|
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)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer nbus.Close()
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
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.Addr = ":5001"
|
||||||
|
|
||||||
|
// Listen for shutdown signal
|
||||||
|
go func() {
|
||||||
|
<-shutdownCtx.Done()
|
||||||
|
srv.Shutdown(context.Background())
|
||||||
|
}()
|
||||||
|
|
||||||
|
logger.Info("Starting http server", "addr", srv.Addr)
|
||||||
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
|
logger.Error("Failed to start http server", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
logger.Info("Shutting down")
|
||||||
}
|
}
|
||||||
|
91
server/server.go
Normal file
91
server/server.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.t-juice.club/torjus/alerttonotify/bus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
logger *slog.Logger
|
||||||
|
nbus *bus.NotifyBus
|
||||||
|
http.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alert struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Labels map[string]string `json:"labels"`
|
||||||
|
Annotations map[string]string `json:"annotations"`
|
||||||
|
StartsAt time.Time `json:"startsAt"`
|
||||||
|
EndsAt time.Time `json:"endsAt"`
|
||||||
|
GeneratorURL string `json:"generatorURL"`
|
||||||
|
Fingerprint string `json:"fingerprint"`
|
||||||
|
}
|
||||||
|
type AlertMessage struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
GroupKey string `json:"groupKey"`
|
||||||
|
TruncatedAlerts int `json:"truncatedAlerts"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Receiver string `json:"receiver"`
|
||||||
|
GroupLabels map[string]string `json:"groupLabels"`
|
||||||
|
CommonLabels map[string]string `json:"commonLabels"`
|
||||||
|
CommonAnnotations map[string]string `json:"commonAnnotations"`
|
||||||
|
ExternalURL string `json:"externalURL"`
|
||||||
|
Alerts []Alert `json:"alerts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(nbus *bus.NotifyBus, logger *slog.Logger) *Server {
|
||||||
|
srv := &Server{
|
||||||
|
nbus: nbus,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("GET /", srv.handleIndex)
|
||||||
|
mux.HandleFunc("POST /alert", srv.handleAlert)
|
||||||
|
|
||||||
|
srv.Handler = mux
|
||||||
|
|
||||||
|
return srv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
s.logger.Info("index page")
|
||||||
|
w.Write([]byte("Hello!"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleAlert(w http.ResponseWriter, r *http.Request) {
|
||||||
|
s.logger.Debug("Got new alert", "remoteAddr", r.RemoteAddr)
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
var alertMessage AlertMessage
|
||||||
|
if err := decoder.Decode(&alertMessage); err != nil {
|
||||||
|
s.logger.Error("Failed to decode alert message", "error", err)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.logger.Debug("Decoded alert message", "alert", alertMessage)
|
||||||
|
|
||||||
|
s.logger.Info("Incoming message", "status", alertMessage.Status)
|
||||||
|
var sb strings.Builder
|
||||||
|
for _, alert := range alertMessage.Alerts {
|
||||||
|
s.logger.Debug("Incoming alert", "status", alert.Status, "fingerprint", alert.Fingerprint)
|
||||||
|
if summary, ok := alert.Annotations["summary"]; ok {
|
||||||
|
sb.WriteString(fmt.Sprintf("[%s] %s\n", strings.ToUpper(alert.Status), summary))
|
||||||
|
} else {
|
||||||
|
sb.WriteString(fmt.Sprintf("[%s]: %s\n", strings.ToUpper(alert.Status), alert.Fingerprint))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := bus.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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user