181 lines
3.9 KiB
Go
181 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"log/slog"
|
|
"os"
|
|
"os/signal"
|
|
|
|
"git.t-juice.club/torjus/natstonotify/bus"
|
|
"git.t-juice.club/torjus/natstonotify/server"
|
|
"github.com/nats-io/nats.go"
|
|
"github.com/nats-io/nkeys"
|
|
"github.com/urfave/cli/v3"
|
|
)
|
|
|
|
const Version = "v0.1.0"
|
|
|
|
func connectNats() (*nats.Conn, error) {
|
|
natsURL, ok := os.LookupEnv("NATS_URL")
|
|
if !ok {
|
|
return nil, fmt.Errorf("NATS_URL not set")
|
|
}
|
|
nkey, ok := os.LookupEnv("NATS_NKEY")
|
|
if !ok {
|
|
return nil, fmt.Errorf("NATS_NKEY not set")
|
|
}
|
|
|
|
kp, err := nkeys.FromSeed([]byte(nkey))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pub, err := kp.PublicKey()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
opt := nats.Nkey(pub, kp.Sign)
|
|
|
|
nc, err := nats.Connect(natsURL, opt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return nc, nil
|
|
}
|
|
|
|
func main() {
|
|
// Setup logging
|
|
logger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
|
|
Level: slog.LevelDebug,
|
|
}))
|
|
|
|
slog.SetDefault(logger)
|
|
|
|
cmd := &cli.Command{
|
|
EnableShellCompletion: true,
|
|
Usage: "NATS-powered notification service",
|
|
Commands: []*cli.Command{
|
|
{
|
|
Name: "server",
|
|
Usage: "Start the server",
|
|
EnableShellCompletion: true,
|
|
Action: func(ctx context.Context, cmd *cli.Command) error {
|
|
b, err := bus.NewNotifyBus()
|
|
if err != nil {
|
|
fmt.Println("Error creating notification bus: ", err)
|
|
return cli.Exit(err, 1)
|
|
}
|
|
|
|
info, err := b.ServerInfo()
|
|
if err != nil {
|
|
return cli.Exit(err, 1)
|
|
}
|
|
|
|
logger.Info("Connected to notification bus", "bus_name", info.Name, "bus_version", info.Version)
|
|
|
|
defer b.Close()
|
|
|
|
nc, err := connectNats()
|
|
if err != nil {
|
|
logger.Error("Error connecting to NATS", "error", err)
|
|
return cli.Exit(err, 1)
|
|
}
|
|
srv, err := server.New(nc, b)
|
|
if err != nil {
|
|
return cli.Exit(err, 1)
|
|
}
|
|
|
|
go func() {
|
|
<-ctx.Done()
|
|
srv.Close()
|
|
}()
|
|
|
|
slog.Info("Server started", "version", Version)
|
|
if err := srv.Start(); err != nil {
|
|
slog.Info("Server exited with error", "error", err)
|
|
return cli.Exit(err, 2)
|
|
}
|
|
|
|
slog.Info("Server stopped")
|
|
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
Name: "notify",
|
|
Aliases: []string{"n"},
|
|
Usage: "Send a notification",
|
|
ArgsUsage: "SUMMARY [BODY]",
|
|
EnableShellCompletion: true,
|
|
Flags: []cli.Flag{
|
|
&cli.BoolFlag{
|
|
Name: "local",
|
|
Usage: "Send a local notification",
|
|
},
|
|
},
|
|
Action: func(ctx context.Context, cmd *cli.Command) error {
|
|
if cmd.NArg() < 1 {
|
|
return cli.Exit("notify requires exactly one argument", 1)
|
|
}
|
|
summary := cmd.Args().Get(0)
|
|
body := cmd.Args().Get(1)
|
|
|
|
bn := bus.BusNotification{
|
|
Summary: summary,
|
|
Body: body,
|
|
}
|
|
|
|
local := cmd.Bool("local")
|
|
if local {
|
|
b, err := bus.NewNotifyBus()
|
|
if err != nil {
|
|
fmt.Println("Error creating notification bus: ", err)
|
|
return cli.Exit(err, 1)
|
|
}
|
|
defer b.Close()
|
|
|
|
_, err = b.Notify(bn)
|
|
if err != nil {
|
|
fmt.Println("Sending message: ", err)
|
|
return cli.Exit(err, 1)
|
|
}
|
|
} else {
|
|
nc, err := connectNats()
|
|
if err != nil {
|
|
fmt.Printf("Error connecting to NATS: %s\n", err)
|
|
return cli.Exit(err, 1)
|
|
}
|
|
defer nc.Drain() //nolint: errcheck
|
|
|
|
data, err := json.Marshal(bn)
|
|
if err != nil {
|
|
return cli.Exit(err, 1)
|
|
}
|
|
|
|
if err := nc.PublishMsg(&nats.Msg{
|
|
Subject: server.DefaultSubject,
|
|
Data: data,
|
|
}); err != nil {
|
|
fmt.Printf("Error sending message: %s\n", err)
|
|
}
|
|
nc.Flush()
|
|
fmt.Printf("Published message to %s: %s", server.DefaultSubject, data)
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
|
defer cancel()
|
|
|
|
if err := cmd.Run(ctx, os.Args); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|