kra-new/pkg/mq/mq.go

108 lines
2.9 KiB
Go

// Package mq exposes the broker-agnostic messaging seam used by services.
package mq
import (
"context"
"encoding/json"
"errors"
"time"
)
var ErrUnavailable = errors.New("message broker unavailable")
const (
ProviderEMQX = "emqx"
ProviderKafka = "kafka"
ProviderRabbitMQ = "rabbitmq"
)
const (
AtMostOnce byte = 0
AtLeastOnce byte = 1
ExactlyOnce byte = 2
)
type Message struct {
Topic string
Payload []byte
QoS byte
Retain bool
}
func (m Message) DecodeJSON(target any) error { return json.Unmarshal(m.Payload, target) }
type Handler func(context.Context, Message)
// TopicSubscription is one logical module subscription. The handler is kept
// by the runtime and is replayed after a client reconnects or is rebuilt.
type TopicSubscription struct {
Topic string
QoS byte
Handler Handler
}
// SubscriptionSet is the complete subscription declaration for one module and
// provider. Registering the same owner/provider replaces its previous set.
// Owner must be a stable module name, not a request or goroutine identifier.
type SubscriptionSet struct {
Owner string
Provider string
Topics []TopicSubscription
}
// SubscriptionRegistrar is the module-facing seam for durable-in-process
// subscription intent. Register does not require a live broker; the runtime
// will bind the declared topics when the provider becomes available.
type SubscriptionRegistrar interface {
Register(SubscriptionSet) error
Unregister(owner string) error
}
// SubscriptionContributor lets a module expose its broker subscriptions
// without depending on the concrete integration implementation.
type SubscriptionContributor interface {
RegisterSubscriptions(SubscriptionRegistrar) error
}
type Client interface {
Publish(context.Context, string, []byte, byte, bool) error
Subscribe(context.Context, string, byte, Handler) error
Unsubscribe(context.Context, ...string) error
Connected() bool
Close() error
}
// Registry exposes named broker clients while preserving Client as the
// default EMQX/MQTT boundary for existing modules.
type Registry interface {
SubscriptionRegistrar
Client(provider string) Client
PublishTo(context.Context, string, string, []byte, byte, bool) error
SubscribeTo(context.Context, string, string, byte, Handler) error
UnsubscribeFrom(context.Context, string, ...string) error
ConnectedTo(provider string) bool
}
type Config struct {
Enabled bool
Broker string
ClientID string
Username string
Password string
KeepAlive time.Duration
CleanSession bool
ConnectTimeout time.Duration
ReconnectInterval time.Duration
}
func PublishJSON(ctx context.Context, client Client, topic string, value any, qos byte, retain bool) error {
if client == nil {
return ErrUnavailable
}
payload, err := json.Marshal(value)
if err != nil {
return err
}
return client.Publish(ctx, topic, payload, qos, retain)
}