github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/server/publisher.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync/atomic"
     7  
     8  	"github.com/google/uuid"
     9  	"github.com/volts-dev/volts/broker"
    10  	"github.com/volts-dev/volts/client"
    11  	"github.com/volts-dev/volts/codec"
    12  	"github.com/volts-dev/volts/internal/errors"
    13  	"github.com/volts-dev/volts/internal/metadata"
    14  )
    15  
    16  type (
    17  	// PublisherOption defines the method to customize a Publisher.
    18  	PublisherOption func(*Publisher)
    19  	// PublishOption used by Publish.
    20  	PublishOption func(*PublishConfig)
    21  
    22  	PublishConfig struct {
    23  		// Other options for implementations of the interface
    24  		// can be stored in a context
    25  		Context context.Context
    26  		// Exchange is the routing exchange for the message
    27  		Exchange string
    28  	}
    29  
    30  	// Message is the interface for publishing asynchronously.
    31  	IMessage interface {
    32  		Topic() string
    33  		Payload() interface{}
    34  		ContentType() string // codec 类型 用于指定序列或者加密
    35  	}
    36  
    37  	Publisher struct {
    38  		id     string
    39  		once   atomic.Value
    40  		Broker broker.IBroker
    41  		Client client.IClient
    42  	}
    43  )
    44  
    45  // NewPublisher returns a Publisher.
    46  func NewPublisher(opts ...PublisherOption) *Publisher {
    47  	pub := &Publisher{
    48  		id: uuid.New().String(),
    49  	}
    50  	pub.Init(opts...)
    51  	return pub
    52  }
    53  
    54  func (self *Publisher) Init(opts ...PublisherOption) {
    55  	for _, opt := range opts {
    56  		opt(self)
    57  	}
    58  }
    59  
    60  // 发布订阅消息
    61  func (self *Publisher) Publish(ctx context.Context, msg IMessage, opts ...PublishOption) error {
    62  	cfg := PublishConfig{
    63  		Context: context.Background(),
    64  	}
    65  	for _, o := range opts {
    66  		o(&cfg)
    67  	}
    68  	// set the topic
    69  	topic := msg.Topic()
    70  
    71  	metadata, ok := metadata.FromContext(ctx)
    72  	if !ok {
    73  		metadata = make(map[string]string)
    74  	}
    75  
    76  	metadata["Content-Type"] = msg.ContentType()
    77  	metadata["Micro-Topic"] = topic
    78  	metadata["Micro-ID"] = self.id
    79  
    80  	// get the exchange
    81  	if len(cfg.Exchange) > 0 {
    82  		topic = cfg.Exchange
    83  	}
    84  
    85  	// encode message body
    86  	cf := codec.Use(msg.ContentType())
    87  	if cf == 0 {
    88  		return nil
    89  		//return merrors.InternalServerError(packageID, err.Error())
    90  	}
    91  
    92  	// 验证解码器
    93  	msgCodece := codec.IdentifyCodec(cf)
    94  	if msgCodece == nil { // no codec specified
    95  		return errors.UnsupportedCodec("volts.client", cf)
    96  	}
    97  
    98  	body, err := msgCodece.Encode(msg.Payload())
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	l, ok := self.once.Load().(bool)
   104  	if !ok {
   105  		return fmt.Errorf("failed to cast to bool")
   106  	}
   107  
   108  	if !l {
   109  		if err = self.Broker.Start(); err != nil {
   110  			return err
   111  			//return merrors.InternalServerError(packageID, err.Error())
   112  		}
   113  
   114  		self.once.Store(true)
   115  	}
   116  
   117  	return self.Broker.Publish(topic, &broker.Message{
   118  		Header: metadata,
   119  		Body:   body,
   120  	}, broker.PublishContext(cfg.Context))
   121  }
   122  
   123  // WithId customizes a Publisher with the id.
   124  func WithId(id string) PublisherOption {
   125  	return func(publisher *Publisher) {
   126  		publisher.id = id
   127  	}
   128  }
   129  
   130  func WithClient(cli client.IClient) PublisherOption {
   131  	return func(publisher *Publisher) {
   132  		publisher.Client = cli
   133  	}
   134  }
   135  
   136  func WithPublisherBroker(brok broker.IBroker) PublisherOption {
   137  	return func(publisher *Publisher) {
   138  		publisher.Broker = brok
   139  	}
   140  }