package nats import ( "context" "fmt" "time" "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" ) type Client struct { Conn *nats.Conn JS jetstream.JetStream } // Connect initializes a NATS connection and JetStream context. func Connect(url string) (*Client, error) { nc, err := nats.Connect(url, nats.Name("SimpleArmaAdmin"), nats.MaxReconnects(-1), // Infinite retries nats.ReconnectWait(2*time.Second), nats.RetryOnFailedConnect(true), // Important for Docker startup nats.Timeout(5*time.Second), ) if err != nil { return nil, fmt.Errorf("failed to connect to NATS: %w", err) } js, err := jetstream.New(nc) if err != nil { nc.Close() return nil, fmt.Errorf("failed to create JetStream context: %w", err) } return &Client{ Conn: nc, JS: js, }, nil } // SetupStream ensures a JetStream stream exists for logs. func (c *Client) SetupStream(ctx context.Context, streamName string, subjects []string) error { _, err := c.JS.CreateOrUpdateStream(ctx, jetstream.StreamConfig{ Name: streamName, Subjects: subjects, Retention: jetstream.LimitsPolicy, MaxAge: 30 * 24 * time.Hour, // 30 days retention as per blueprint }) return err } // PublishLog sends an encrypted log blob to a specific subject. func (c *Client) PublishLog(ctx context.Context, communityID string, logType string, data []byte) error { subject := fmt.Sprintf("logs.%s.%s", communityID, logType) _, err := c.JS.Publish(ctx, subject, data) return err } func (c *Client) Close() { if c.Conn != nil { c.Conn.Close() } }