mirror of
https://github.com/hanzo-fi/go-libs.git
synced 2026-10-30 20:53:44 +00:00
555 lines
18 KiB
Go
555 lines
18 KiB
Go
package messagingfx
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/IBM/sarama"
|
|
"github.com/ThreeDotsLabs/watermill"
|
|
"github.com/ThreeDotsLabs/watermill-aws/sns"
|
|
"github.com/ThreeDotsLabs/watermill-aws/sqs"
|
|
wHttp "github.com/ThreeDotsLabs/watermill-http/v2/pkg/http"
|
|
"github.com/ThreeDotsLabs/watermill-kafka/v3/pkg/kafka"
|
|
wNats "github.com/ThreeDotsLabs/watermill-nats/v2/pkg/nats"
|
|
"github.com/ThreeDotsLabs/watermill/message"
|
|
"github.com/ThreeDotsLabs/watermill/pubsub/gochannel"
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
|
"github.com/aws/aws-sdk-go-v2/config"
|
|
"github.com/aws/aws-sdk-go-v2/credentials"
|
|
snsservice "github.com/aws/aws-sdk-go-v2/service/sns"
|
|
sqsservice "github.com/aws/aws-sdk-go-v2/service/sqs"
|
|
transport "github.com/aws/smithy-go/endpoints"
|
|
"github.com/nats-io/nats.go"
|
|
"github.com/spf13/cobra"
|
|
"github.com/uptrace/bun"
|
|
"github.com/xdg-go/scram"
|
|
"go.uber.org/fx"
|
|
|
|
"github.com/hanzo-fi/go-libs/v5/pkg/cloud/aws/iam"
|
|
"github.com/hanzo-fi/go-libs/v5/pkg/messaging/publish"
|
|
circuitbreaker "github.com/hanzo-fi/go-libs/v5/pkg/messaging/publish/circuit"
|
|
circuitstorage "github.com/hanzo-fi/go-libs/v5/pkg/messaging/publish/circuit/storage"
|
|
topicmapper "github.com/hanzo-fi/go-libs/v5/pkg/messaging/publish/topicmap"
|
|
logging "github.com/hanzo-fi/go-libs/v5/pkg/observe/log"
|
|
"github.com/hanzo-fi/go-libs/v5/pkg/service"
|
|
bunconnect "github.com/hanzo-fi/go-libs/v5/pkg/storage/bun/connect"
|
|
bundebug "github.com/hanzo-fi/go-libs/v5/pkg/storage/bun/debug"
|
|
)
|
|
|
|
func defaultLoggingModule() fx.Option {
|
|
return fx.Provide(func(logger logging.Logger) watermill.LoggerAdapter {
|
|
return publish.NewWatermillLoggerAdapter(logger, false)
|
|
})
|
|
}
|
|
|
|
func GoChannelModule() fx.Option {
|
|
return fx.Options(
|
|
fx.Provide(publish.NewGoChannel),
|
|
fx.Provide(func(ch *gochannel.GoChannel) message.Subscriber {
|
|
return ch
|
|
}),
|
|
fx.Provide(func(ch *gochannel.GoChannel) message.Publisher {
|
|
return ch
|
|
}),
|
|
fx.Invoke(func(lc fx.Lifecycle, channel *gochannel.GoChannel) {
|
|
lc.Append(fx.Hook{
|
|
OnStop: func(ctx context.Context) error {
|
|
return channel.Close()
|
|
},
|
|
})
|
|
}),
|
|
)
|
|
}
|
|
|
|
func Module(topics map[string]string) fx.Option {
|
|
options := fx.Options(
|
|
defaultLoggingModule(),
|
|
fx.Supply(message.RouterConfig{}),
|
|
fx.Provide(message.NewRouter),
|
|
fx.Invoke(func(router *message.Router, lc fx.Lifecycle) error {
|
|
lc.Append(fx.Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
go func() {
|
|
if err := router.Run(context.Background()); err != nil {
|
|
panic(err)
|
|
}
|
|
}()
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-router.Running():
|
|
}
|
|
return nil
|
|
},
|
|
OnStop: func(ctx context.Context) error {
|
|
logging.FromContext(ctx).Infof("Stopping router...")
|
|
if err := router.Close(); err != nil {
|
|
return fmt.Errorf("stopping router: %w", err)
|
|
}
|
|
logging.FromContext(ctx).Infof("Router stopped...")
|
|
|
|
return nil
|
|
},
|
|
})
|
|
return nil
|
|
}),
|
|
fx.Provide(func(publisher message.Publisher) *topicmapper.TopicMapperPublisherDecorator {
|
|
return topicmapper.NewPublisherDecorator(publisher, topics)
|
|
}),
|
|
)
|
|
return options
|
|
}
|
|
|
|
func ProvideSaramaOption(options ...publish.SaramaOption) fx.Option {
|
|
fxOptions := make([]fx.Option, 0)
|
|
for _, opt := range options {
|
|
opt := opt
|
|
fxOptions = append(fxOptions, fx.Provide(fx.Annotate(func() publish.SaramaOption {
|
|
return opt
|
|
}, fx.ResultTags(`group:"saramaOptions"`), fx.As(new(publish.SaramaOption)))))
|
|
}
|
|
return fx.Options(fxOptions...)
|
|
}
|
|
|
|
func KafkaModule(clientId string, consumerGroup string, brokers ...string) fx.Option {
|
|
return fx.Options(
|
|
fx.Supply(publish.ClientID(clientId)),
|
|
fx.Supply(sarama.V1_0_0_0),
|
|
fx.Supply(fx.Annotate(kafka.DefaultMarshaler{}, fx.As(new(kafka.Marshaler)))),
|
|
fx.Supply(fx.Annotate(kafka.DefaultMarshaler{}, fx.As(new(kafka.Unmarshaler)))),
|
|
fx.Provide(fx.Annotate(publish.NewSaramaConfig, fx.ParamTags(``, ``, `group:"saramaOptions"`))),
|
|
fx.Provide(func(lc fx.Lifecycle, logger watermill.LoggerAdapter, marshaller kafka.Marshaler, config *sarama.Config) (*kafka.Publisher, error) {
|
|
ret, err := publish.NewKafkaPublisher(logger, config, marshaller, brokers...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lc.Append(fx.Hook{
|
|
OnStop: func(ctx context.Context) error {
|
|
return ret.Close()
|
|
},
|
|
})
|
|
return ret, nil
|
|
}),
|
|
fx.Provide(func(lc fx.Lifecycle, logger watermill.LoggerAdapter, unmarshaler kafka.Unmarshaler, config *sarama.Config) (*kafka.Subscriber, error) {
|
|
ret, err := publish.NewKafkaSubscriber(logger, config, unmarshaler, consumerGroup, brokers...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lc.Append(fx.Hook{
|
|
OnStop: func(ctx context.Context) error {
|
|
return ret.Close()
|
|
},
|
|
})
|
|
return ret, nil
|
|
}),
|
|
fx.Provide(func(kafkaPublisher *kafka.Publisher) message.Publisher {
|
|
return kafkaPublisher
|
|
}),
|
|
fx.Provide(func(kafkaSubscriber *kafka.Subscriber) message.Subscriber {
|
|
return kafkaSubscriber
|
|
}),
|
|
)
|
|
}
|
|
|
|
func NatsModule(url, group string, autoProvision bool, natsOptions ...nats.Option) fx.Option {
|
|
jetStreamConfig := wNats.JetStreamConfig{
|
|
AutoProvision: autoProvision,
|
|
SubscribeOptions: []nats.SubOpt{nats.ManualAck()},
|
|
}
|
|
return fx.Options(
|
|
fx.Provide(publish.NewNatsConn),
|
|
fx.Invoke(func(lc fx.Lifecycle, conn *nats.Conn) {
|
|
lc.Append(fx.Hook{
|
|
OnStop: func(ctx context.Context) error {
|
|
logging.FromContext(ctx).Infof("stopping nats connection")
|
|
conn.Close()
|
|
return nil
|
|
},
|
|
})
|
|
}),
|
|
fx.Provide(func(logger logging.Logger, shutdowner fx.Shutdowner) publish.NATSCallbacks {
|
|
return publish.NewNatsDefaultCallbacks(logger, func() error {
|
|
return shutdowner.Shutdown()
|
|
})
|
|
}),
|
|
fx.Provide(publish.NewNatsPublisherWithConn),
|
|
fx.Provide(publish.NewNatsSubscriberWithConn),
|
|
fx.Provide(func(natsCallbacks publish.NATSCallbacks) wNats.PublisherConfig {
|
|
natsOptions = publish.AppendNatsCallBacks(natsOptions, natsCallbacks)
|
|
return wNats.PublisherConfig{
|
|
NatsOptions: natsOptions,
|
|
URL: url,
|
|
Marshaler: &wNats.NATSMarshaler{},
|
|
JetStream: jetStreamConfig,
|
|
SubjectCalculator: wNats.DefaultSubjectCalculator,
|
|
}
|
|
}),
|
|
fx.Provide(func(natsCallbacks publish.NATSCallbacks) wNats.SubscriberConfig {
|
|
natsOptions = publish.AppendNatsCallBacks(natsOptions, natsCallbacks)
|
|
return wNats.SubscriberConfig{
|
|
NatsOptions: natsOptions,
|
|
Unmarshaler: &wNats.NATSMarshaler{},
|
|
URL: url,
|
|
QueueGroupPrefix: group,
|
|
JetStream: jetStreamConfig,
|
|
SubjectCalculator: wNats.DefaultSubjectCalculator,
|
|
SubscribersCount: 100,
|
|
NakDelay: wNats.NewStaticDelay(time.Second),
|
|
}
|
|
}),
|
|
fx.Provide(func(publisher *wNats.Publisher) message.Publisher {
|
|
return publisher
|
|
}),
|
|
fx.Provide(func(subscriber *wNats.Subscriber, lc fx.Lifecycle) message.Subscriber {
|
|
lc.Append(fx.Hook{
|
|
OnStop: func(ctx context.Context) error {
|
|
return subscriber.Close()
|
|
},
|
|
})
|
|
return subscriber
|
|
}),
|
|
)
|
|
}
|
|
|
|
func HTTPModule() fx.Option {
|
|
return fx.Module("publish-http",
|
|
fx.Provide(publish.NewHTTPPublisher),
|
|
fx.Provide(publish.NewHTTPPublisherConfig),
|
|
fx.Provide(publish.DefaultHTTPMarshalMessageFunc),
|
|
fx.Supply(http.DefaultClient, fx.Private),
|
|
fx.Provide(func(p *wHttp.Publisher) message.Publisher {
|
|
return p
|
|
}),
|
|
)
|
|
}
|
|
|
|
func SNSModule(cmd *cobra.Command, snsEndpointOverride string) fx.Option {
|
|
return fx.Options(
|
|
fx.Provide(
|
|
fx.Annotate(func(optFn func(*config.LoadOptions) error) []func(*config.LoadOptions) error {
|
|
loadOptions := []func(*config.LoadOptions) error{optFn}
|
|
if snsEndpointOverride != "" {
|
|
loadOptions = append(loadOptions, config.WithCredentialsProvider(
|
|
credentials.NewStaticCredentialsProvider("dummy", "dummy", "dummy"),
|
|
))
|
|
}
|
|
return loadOptions
|
|
}, fx.ParamTags(`name:"publish-sns-enabled"`), fx.ResultTags(`name:"publish-sns-load-opts"`)),
|
|
),
|
|
fx.Provide(
|
|
fx.Annotate(func(loadOpts []func(*config.LoadOptions) error) (aws.Config, error) {
|
|
cfg, err := config.LoadDefaultConfig(cmd.Context(), loadOpts...)
|
|
if err != nil {
|
|
return cfg, fmt.Errorf("unable to load aws config %w", err)
|
|
}
|
|
return cfg, nil
|
|
}, fx.ParamTags(`name:"publish-sns-load-opts"`), fx.ResultTags(`name:"publish-sns-cfg"`, ``)),
|
|
),
|
|
fx.Provide(
|
|
fx.Annotate(func() ([]func(*snsservice.Options), error) {
|
|
snsOpts := []func(*snsservice.Options){}
|
|
if snsEndpointOverride == "" {
|
|
return snsOpts, nil
|
|
}
|
|
|
|
snsUrl, err := url.Parse(snsEndpointOverride)
|
|
if err != nil {
|
|
return snsOpts, fmt.Errorf("unable to parse sns url %q", snsEndpointOverride)
|
|
}
|
|
snsOpts = append(snsOpts, snsservice.WithEndpointResolverV2(sns.OverrideEndpointResolver{
|
|
Endpoint: transport.Endpoint{
|
|
URI: *snsUrl,
|
|
},
|
|
}))
|
|
return snsOpts, nil
|
|
}, fx.ResultTags(`name:"publish-sns-opts"`, ``)),
|
|
),
|
|
fx.Provide(
|
|
fx.Annotate(func(lc fx.Lifecycle, logger watermill.LoggerAdapter, cfg aws.Config, optFns []func(*snsservice.Options)) (*sns.Publisher, error) {
|
|
ret, err := publish.NewSnsPublisher(cmd.Context(), logger, cfg, optFns, service.IsDebug(cmd))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lc.Append(fx.Hook{
|
|
OnStop: func(ctx context.Context) error {
|
|
return ret.Close()
|
|
},
|
|
})
|
|
return ret, nil
|
|
}, fx.ParamTags(``, ``, `name:"publish-sns-cfg"`, `name:"publish-sns-opts"`)),
|
|
),
|
|
fx.Provide(func(snsPublisher *sns.Publisher) message.Publisher {
|
|
return snsPublisher
|
|
}),
|
|
)
|
|
}
|
|
|
|
func SQSModule(cmd *cobra.Command, sqsEndpointOverride string) fx.Option {
|
|
return fx.Options(
|
|
fx.Provide(
|
|
fx.Annotate(func(optFn func(*config.LoadOptions) error) []func(*config.LoadOptions) error {
|
|
loadOptions := []func(*config.LoadOptions) error{optFn}
|
|
if sqsEndpointOverride != "" {
|
|
loadOptions = append(loadOptions, config.WithCredentialsProvider(
|
|
credentials.NewStaticCredentialsProvider("dummy", "dummy", "dummy"),
|
|
))
|
|
}
|
|
return loadOptions
|
|
}, fx.ParamTags(`name:"publish-sqs-enabled"`), fx.ResultTags(`name:"publish-subscriber-sqs-load-opts"`)),
|
|
),
|
|
fx.Provide(
|
|
fx.Annotate(func(loadOpts []func(*config.LoadOptions) error) (aws.Config, error) {
|
|
cfg, err := config.LoadDefaultConfig(cmd.Context(), loadOpts...)
|
|
if err != nil {
|
|
return cfg, fmt.Errorf("unable to load aws config %w", err)
|
|
}
|
|
return cfg, nil
|
|
}, fx.ParamTags(`name:"publish-subscriber-sqs-load-opts"`), fx.ResultTags(`name:"publish-subscriber-sqs-cfg"`, ``)),
|
|
),
|
|
fx.Provide(
|
|
fx.Annotate(func() ([]func(*sqsservice.Options), error) {
|
|
sqsOpts := []func(*sqsservice.Options){}
|
|
if sqsEndpointOverride == "" {
|
|
return sqsOpts, nil
|
|
}
|
|
|
|
sqsUrl, err := url.Parse(sqsEndpointOverride)
|
|
if err != nil {
|
|
return sqsOpts, fmt.Errorf("unable to parse sqs url %q", sqsEndpointOverride)
|
|
}
|
|
sqsOpts = append(sqsOpts, sqsservice.WithEndpointResolverV2(sqs.OverrideEndpointResolver{
|
|
Endpoint: transport.Endpoint{
|
|
URI: *sqsUrl,
|
|
},
|
|
}))
|
|
return sqsOpts, nil
|
|
}, fx.ResultTags(`name:"publish-subscriber-sqs-opts"`, ``)),
|
|
),
|
|
fx.Provide(
|
|
fx.Annotate(func(lc fx.Lifecycle, logger watermill.LoggerAdapter, cfg aws.Config, optFns []func(*sqsservice.Options)) (*sqs.Subscriber, error) {
|
|
ret, err := publish.NewSqsSubscriber(logger, cfg, optFns, service.IsDebug(cmd))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lc.Append(fx.Hook{
|
|
OnStop: func(ctx context.Context) error {
|
|
return ret.Close()
|
|
},
|
|
})
|
|
return ret, nil
|
|
}, fx.ParamTags(``, ``, `name:"publish-subscriber-sqs-cfg"`, `name:"publish-subscriber-sqs-opts"`)),
|
|
),
|
|
fx.Provide(func(sqsSubscriber *sqs.Subscriber) message.Subscriber {
|
|
return sqsSubscriber
|
|
}),
|
|
)
|
|
}
|
|
|
|
func CircuitBreakerStorageModule(schema string, storageLimit int, debug bool) fx.Option {
|
|
return fx.Provide(func(connectionOptions *bunconnect.ConnectionOptions, lc fx.Lifecycle) (circuitstorage.Store, error) {
|
|
hooks := make([]bun.QueryHook, 0)
|
|
if debug {
|
|
hooks = append(hooks, bundebug.NewQueryHook())
|
|
}
|
|
|
|
db, err := bunconnect.OpenDBWithSchema(context.Background(), *connectionOptions, schema, hooks...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
lc.Append(fx.Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
return circuitstorage.Migrate(ctx, schema, db)
|
|
},
|
|
})
|
|
|
|
return circuitstorage.New(schema, db, storageLimit), nil
|
|
})
|
|
}
|
|
|
|
func CircuitBreakerModule(schema string, openIntervalDuration time.Duration, storageLimit int, debug bool) fx.Option {
|
|
return fx.Options(
|
|
fx.Provide(func(
|
|
logger logging.Logger,
|
|
topicMapper *topicmapper.TopicMapperPublisherDecorator,
|
|
store circuitstorage.Store,
|
|
lc fx.Lifecycle,
|
|
) *circuitbreaker.CircuitBreaker {
|
|
cb := circuitbreaker.NewCircuitBreaker(logger, topicMapper, store, openIntervalDuration)
|
|
|
|
lc.Append(fx.Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
go cb.Loop(context.WithoutCancel(ctx))
|
|
return nil
|
|
},
|
|
OnStop: func(ctx context.Context) error {
|
|
return cb.Close()
|
|
},
|
|
})
|
|
return cb
|
|
}),
|
|
CircuitBreakerStorageModule(schema, storageLimit, debug),
|
|
)
|
|
}
|
|
|
|
func PublishModuleFromFlags(cmd *cobra.Command, debug bool) fx.Option {
|
|
options := make([]fx.Option, 0)
|
|
|
|
topics, _ := cmd.Flags().GetStringSlice(publish.PublisherTopicMappingFlag)
|
|
queueGroup, _ := cmd.Flags().GetString(publish.PublisherQueueGroupFlag)
|
|
|
|
mapping := make(map[string]string)
|
|
for _, topic := range topics {
|
|
parts := strings.SplitN(topic, ":", 2)
|
|
if len(parts) != 2 {
|
|
panic(fmt.Sprintf("unable to parse topic '%s', must be two parts, separated by a colon", topic))
|
|
}
|
|
mapping[parts[0]] = parts[1]
|
|
}
|
|
|
|
options = append(options, Module(mapping))
|
|
|
|
circuitBreakerEnabled, _ := cmd.Flags().GetBool(publish.PublisherCircuitBreakerEnabledFlag)
|
|
if circuitBreakerEnabled {
|
|
scheme, _ := cmd.Flags().GetString(publish.PublisherCircuitBreakerSchemaFlag)
|
|
intervalDuration, _ := cmd.Flags().GetDuration(publish.PublisherCircuitBreakerOpenIntervalDurationFlag)
|
|
storageLimit, _ := cmd.Flags().GetInt(publish.PublisherCircuitBreakerListStorageLimitFlag)
|
|
|
|
options = append(options,
|
|
CircuitBreakerModule(scheme, intervalDuration, storageLimit, debug),
|
|
fx.Decorate(func(cb *circuitbreaker.CircuitBreaker) message.Publisher {
|
|
return cb
|
|
}),
|
|
)
|
|
} else {
|
|
options = append(options,
|
|
fx.Decorate(func(topicMapper *topicmapper.TopicMapperPublisherDecorator) message.Publisher {
|
|
return topicMapper
|
|
}),
|
|
)
|
|
}
|
|
|
|
httpEnabled, _ := cmd.Flags().GetBool(publish.PublisherHttpEnabledFlag)
|
|
natsEnabled, _ := cmd.Flags().GetBool(publish.PublisherNatsEnabledFlag)
|
|
kafkaEnabled, _ := cmd.Flags().GetBool(publish.PublisherKafkaEnabledFlag)
|
|
sqsSubscriberEnabled, _ := cmd.Flags().GetBool(publish.SubscriberSqsEnabledFlag)
|
|
snsPublisherEnabled, _ := cmd.Flags().GetBool(publish.PublisherSnsEnabledFlag)
|
|
|
|
switch {
|
|
case httpEnabled:
|
|
options = append(options, HTTPModule())
|
|
case natsEnabled:
|
|
natsConnName := queueGroup
|
|
clientId, _ := cmd.Flags().GetString(publish.PublisherNatsClientIDFlag)
|
|
if clientId != "" {
|
|
natsConnName = clientId
|
|
}
|
|
natsUrl, _ := cmd.Flags().GetString(publish.PublisherNatsURLFlag)
|
|
autoProvision, _ := cmd.Flags().GetBool(publish.PublisherNatsAutoProvisionFlag)
|
|
maxReconnect, _ := cmd.Flags().GetInt(publish.PublisherNatsMaxReconnectFlag)
|
|
maxReconnectWait, _ := cmd.Flags().GetDuration(publish.PublisherNatsReconnectWaitFlag)
|
|
nkeyFiles, _ := cmd.Flags().GetStringArray(publish.PublisherNatsNkeyFileFlag)
|
|
|
|
natsOptions := []nats.Option{
|
|
nats.Name(natsConnName),
|
|
nats.MaxReconnects(maxReconnect),
|
|
nats.ReconnectWait(maxReconnectWait),
|
|
}
|
|
|
|
for _, file := range nkeyFiles {
|
|
option, err := nats.NkeyOptionFromSeed(file)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("unable to parse nkey file '%s': %v", file, err))
|
|
}
|
|
natsOptions = append(natsOptions, option)
|
|
}
|
|
|
|
options = append(options, NatsModule(
|
|
natsUrl,
|
|
queueGroup,
|
|
autoProvision,
|
|
natsOptions...,
|
|
))
|
|
|
|
case sqsSubscriberEnabled, snsPublisherEnabled:
|
|
if sqsSubscriberEnabled {
|
|
sqsEndpointOverride, _ := cmd.Flags().GetString(publish.SubscriberSqsEndpointOverrideFlag)
|
|
|
|
options = append(options,
|
|
fx.Supply(fx.Annotate(iam.LoadOptionFromFlags(cmd.Flags()), fx.ResultTags(`name:"publish-sqs-enabled"`))),
|
|
SQSModule(cmd, sqsEndpointOverride),
|
|
)
|
|
}
|
|
if snsPublisherEnabled {
|
|
snsEndpointOverride, _ := cmd.Flags().GetString(publish.PublisherSnsEndpointOverrideFlag)
|
|
|
|
options = append(options,
|
|
fx.Supply(fx.Annotate(iam.LoadOptionFromFlags(cmd.Flags()), fx.ResultTags(`name:"publish-sns-enabled"`))),
|
|
SNSModule(cmd, snsEndpointOverride),
|
|
)
|
|
}
|
|
case kafkaEnabled:
|
|
brokers, _ := cmd.Flags().GetStringSlice(publish.PublisherKafkaBrokerFlag)
|
|
|
|
options = append(options,
|
|
KafkaModule(queueGroup, queueGroup, brokers...),
|
|
ProvideSaramaOption(
|
|
publish.WithConsumerReturnErrors(),
|
|
publish.WithProducerReturnSuccess(),
|
|
),
|
|
)
|
|
if tlsEnabled, _ := cmd.Flags().GetBool(publish.PublisherKafkaTLSEnabledFlag); tlsEnabled {
|
|
options = append(options, ProvideSaramaOption(publish.WithTLS()))
|
|
}
|
|
if saslEnabled, _ := cmd.Flags().GetBool(publish.PublisherKafkaSASLEnabledFlag); saslEnabled {
|
|
mechanism, _ := cmd.Flags().GetString(publish.PublisherKafkaSASLMechanismFlag)
|
|
saslUsername, _ := cmd.Flags().GetString(publish.PublisherKafkaSASLUsernameFlag)
|
|
saslPassword, _ := cmd.Flags().GetString(publish.PublisherKafkaSASLPasswordFlag)
|
|
saslScramShaSize, _ := cmd.Flags().GetInt(publish.PublisherKafkaSASLScramSHASizeFlag)
|
|
|
|
saramaOptions := []publish.SaramaOption{
|
|
publish.WithSASLEnabled(),
|
|
publish.WithSASLMechanism(sarama.SASLMechanism(mechanism)),
|
|
publish.WithSASLCredentials(saslUsername, saslPassword),
|
|
publish.WithSASLScramClient(func() sarama.SCRAMClient {
|
|
var fn scram.HashGeneratorFcn
|
|
switch saslScramShaSize {
|
|
case 512:
|
|
fn = publish.SHA512
|
|
case 256:
|
|
fn = publish.SHA256
|
|
default:
|
|
panic("sha size not handled")
|
|
}
|
|
return &publish.XDGSCRAMClient{
|
|
HashGeneratorFcn: fn,
|
|
}
|
|
}),
|
|
}
|
|
|
|
if awsEnabled, _ := cmd.Flags().GetBool(publish.PublisherKafkaSASLIAMEnabledFlag); awsEnabled {
|
|
region, _ := cmd.Flags().GetString(iam.AWSRegionFlag)
|
|
roleArn, _ := cmd.Flags().GetString(iam.AWSRoleArnFlag)
|
|
sessionName, _ := cmd.Flags().GetString(publish.PublisherKafkaSASLIAMSessionNameFlag)
|
|
|
|
saramaOptions = append(saramaOptions,
|
|
publish.WithTokenProvider(&publish.MSKAccessTokenProvider{
|
|
Region: region,
|
|
RoleArn: roleArn,
|
|
SessionName: sessionName,
|
|
}),
|
|
)
|
|
}
|
|
|
|
options = append(options, ProvideSaramaOption(saramaOptions...))
|
|
}
|
|
default:
|
|
options = append(options, GoChannelModule())
|
|
}
|
|
return fx.Options(options...)
|
|
}
|