github.com/micro/go-micro/v2@v2.9.1/config/default.go (about)

     1  package config
     2  
     3  import (
     4  	"bytes"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/micro/go-micro/v2/config/loader"
     9  	"github.com/micro/go-micro/v2/config/loader/memory"
    10  	"github.com/micro/go-micro/v2/config/reader"
    11  	"github.com/micro/go-micro/v2/config/reader/json"
    12  	"github.com/micro/go-micro/v2/config/source"
    13  )
    14  
    15  type config struct {
    16  	exit chan bool
    17  	opts Options
    18  
    19  	sync.RWMutex
    20  	// the current snapshot
    21  	snap *loader.Snapshot
    22  	// the current values
    23  	vals reader.Values
    24  }
    25  
    26  type watcher struct {
    27  	lw    loader.Watcher
    28  	rd    reader.Reader
    29  	path  []string
    30  	value reader.Value
    31  }
    32  
    33  func newConfig(opts ...Option) (Config, error) {
    34  	var c config
    35  
    36  	c.Init(opts...)
    37  	go c.run()
    38  
    39  	return &c, nil
    40  }
    41  
    42  func (c *config) Init(opts ...Option) error {
    43  	c.opts = Options{
    44  		Reader: json.NewReader(),
    45  	}
    46  	c.exit = make(chan bool)
    47  	for _, o := range opts {
    48  		o(&c.opts)
    49  	}
    50  
    51  	// default loader uses the configured reader
    52  	if c.opts.Loader == nil {
    53  		c.opts.Loader = memory.NewLoader(memory.WithReader(c.opts.Reader))
    54  	}
    55  
    56  	err := c.opts.Loader.Load(c.opts.Source...)
    57  	if err != nil {
    58  		return err
    59  	}
    60  
    61  	c.snap, err = c.opts.Loader.Snapshot()
    62  	if err != nil {
    63  		return err
    64  	}
    65  
    66  	c.vals, err = c.opts.Reader.Values(c.snap.ChangeSet)
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	return nil
    72  }
    73  
    74  func (c *config) Options() Options {
    75  	return c.opts
    76  }
    77  
    78  func (c *config) run() {
    79  	watch := func(w loader.Watcher) error {
    80  		for {
    81  			// get changeset
    82  			snap, err := w.Next()
    83  			if err != nil {
    84  				return err
    85  			}
    86  
    87  			c.Lock()
    88  
    89  			if c.snap.Version >= snap.Version {
    90  				c.Unlock()
    91  				continue
    92  			}
    93  
    94  			// save
    95  			c.snap = snap
    96  
    97  			// set values
    98  			c.vals, _ = c.opts.Reader.Values(snap.ChangeSet)
    99  
   100  			c.Unlock()
   101  		}
   102  	}
   103  
   104  	for {
   105  		w, err := c.opts.Loader.Watch()
   106  		if err != nil {
   107  			time.Sleep(time.Second)
   108  			continue
   109  		}
   110  
   111  		done := make(chan bool)
   112  
   113  		// the stop watch func
   114  		go func() {
   115  			select {
   116  			case <-done:
   117  			case <-c.exit:
   118  			}
   119  			w.Stop()
   120  		}()
   121  
   122  		// block watch
   123  		if err := watch(w); err != nil {
   124  			// do something better
   125  			time.Sleep(time.Second)
   126  		}
   127  
   128  		// close done chan
   129  		close(done)
   130  
   131  		// if the config is closed exit
   132  		select {
   133  		case <-c.exit:
   134  			return
   135  		default:
   136  		}
   137  	}
   138  }
   139  
   140  func (c *config) Map() map[string]interface{} {
   141  	c.RLock()
   142  	defer c.RUnlock()
   143  	return c.vals.Map()
   144  }
   145  
   146  func (c *config) Scan(v interface{}) error {
   147  	c.RLock()
   148  	defer c.RUnlock()
   149  	return c.vals.Scan(v)
   150  }
   151  
   152  // sync loads all the sources, calls the parser and updates the config
   153  func (c *config) Sync() error {
   154  	if err := c.opts.Loader.Sync(); err != nil {
   155  		return err
   156  	}
   157  
   158  	snap, err := c.opts.Loader.Snapshot()
   159  	if err != nil {
   160  		return err
   161  	}
   162  
   163  	c.Lock()
   164  	defer c.Unlock()
   165  
   166  	c.snap = snap
   167  	vals, err := c.opts.Reader.Values(snap.ChangeSet)
   168  	if err != nil {
   169  		return err
   170  	}
   171  	c.vals = vals
   172  
   173  	return nil
   174  }
   175  
   176  func (c *config) Close() error {
   177  	select {
   178  	case <-c.exit:
   179  		return nil
   180  	default:
   181  		close(c.exit)
   182  	}
   183  	return nil
   184  }
   185  
   186  func (c *config) Get(path ...string) reader.Value {
   187  	c.RLock()
   188  	defer c.RUnlock()
   189  
   190  	// did sync actually work?
   191  	if c.vals != nil {
   192  		return c.vals.Get(path...)
   193  	}
   194  
   195  	// no value
   196  	return newValue()
   197  }
   198  
   199  func (c *config) Set(val interface{}, path ...string) {
   200  	c.Lock()
   201  	defer c.Unlock()
   202  
   203  	if c.vals != nil {
   204  		c.vals.Set(val, path...)
   205  	}
   206  
   207  	return
   208  }
   209  
   210  func (c *config) Del(path ...string) {
   211  	c.Lock()
   212  	defer c.Unlock()
   213  
   214  	if c.vals != nil {
   215  		c.vals.Del(path...)
   216  	}
   217  
   218  	return
   219  }
   220  
   221  func (c *config) Bytes() []byte {
   222  	c.RLock()
   223  	defer c.RUnlock()
   224  
   225  	if c.vals == nil {
   226  		return []byte{}
   227  	}
   228  
   229  	return c.vals.Bytes()
   230  }
   231  
   232  func (c *config) Load(sources ...source.Source) error {
   233  	if err := c.opts.Loader.Load(sources...); err != nil {
   234  		return err
   235  	}
   236  
   237  	snap, err := c.opts.Loader.Snapshot()
   238  	if err != nil {
   239  		return err
   240  	}
   241  
   242  	c.Lock()
   243  	defer c.Unlock()
   244  
   245  	c.snap = snap
   246  	vals, err := c.opts.Reader.Values(snap.ChangeSet)
   247  	if err != nil {
   248  		return err
   249  	}
   250  	c.vals = vals
   251  
   252  	return nil
   253  }
   254  
   255  func (c *config) Watch(path ...string) (Watcher, error) {
   256  	value := c.Get(path...)
   257  
   258  	w, err := c.opts.Loader.Watch(path...)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  
   263  	return &watcher{
   264  		lw:    w,
   265  		rd:    c.opts.Reader,
   266  		path:  path,
   267  		value: value,
   268  	}, nil
   269  }
   270  
   271  func (c *config) String() string {
   272  	return "config"
   273  }
   274  
   275  func (w *watcher) Next() (reader.Value, error) {
   276  	for {
   277  		s, err := w.lw.Next()
   278  		if err != nil {
   279  			return nil, err
   280  		}
   281  
   282  		// only process changes
   283  		if bytes.Equal(w.value.Bytes(), s.ChangeSet.Data) {
   284  			continue
   285  		}
   286  
   287  		v, err := w.rd.Values(s.ChangeSet)
   288  		if err != nil {
   289  			return nil, err
   290  		}
   291  
   292  		w.value = v.Get()
   293  		return w.value, nil
   294  	}
   295  }
   296  
   297  func (w *watcher) Stop() error {
   298  	return w.lw.Stop()
   299  }