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 }