106 lines
2.8 KiB
Go
106 lines
2.8 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"
|
|
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
|
|
}
|
|
|
|
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)
|
|
}
|