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

     1  package memory
     2  
     3  import (
     4  	"bytes"
     5  	"container/list"
     6  	"errors"
     7  	"fmt"
     8  	"strings"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/micro/go-micro/v2/config/loader"
    13  	"github.com/micro/go-micro/v2/config/reader"
    14  	"github.com/micro/go-micro/v2/config/reader/json"
    15  	"github.com/micro/go-micro/v2/config/source"
    16  )
    17  
    18  type memory struct {
    19  	exit chan bool
    20  	opts loader.Options
    21  
    22  	sync.RWMutex
    23  	// the current snapshot
    24  	snap *loader.Snapshot
    25  	// the current values
    26  	vals reader.Values
    27  	// all the sets
    28  	sets []*source.ChangeSet
    29  	// all the sources
    30  	sources []source.Source
    31  
    32  	watchers *list.List
    33  }
    34  
    35  type updateValue struct {
    36  	version string
    37  	value   reader.Value
    38  }
    39  
    40  type watcher struct {
    41  	exit    chan bool
    42  	path    []string
    43  	value   reader.Value
    44  	reader  reader.Reader
    45  	version string
    46  	updates chan updateValue
    47  }
    48  
    49  func (m *memory) watch(idx int, s source.Source) {
    50  	// watches a source for changes
    51  	watch := func(idx int, s source.Watcher) error {
    52  		for {
    53  			// get changeset
    54  			cs, err := s.Next()
    55  			if err != nil {
    56  				return err
    57  			}
    58  
    59  			m.Lock()
    60  
    61  			// save
    62  			m.sets[idx] = cs
    63  
    64  			// merge sets
    65  			set, err := m.opts.Reader.Merge(m.sets...)
    66  			if err != nil {
    67  				m.Unlock()
    68  				return err
    69  			}
    70  
    71  			// set values
    72  			m.vals, _ = m.opts.Reader.Values(set)
    73  			m.snap = &loader.Snapshot{
    74  				ChangeSet: set,
    75  				Version:   genVer(),
    76  			}
    77  			m.Unlock()
    78  
    79  			// send watch updates
    80  			m.update()
    81  		}
    82  	}
    83  
    84  	for {
    85  		// watch the source
    86  		w, err := s.Watch()
    87  		if err != nil {
    88  			time.Sleep(time.Second)
    89  			continue
    90  		}
    91  
    92  		done := make(chan bool)
    93  
    94  		// the stop watch func
    95  		go func() {
    96  			select {
    97  			case <-done:
    98  			case <-m.exit:
    99  			}
   100  			w.Stop()
   101  		}()
   102  
   103  		// block watch
   104  		if err := watch(idx, w); err != nil {
   105  			// do something better
   106  			time.Sleep(time.Second)
   107  		}
   108  
   109  		// close done chan
   110  		close(done)
   111  
   112  		// if the config is closed exit
   113  		select {
   114  		case <-m.exit:
   115  			return
   116  		default:
   117  		}
   118  	}
   119  }
   120  
   121  func (m *memory) loaded() bool {
   122  	var loaded bool
   123  	m.RLock()
   124  	if m.vals != nil {
   125  		loaded = true
   126  	}
   127  	m.RUnlock()
   128  	return loaded
   129  }
   130  
   131  // reload reads the sets and creates new values
   132  func (m *memory) reload() error {
   133  	m.Lock()
   134  
   135  	// merge sets
   136  	set, err := m.opts.Reader.Merge(m.sets...)
   137  	if err != nil {
   138  		m.Unlock()
   139  		return err
   140  	}
   141  
   142  	// set values
   143  	m.vals, _ = m.opts.Reader.Values(set)
   144  	m.snap = &loader.Snapshot{
   145  		ChangeSet: set,
   146  		Version:   genVer(),
   147  	}
   148  
   149  	m.Unlock()
   150  
   151  	// update watchers
   152  	m.update()
   153  
   154  	return nil
   155  }
   156  
   157  func (m *memory) update() {
   158  	watchers := make([]*watcher, 0, m.watchers.Len())
   159  
   160  	m.RLock()
   161  	for e := m.watchers.Front(); e != nil; e = e.Next() {
   162  		watchers = append(watchers, e.Value.(*watcher))
   163  	}
   164  
   165  	vals := m.vals
   166  	snap := m.snap
   167  	m.RUnlock()
   168  
   169  	for _, w := range watchers {
   170  		if w.version >= snap.Version {
   171  			continue
   172  		}
   173  
   174  		uv := updateValue{
   175  			version: m.snap.Version,
   176  			value:   vals.Get(w.path...),
   177  		}
   178  
   179  		select {
   180  		case w.updates <- uv:
   181  		default:
   182  		}
   183  	}
   184  }
   185  
   186  // Snapshot returns a snapshot of the current loaded config
   187  func (m *memory) Snapshot() (*loader.Snapshot, error) {
   188  	if m.loaded() {
   189  		m.RLock()
   190  		snap := loader.Copy(m.snap)
   191  		m.RUnlock()
   192  		return snap, nil
   193  	}
   194  
   195  	// not loaded, sync
   196  	if err := m.Sync(); err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	// make copy
   201  	m.RLock()
   202  	snap := loader.Copy(m.snap)
   203  	m.RUnlock()
   204  
   205  	return snap, nil
   206  }
   207  
   208  // Sync loads all the sources, calls the parser and updates the config
   209  func (m *memory) Sync() error {
   210  	//nolint:prealloc
   211  	var sets []*source.ChangeSet
   212  
   213  	m.Lock()
   214  
   215  	// read the source
   216  	var gerr []string
   217  
   218  	for _, source := range m.sources {
   219  		ch, err := source.Read()
   220  		if err != nil {
   221  			gerr = append(gerr, err.Error())
   222  			continue
   223  		}
   224  		sets = append(sets, ch)
   225  	}
   226  
   227  	// merge sets
   228  	set, err := m.opts.Reader.Merge(sets...)
   229  	if err != nil {
   230  		m.Unlock()
   231  		return err
   232  	}
   233  
   234  	// set values
   235  	vals, err := m.opts.Reader.Values(set)
   236  	if err != nil {
   237  		m.Unlock()
   238  		return err
   239  	}
   240  	m.vals = vals
   241  	m.snap = &loader.Snapshot{
   242  		ChangeSet: set,
   243  		Version:   genVer(),
   244  	}
   245  
   246  	m.Unlock()
   247  
   248  	// update watchers
   249  	m.update()
   250  
   251  	if len(gerr) > 0 {
   252  		return fmt.Errorf("source loading errors: %s", strings.Join(gerr, "\n"))
   253  	}
   254  
   255  	return nil
   256  }
   257  
   258  func (m *memory) Close() error {
   259  	select {
   260  	case <-m.exit:
   261  		return nil
   262  	default:
   263  		close(m.exit)
   264  	}
   265  	return nil
   266  }
   267  
   268  func (m *memory) Get(path ...string) (reader.Value, error) {
   269  	if !m.loaded() {
   270  		if err := m.Sync(); err != nil {
   271  			return nil, err
   272  		}
   273  	}
   274  
   275  	m.Lock()
   276  	defer m.Unlock()
   277  
   278  	// did sync actually work?
   279  	if m.vals != nil {
   280  		return m.vals.Get(path...), nil
   281  	}
   282  
   283  	// assuming vals is nil
   284  	// create new vals
   285  
   286  	ch := m.snap.ChangeSet
   287  
   288  	// we are truly screwed, trying to load in a hacked way
   289  	v, err := m.opts.Reader.Values(ch)
   290  	if err != nil {
   291  		return nil, err
   292  	}
   293  
   294  	// lets set it just because
   295  	m.vals = v
   296  
   297  	if m.vals != nil {
   298  		return m.vals.Get(path...), nil
   299  	}
   300  
   301  	// ok we're going hardcore now
   302  
   303  	return nil, errors.New("no values")
   304  }
   305  
   306  func (m *memory) Load(sources ...source.Source) error {
   307  	var gerrors []string
   308  
   309  	for _, source := range sources {
   310  		set, err := source.Read()
   311  		if err != nil {
   312  			gerrors = append(gerrors,
   313  				fmt.Sprintf("error loading source %s: %v",
   314  					source,
   315  					err))
   316  			// continue processing
   317  			continue
   318  		}
   319  		m.Lock()
   320  		m.sources = append(m.sources, source)
   321  		m.sets = append(m.sets, set)
   322  		idx := len(m.sets) - 1
   323  		m.Unlock()
   324  		go m.watch(idx, source)
   325  	}
   326  
   327  	if err := m.reload(); err != nil {
   328  		gerrors = append(gerrors, err.Error())
   329  	}
   330  
   331  	// Return errors
   332  	if len(gerrors) != 0 {
   333  		return errors.New(strings.Join(gerrors, "\n"))
   334  	}
   335  	return nil
   336  }
   337  
   338  func (m *memory) Watch(path ...string) (loader.Watcher, error) {
   339  	value, err := m.Get(path...)
   340  	if err != nil {
   341  		return nil, err
   342  	}
   343  
   344  	m.Lock()
   345  
   346  	w := &watcher{
   347  		exit:    make(chan bool),
   348  		path:    path,
   349  		value:   value,
   350  		reader:  m.opts.Reader,
   351  		updates: make(chan updateValue, 1),
   352  		version: m.snap.Version,
   353  	}
   354  
   355  	e := m.watchers.PushBack(w)
   356  
   357  	m.Unlock()
   358  
   359  	go func() {
   360  		<-w.exit
   361  		m.Lock()
   362  		m.watchers.Remove(e)
   363  		m.Unlock()
   364  	}()
   365  
   366  	return w, nil
   367  }
   368  
   369  func (m *memory) String() string {
   370  	return "memory"
   371  }
   372  
   373  func (w *watcher) Next() (*loader.Snapshot, error) {
   374  	update := func(v reader.Value) *loader.Snapshot {
   375  		w.value = v
   376  
   377  		cs := &source.ChangeSet{
   378  			Data:      v.Bytes(),
   379  			Format:    w.reader.String(),
   380  			Source:    "memory",
   381  			Timestamp: time.Now(),
   382  		}
   383  		cs.Checksum = cs.Sum()
   384  
   385  		return &loader.Snapshot{
   386  			ChangeSet: cs,
   387  			Version:   w.version,
   388  		}
   389  
   390  	}
   391  
   392  	for {
   393  		select {
   394  		case <-w.exit:
   395  			return nil, errors.New("watcher stopped")
   396  
   397  		case uv := <-w.updates:
   398  			if uv.version <= w.version {
   399  				continue
   400  			}
   401  
   402  			v := uv.value
   403  
   404  			w.version = uv.version
   405  
   406  			if bytes.Equal(w.value.Bytes(), v.Bytes()) {
   407  				continue
   408  			}
   409  
   410  			return update(v), nil
   411  		}
   412  	}
   413  }
   414  
   415  func (w *watcher) Stop() error {
   416  	select {
   417  	case <-w.exit:
   418  	default:
   419  		close(w.exit)
   420  		close(w.updates)
   421  	}
   422  
   423  	return nil
   424  }
   425  
   426  func genVer() string {
   427  	return fmt.Sprintf("%d", time.Now().UnixNano())
   428  }
   429  
   430  func NewLoader(opts ...loader.Option) loader.Loader {
   431  	options := loader.Options{
   432  		Reader: json.NewReader(),
   433  	}
   434  
   435  	for _, o := range opts {
   436  		o(&options)
   437  	}
   438  
   439  	m := &memory{
   440  		exit:     make(chan bool),
   441  		opts:     options,
   442  		watchers: list.New(),
   443  		sources:  options.Source,
   444  	}
   445  
   446  	m.sets = make([]*source.ChangeSet, len(options.Source))
   447  
   448  	for i, s := range options.Source {
   449  		m.sets[i] = &source.ChangeSet{Source: s.String()}
   450  		go m.watch(i, s)
   451  	}
   452  
   453  	return m
   454  }