github.com/wfusion/gofusion@v1.1.14/common/infra/watermill/components/cqrs/event_bus.go (about)

     1  package cqrs
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/pkg/errors"
     7  	"go.uber.org/multierr"
     8  
     9  	"github.com/wfusion/gofusion/common/infra/watermill"
    10  	"github.com/wfusion/gofusion/common/infra/watermill/message"
    11  )
    12  
    13  type EventBusConfig struct {
    14  	// GeneratePublishTopic is used to generate topic name for publishing event.
    15  	GeneratePublishTopic GenerateEventPublishTopicFn
    16  
    17  	// OnPublish is called before sending the event.
    18  	// The *message.Message can be modified.
    19  	//
    20  	// This option is not required.
    21  	OnPublish OnEventSendFn
    22  
    23  	// Marshaler is used to marshal and unmarshal events.
    24  	// It is required.
    25  	Marshaler CommandEventMarshaler
    26  
    27  	// Logger instance used to log.
    28  	// If not provided, watermill.NopLogger is used.
    29  	Logger watermill.LoggerAdapter
    30  }
    31  
    32  func (c *EventBusConfig) setDefaults() {
    33  	if c.Logger == nil {
    34  		c.Logger = watermill.NopLogger{}
    35  	}
    36  }
    37  
    38  func (c EventBusConfig) Validate() error {
    39  	var err error
    40  
    41  	if c.Marshaler == nil {
    42  		err = multierr.Append(err, errors.New("missing Marshaler"))
    43  	}
    44  
    45  	if c.GeneratePublishTopic == nil {
    46  		err = multierr.Append(err, errors.New("missing GenerateHandlerTopic"))
    47  	}
    48  
    49  	return err
    50  }
    51  
    52  type GenerateEventPublishTopicFn func(GenerateEventPublishTopicParams) (string, error)
    53  
    54  type GenerateEventPublishTopicParams struct {
    55  	EventName string
    56  	Event     any
    57  }
    58  
    59  type OnEventSendFn func(params OnEventSendParams) error
    60  
    61  type OnEventSendParams struct {
    62  	EventName string
    63  	Event     any
    64  
    65  	// Message is never nil and can be modified.
    66  	Message *message.Message
    67  }
    68  
    69  // EventBus transports events to event handlers.
    70  type EventBus struct {
    71  	publisher message.Publisher
    72  	config    EventBusConfig
    73  }
    74  
    75  // NewEventBus creates a new CommandBus.
    76  // Deprecated: use NewEventBusWithConfig instead.
    77  func NewEventBus(
    78  	publisher message.Publisher,
    79  	generateTopic func(eventName string) string,
    80  	marshaler CommandEventMarshaler,
    81  ) (*EventBus, error) {
    82  	if publisher == nil {
    83  		return nil, errors.New("missing publisher")
    84  	}
    85  	if generateTopic == nil {
    86  		return nil, errors.New("missing generateTopic")
    87  	}
    88  	if marshaler == nil {
    89  		return nil, errors.New("missing marshaler")
    90  	}
    91  
    92  	return &EventBus{
    93  		publisher: publisher,
    94  		config: EventBusConfig{
    95  			GeneratePublishTopic: func(params GenerateEventPublishTopicParams) (string, error) {
    96  				return generateTopic(params.EventName), nil
    97  			},
    98  			Marshaler: marshaler,
    99  		},
   100  	}, nil
   101  }
   102  
   103  // NewEventBusWithConfig creates a new EventBus.
   104  func NewEventBusWithConfig(publisher message.Publisher, config EventBusConfig) (*EventBus, error) {
   105  	if publisher == nil {
   106  		return nil, errors.New("missing publisher")
   107  	}
   108  
   109  	config.setDefaults()
   110  	if err := config.Validate(); err != nil {
   111  		return nil, errors.Wrap(err, "invalid config")
   112  	}
   113  
   114  	return &EventBus{publisher, config}, nil
   115  }
   116  
   117  // Publish sends event to the event bus.
   118  func (c EventBus) Publish(ctx context.Context, event any) error {
   119  	msg, err := c.config.Marshaler.Marshal(event)
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	eventName := c.config.Marshaler.Name(event)
   125  	topicName, err := c.config.GeneratePublishTopic(GenerateEventPublishTopicParams{
   126  		EventName: eventName,
   127  		Event:     event,
   128  	})
   129  	if err != nil {
   130  		return errors.Wrap(err, "cannot generate topic")
   131  	}
   132  
   133  	msg.SetContext(ctx)
   134  
   135  	if c.config.OnPublish != nil {
   136  		err := c.config.OnPublish(OnEventSendParams{
   137  			EventName: eventName,
   138  			Event:     event,
   139  			Message:   msg,
   140  		})
   141  		if err != nil {
   142  			return errors.Wrap(err, "cannot execute OnPublish")
   143  		}
   144  	}
   145  
   146  	return c.publisher.Publish(ctx, topicName, msg)
   147  }