89 lines
2.5 KiB
Go
89 lines
2.5 KiB
Go
package rabbitmq
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/wagslane/go-rabbitmq"
|
|
|
|
"code.icb4dc0.de/prskr/pg_v_man/core/domain"
|
|
"code.icb4dc0.de/prskr/pg_v_man/core/ports"
|
|
"code.icb4dc0.de/prskr/pg_v_man/infrastructure/config"
|
|
)
|
|
|
|
var _ ports.ReplicationEventConsumer = (*PublishingEventConsumer)(nil)
|
|
|
|
func NewPublishingEventConsumer(ctx context.Context, cfg config.RabbitMQ) (consumer *PublishingEventConsumer, err error) {
|
|
var dialer net.Dialer
|
|
conn, err := rabbitmq.NewConn(cfg.ConnectionString, rabbitmq.WithConnectionOptionsLogging, func(options *rabbitmq.ConnectionOptions) {
|
|
options.Config.Dial = func(network, addr string) (net.Conn, error) {
|
|
return dialer.DialContext(ctx, network, addr)
|
|
}
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not create RabbitMQ connection: %w", err)
|
|
}
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
err = errors.Join(err, conn.Close())
|
|
}
|
|
}()
|
|
|
|
publisherOptions := []func(*rabbitmq.PublisherOptions){
|
|
rabbitmq.WithPublisherOptionsLogging,
|
|
rabbitmq.WithPublisherOptionsExchangeName(cfg.Exchange.Name),
|
|
rabbitmq.WithPublisherOptionsExchangeKind(cfg.Exchange.Kind),
|
|
rabbitmq.WithPublisherOptionsExchangeDeclare,
|
|
}
|
|
|
|
if cfg.Exchange.Durable {
|
|
publisherOptions = append(publisherOptions, rabbitmq.WithPublisherOptionsExchangeDurable)
|
|
}
|
|
|
|
publisher, err := rabbitmq.NewPublisher(
|
|
conn,
|
|
publisherOptions...,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not create RabbitMQ publisher: %w", err)
|
|
}
|
|
|
|
return &PublishingEventConsumer{Conn: conn, Publisher: publisher, Cfg: cfg}, nil
|
|
}
|
|
|
|
type PublishingEventConsumer struct {
|
|
Conn *rabbitmq.Conn
|
|
Publisher *rabbitmq.Publisher
|
|
Cfg config.RabbitMQ
|
|
}
|
|
|
|
func (p PublishingEventConsumer) OnDataChange(ctx context.Context, ev domain.ReplicationEvent) error {
|
|
data, err := json.Marshal(ev)
|
|
if err != nil {
|
|
return fmt.Errorf("could not marshal event: %w", err)
|
|
}
|
|
return p.Publisher.PublishWithContext(
|
|
ctx, data, []string{p.Cfg.RoutingKey, strings.Join([]string{ev.DBName, ev.Namespace, ev.Relation}, ".")},
|
|
rabbitmq.WithPublishOptionsContentType("application/json"),
|
|
rabbitmq.WithPublishOptionsExchange(p.Cfg.Exchange.Name),
|
|
rabbitmq.WithPublishOptionsCorrelationID(strconv.Itoa(int(ev.TransactionId))),
|
|
rabbitmq.WithPublishOptionsType(ev.EventType.String()),
|
|
rabbitmq.WithPublishOptionsHeaders(rabbitmq.Table{
|
|
"db": ev.DBName,
|
|
"namespace": ev.Namespace,
|
|
"relation": ev.Relation,
|
|
}),
|
|
)
|
|
}
|
|
|
|
func (p PublishingEventConsumer) Close() error {
|
|
p.Publisher.Close()
|
|
|
|
return p.Conn.Close()
|
|
}
|