github.com/moleculer-go/moleculer@v0.3.3/transit/nats/nats.go (about) 1 package nats 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 "time" 8 9 "github.com/moleculer-go/moleculer" 10 "github.com/moleculer-go/moleculer/serializer" 11 "github.com/moleculer-go/moleculer/transit" 12 "github.com/nats-io/go-nats" 13 log "github.com/sirupsen/logrus" 14 ) 15 16 type NatsTransporter struct { 17 prefix string 18 opts *nats.Options 19 conn *nats.Conn 20 logger *log.Entry 21 serializer serializer.Serializer 22 subscriptions []*nats.Subscription 23 } 24 25 type NATSOptions struct { 26 URL string 27 Name string 28 Logger *log.Entry 29 Serializer serializer.Serializer 30 ValidateMsg transit.ValidateMsgFunc 31 32 AllowReconnect bool 33 ReconnectWait time.Duration 34 MaxReconnect int 35 } 36 37 func natsOptions(options NATSOptions) *nats.Options { 38 opts := nats.GetDefaultOptions() 39 opts.Name = options.Name 40 opts.Url = options.URL 41 opts.AllowReconnect = options.AllowReconnect 42 if options.ReconnectWait != 0 { 43 opts.ReconnectWait = options.ReconnectWait 44 } 45 if options.MaxReconnect != 0 { 46 opts.MaxReconnect = options.MaxReconnect 47 } 48 return &opts 49 } 50 51 func CreateNatsTransporter(options NATSOptions) transit.Transport { 52 return &NatsTransporter{ 53 opts: natsOptions(options), 54 logger: options.Logger, 55 serializer: options.Serializer, 56 subscriptions: []*nats.Subscription{}, 57 } 58 } 59 60 func (t *NatsTransporter) Connect() chan error { 61 endChan := make(chan error) 62 go func() { 63 t.logger.Debug("NATS Connect() - url: ", t.opts.Url, " Name: ", t.opts.Name) 64 conn, err := t.opts.Connect() 65 if err != nil { 66 t.logger.Error("NATS Connect() - Error: ", err, " url: ", t.opts.Url, " Name: ", t.opts.Name) 67 endChan <- errors.New(fmt.Sprint("Error connection to NATS. error: ", err, " url: ", t.opts.Url)) 68 return 69 } 70 71 t.logger.Info("Connected to ", t.opts.Url) 72 t.conn = conn 73 endChan <- nil 74 }() 75 return endChan 76 } 77 78 func (t *NatsTransporter) Disconnect() chan error { 79 endChan := make(chan error) 80 go func() { 81 if t.conn == nil { 82 endChan <- nil 83 return 84 } 85 for _, sub := range t.subscriptions { 86 if err := sub.Unsubscribe(); err != nil { 87 t.logger.Error(err) 88 } 89 } 90 t.conn.Close() 91 t.conn = nil 92 endChan <- nil 93 }() 94 return endChan 95 } 96 97 func (t *NatsTransporter) topicName(command string, nodeID string) string { 98 parts := []string{t.prefix, command} 99 if nodeID != "" { 100 parts = append(parts, nodeID) 101 } 102 return strings.Join(parts, ".") 103 } 104 105 func (t *NatsTransporter) Subscribe(command, nodeID string, handler transit.TransportHandler) { 106 if t.conn == nil { 107 msg := fmt.Sprint("nats.Subscribe() No connection :( -> command: ", command, " nodeID: ", nodeID) 108 t.logger.Warn(msg) 109 panic(errors.New(msg)) 110 } 111 112 topic := t.topicName(command, nodeID) 113 114 sub, err := t.conn.Subscribe(topic, func(msg *nats.Msg) { 115 payload := t.serializer.BytesToPayload(&msg.Data) 116 t.logger.Debug(fmt.Sprintf("Incoming %s packet from '%s'", topic, payload.Get("sender").String())) 117 handler(payload) 118 }) 119 if err != nil { 120 t.logger.Error("Cannot subscribe: ", topic, " error: ", err) 121 return 122 } 123 t.subscriptions = append(t.subscriptions, sub) 124 } 125 126 func (t *NatsTransporter) Publish(command, nodeID string, message moleculer.Payload) { 127 if t.conn == nil { 128 msg := fmt.Sprint("nats.Publish() No connection :( -> command: ", command, " nodeID: ", nodeID) 129 t.logger.Warn(msg) 130 panic(errors.New(msg)) 131 } 132 133 topic := t.topicName(command, nodeID) 134 t.logger.Debug("nats.Publish() command: ", command, " topic: ", topic, " nodeID: ", nodeID) 135 t.logger.Trace("message: \n", message, "\n - end") 136 err := t.conn.Publish(topic, t.serializer.PayloadToBytes(message)) 137 if err != nil { 138 t.logger.Error("Error on publish: error: ", err, " command: ", command, " topic: ", topic) 139 panic(err) 140 } 141 } 142 143 func (t *NatsTransporter) SetPrefix(prefix string) { 144 t.prefix = prefix 145 } 146 147 func (t *NatsTransporter) SetNodeID(nodeID string) { 148 } 149 150 func (t *NatsTransporter) SetSerializer(serializer serializer.Serializer) { 151 // Ignored while transporter initialized in pubsub function 152 }