76 lines
2.4 KiB
Go
76 lines
2.4 KiB
Go
// Package bus provides NATS messaging for the poller service.
|
|
//
|
|
// credential_subscriber.go subscribes to device.credential_changed.> events
|
|
// and invalidates the credential cache so the poller uses fresh credentials
|
|
// on the next poll cycle instead of waiting for the 5-minute cache TTL.
|
|
package bus
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log/slog"
|
|
|
|
"github.com/nats-io/nats.go"
|
|
|
|
"github.com/staack/the-other-dude/poller/internal/vault"
|
|
)
|
|
|
|
// CredentialSubscriber listens for credential change events and invalidates
|
|
// the credential cache. This ensures the poller picks up new credentials
|
|
// within seconds of a change rather than waiting for the 5-minute TTL.
|
|
type CredentialSubscriber struct {
|
|
nc *nats.Conn
|
|
credentialCache *vault.CredentialCache
|
|
sub *nats.Subscription
|
|
}
|
|
|
|
// NewCredentialSubscriber creates a subscriber that invalidates cached
|
|
// credentials when the backend publishes credential_changed events.
|
|
func NewCredentialSubscriber(nc *nats.Conn, credentialCache *vault.CredentialCache) *CredentialSubscriber {
|
|
return &CredentialSubscriber{nc: nc, credentialCache: credentialCache}
|
|
}
|
|
|
|
// Start subscribes to "device.credential_changed.>" with a queue group
|
|
// so only one poller instance processes each event.
|
|
func (s *CredentialSubscriber) Start() error {
|
|
sub, err := s.nc.QueueSubscribe("device.credential_changed.>", "credential-invalidators", s.handleEvent)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.sub = sub
|
|
slog.Info("credential subscriber started", "subject", "device.credential_changed.>", "queue", "credential-invalidators")
|
|
return nil
|
|
}
|
|
|
|
// Stop unsubscribes from NATS.
|
|
func (s *CredentialSubscriber) Stop() {
|
|
if s.sub != nil {
|
|
if err := s.sub.Unsubscribe(); err != nil {
|
|
slog.Warn("error unsubscribing credential subscriber", "error", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// handleEvent processes a credential_changed event by invalidating the
|
|
// device's entry in the credential cache.
|
|
func (s *CredentialSubscriber) handleEvent(msg *nats.Msg) {
|
|
var event struct {
|
|
DeviceID string `json:"device_id"`
|
|
TenantID string `json:"tenant_id"`
|
|
}
|
|
if err := json.Unmarshal(msg.Data, &event); err != nil {
|
|
slog.Warn("failed to unmarshal credential_changed event", "error", err)
|
|
return
|
|
}
|
|
|
|
if event.DeviceID == "" {
|
|
slog.Warn("credential_changed event missing device_id")
|
|
return
|
|
}
|
|
|
|
s.credentialCache.Invalidate(event.DeviceID)
|
|
slog.Info("credential cache invalidated",
|
|
"device_id", event.DeviceID,
|
|
"tenant_id", event.TenantID,
|
|
)
|
|
}
|