github.com/moleculer-go/moleculer@v0.3.3/transit/nats/stan.go (about) 1 package nats 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/moleculer-go/moleculer" 8 "github.com/moleculer-go/moleculer/serializer" 9 "github.com/moleculer-go/moleculer/transit" 10 stan "github.com/nats-io/go-nats-streaming" 11 log "github.com/sirupsen/logrus" 12 ) 13 14 type StanTransporter struct { 15 prefix string 16 url string 17 clusterID string 18 clientID string 19 logger *log.Entry 20 validateMsg transit.ValidateMsgFunc 21 22 serializer serializer.Serializer 23 connection stan.Conn 24 subscriptions []stan.Subscription 25 } 26 27 type StanOptions struct { 28 URL string 29 ClusterID string 30 ClientID string 31 32 Logger *log.Entry 33 Serializer serializer.Serializer 34 35 ValidateMsg transit.ValidateMsgFunc 36 } 37 38 func CreateStanTransporter(options StanOptions) StanTransporter { 39 transport := StanTransporter{} 40 transport.url = options.URL 41 transport.clusterID = options.ClusterID 42 transport.clientID = options.ClientID 43 transport.serializer = options.Serializer 44 transport.logger = options.Logger 45 transport.validateMsg = options.ValidateMsg 46 return transport 47 } 48 49 func (transporter *StanTransporter) Connect() chan error { 50 endChan := make(chan error) 51 go func() { 52 transporter.logger.Debug("STAN Connect() - url: ", transporter.url, " clusterID: ", transporter.clusterID, " clientID: ", transporter.clientID) 53 connection, err := stan.Connect(transporter.clusterID, transporter.clientID, stan.NatsURL(transporter.url)) 54 if err != nil { 55 transporter.logger.Error("STAN Connect() - Error: ", err, " clusterID: ", transporter.clusterID, " clientID: ", transporter.clientID) 56 endChan <- err 57 return 58 } 59 transporter.logger.Info("STAN Connect() - connection success!") 60 transporter.connection = connection 61 endChan <- nil 62 }() 63 return endChan 64 } 65 66 func (transporter *StanTransporter) Disconnect() chan error { 67 endChan := make(chan error) 68 go func() { 69 if transporter.connection == nil { 70 endChan <- nil 71 return 72 } 73 transporter.logger.Debug("Disconnect() # of subscriptions: ", len(transporter.subscriptions)) 74 for _, sub := range transporter.subscriptions { 75 error := sub.Unsubscribe() 76 if error != nil { 77 transporter.logger.Error("Disconnect() error when unsubscribing stan subscription: ", error) 78 } 79 } 80 transporter.logger.Debug("Disconnect() subscriptions unsubscribed.") 81 err := transporter.connection.Close() 82 if err == nil { 83 transporter.logger.Debug("Disconnect() stan connection closed :)") 84 endChan <- nil 85 } else { 86 transporter.logger.Error("Disconnect() error when closing stan connection :( ", err) 87 endChan <- err 88 } 89 transporter.connection = nil 90 }() 91 return endChan 92 } 93 94 func topicName(transporter *StanTransporter, command string, nodeID string) string { 95 if nodeID != "" { 96 return fmt.Sprint(transporter.prefix, ".", command, ".", nodeID) 97 } 98 return fmt.Sprint(transporter.prefix, ".", command) 99 } 100 101 func (transporter *StanTransporter) SetPrefix(prefix string) { 102 transporter.prefix = prefix 103 } 104 105 func (transporter *StanTransporter) SetNodeID(nodeID string) { 106 } 107 108 func (transporter *StanTransporter) SetSerializer(serializer serializer.Serializer) { 109 // Ignored while transporter initialized in pubsub function 110 } 111 112 func (transporter *StanTransporter) Subscribe(command string, nodeID string, handler transit.TransportHandler) { 113 if transporter.connection == nil { 114 msg := fmt.Sprint("stan.Subscribe() No connection :( -> command: ", command, " nodeID: ", nodeID) 115 transporter.logger.Warn(msg) 116 panic(errors.New(msg)) 117 } 118 119 topic := topicName(transporter, command, nodeID) 120 transporter.logger.Trace("stan.Subscribe() command: ", command, " nodeID: ", nodeID, " topic: ", topic) 121 122 sub, err := transporter.connection.Subscribe(topic, func(msg *stan.Msg) { 123 transporter.logger.Trace("stan.Subscribe() command: ", command, " nodeID: ", nodeID, " msg: \n", msg, "\n - end") 124 message := transporter.serializer.BytesToPayload(&msg.Data) 125 if transporter.validateMsg(message) { 126 handler(message) 127 } 128 }) 129 if err != nil { 130 transporter.logger.Error("Subscribe() - Error: ", err) 131 panic(err) 132 } 133 transporter.subscriptions = append(transporter.subscriptions, sub) 134 } 135 136 func (transporter *StanTransporter) Publish(command, nodeID string, message moleculer.Payload) { 137 if transporter.connection == nil { 138 msg := fmt.Sprint("stan.Publish() No connection :( -> command: ", command, " nodeID: ", nodeID) 139 transporter.logger.Warn(msg) 140 panic(errors.New(msg)) 141 } 142 topic := topicName(transporter, command, nodeID) 143 transporter.logger.Trace("stan.Publish() command: ", command, " nodeID: ", nodeID, " message: \n", message, "\n - end") 144 err := transporter.connection.Publish(topic, transporter.serializer.PayloadToBytes(message)) 145 if err != nil { 146 transporter.logger.Error("Error on publish: error: ", err, " command: ", command, " topic: ", topic) 147 panic(err) 148 } 149 }