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  }