go-micro.dev/v5@v5.12.0/config/source/nats/nats.go (about)

     1  package nats
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strings"
     7  	"time"
     8  
     9  	natsgo "github.com/nats-io/nats.go"
    10  	"go-micro.dev/v5/config/source"
    11  	log "go-micro.dev/v5/logger"
    12  )
    13  
    14  type nats struct {
    15  	url    string
    16  	bucket string
    17  	key    string
    18  	kv     natsgo.KeyValue
    19  	opts   source.Options
    20  }
    21  
    22  // DefaultBucket is the bucket that nats keys will be assumed to have if you
    23  // haven't specified one.
    24  var (
    25  	DefaultBucket = "default"
    26  	DefaultKey    = "micro_config"
    27  )
    28  
    29  func (n *nats) Read() (*source.ChangeSet, error) {
    30  	e, err := n.kv.Get(n.key)
    31  	if err != nil {
    32  		if err == natsgo.ErrKeyNotFound {
    33  			return nil, nil
    34  		}
    35  		return nil, err
    36  	}
    37  
    38  	if e.Value() == nil || len(e.Value()) == 0 {
    39  		return nil, fmt.Errorf("source not found: %s", n.key)
    40  	}
    41  
    42  	cs := &source.ChangeSet{
    43  		Data:      e.Value(),
    44  		Format:    n.opts.Encoder.String(),
    45  		Source:    n.String(),
    46  		Timestamp: time.Now(),
    47  	}
    48  	cs.Checksum = cs.Sum()
    49  
    50  	return cs, nil
    51  }
    52  
    53  func (n *nats) Write(cs *source.ChangeSet) error {
    54  	_, err := n.kv.Put(n.key, cs.Data)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	return nil
    60  }
    61  
    62  func (n *nats) String() string {
    63  	return "nats"
    64  }
    65  
    66  func (n *nats) Watch() (source.Watcher, error) {
    67  	return newWatcher(n.kv, n.bucket, n.key, n.String(), n.opts.Encoder)
    68  }
    69  
    70  func NewSource(opts ...source.Option) source.Source {
    71  	options := source.NewOptions(opts...)
    72  
    73  	config := natsgo.GetDefaultOptions()
    74  
    75  	urls, ok := options.Context.Value(urlKey{}).([]string)
    76  	endpoints := []string{}
    77  	if ok {
    78  		for _, u := range urls {
    79  			addr, port, err := net.SplitHostPort(u)
    80  			if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
    81  				port = "4222"
    82  				addr = u
    83  				endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port))
    84  			} else if err == nil {
    85  				endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port))
    86  			}
    87  		}
    88  	}
    89  	if len(endpoints) == 0 {
    90  		endpoints = append(endpoints, "127.0.0.1:4222")
    91  	}
    92  
    93  	bucket, ok := options.Context.Value(bucketKey{}).(string)
    94  	if !ok {
    95  		bucket = DefaultBucket
    96  	}
    97  
    98  	key, ok := options.Context.Value(keyKey{}).(string)
    99  	if !ok {
   100  		key = DefaultKey
   101  	}
   102  
   103  	config.Url = strings.Join(endpoints, ",")
   104  
   105  	nc, err := natsgo.Connect(config.Url)
   106  	if err != nil {
   107  		log.Error(err)
   108  	}
   109  
   110  	js, err := nc.JetStream(natsgo.MaxWait(10 * time.Second))
   111  	if err != nil {
   112  		log.Error(err)
   113  	}
   114  
   115  	kv, err := js.KeyValue(bucket)
   116  	if err == natsgo.ErrBucketNotFound || err == natsgo.ErrKeyNotFound {
   117  		kv, err = js.CreateKeyValue(&natsgo.KeyValueConfig{Bucket: bucket})
   118  		if err != nil {
   119  			log.Error(err)
   120  		}
   121  	}
   122  
   123  	if err != nil {
   124  		log.Error(err)
   125  	}
   126  
   127  	return &nats{
   128  		url:    config.Url,
   129  		bucket: bucket,
   130  		key:    key,
   131  		kv:     kv,
   132  		opts:   options,
   133  	}
   134  }