gitee.com/sasukebo/go-micro/v4@v4.7.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  	"gitee.com/sasukebo/go-micro/v4/config/loader"
    13  	"gitee.com/sasukebo/go-micro/v4/config/reader"
    14  	"gitee.com/sasukebo/go-micro/v4/config/reader/json"
    15  	"gitee.com/sasukebo/go-micro/v4/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  	if vals, err := m.opts.Reader.Values(set); err != nil {
   144  		m.vals = vals
   145  	}
   146  	m.snap = &loader.Snapshot{
   147  		ChangeSet: set,
   148  		Version:   genVer(),
   149  	}
   150  
   151  	m.Unlock()
   152  
   153  	// update watchers
   154  	m.update()
   155  
   156  	return nil
   157  }
   158  
   159  func (m *memory) update() {
   160  	watchers := make([]*watcher, 0, m.watchers.Len())
   161  
   162  	m.RLock()
   163  	for e := m.watchers.Front(); e != nil; e = e.Next() {
   164  		watchers = append(watchers, e.Value.(*watcher))
   165  	}
   166  
   167  	vals := m.vals
   168  	snap := m.snap
   169  	m.RUnlock()
   170  
   171  	for _, w := range watchers {
   172  		if w.version >= snap.Version {
   173  			continue
   174  		}
   175  
   176  		uv := updateValue{
   177  			version: m.snap.Version,
   178  			value:   vals.Get(w.path...),
   179  		}
   180  
   181  		select {
   182  		case w.updates <- uv:
   183  		default:
   184  		}
   185  	}
   186  }
   187  
   188  // Snapshot returns a snapshot of the current loaded config
   189  func (m *memory) Snapshot() (*loader.Snapshot, error) {
   190  	if m.loaded() {
   191  		m.RLock()
   192  		snap := loader.Copy(m.snap)
   193  		m.RUnlock()
   194  		return snap, nil
   195  	}
   196  
   197  	// not loaded, sync
   198  	if err := m.Sync(); err != nil {
   199  		return nil, err
   200  	}
   201  
   202  	// make copy
   203  	m.RLock()
   204  	snap := loader.Copy(m.snap)
   205  	m.RUnlock()
   206  
   207  	return snap, nil
   208  }
   209  
   210  // Sync loads all the sources, calls the parser and updates the config
   211  func (m *memory) Sync() error {
   212  	//nolint:prealloc
   213  	var sets []*source.ChangeSet
   214  
   215  	m.Lock()
   216  
   217  	// read the source
   218  	var gerr []string
   219  
   220  	for _, source := range m.sources {
   221  		ch, err := source.Read()
   222  		if err != nil {
   223  			gerr = append(gerr, err.Error())
   224  			continue
   225  		}
   226  		sets = append(sets, ch)
   227  	}
   228  
   229  	// merge sets
   230  	set, err := m.opts.Reader.Merge(sets...)
   231  	if err != nil {
   232  		m.Unlock()
   233  		return err
   234  	}
   235  
   236  	// set values
   237  	vals, err := m.opts.Reader.Values(set)
   238  	if err != nil {
   239  		m.Unlock()
   240  		return err
   241  	}
   242  	m.vals = vals
   243  	m.snap = &loader.Snapshot{
   244  		ChangeSet: set,
   245  		Version:   genVer(),
   246  	}
   247  
   248  	m.Unlock()
   249  
   250  	// update watchers
   251  	m.update()
   252  
   253  	if len(gerr) > 0 {
   254  		return fmt.Errorf("source loading errors: %s", strings.Join(gerr, "\n"))
   255  	}
   256  
   257  	return nil
   258  }
   259  
   260  func (m *memory) Close() error {
   261  	select {
   262  	case <-m.exit:
   263  		return nil
   264  	default:
   265  		close(m.exit)
   266  	}
   267  	return nil
   268  }
   269  
   270  func (m *memory) Get(path ...string) (reader.Value, error) {
   271  	if !m.loaded() {
   272  		if err := m.Sync(); err != nil {
   273  			return nil, err
   274  		}
   275  	}
   276  
   277  	m.Lock()
   278  	defer m.Unlock()
   279  
   280  	// did sync actually work?
   281  	if m.vals != nil {
   282  		return m.vals.Get(path...), nil
   283  	}
   284  
   285  	// assuming vals is nil
   286  	// create new vals
   287  
   288  	ch := m.snap.ChangeSet
   289  
   290  	// we are truly screwed, trying to load in a hacked way
   291  	v, err := m.opts.Reader.Values(ch)
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  
   296  	// lets set it just because
   297  	m.vals = v
   298  
   299  	if m.vals != nil {
   300  		return m.vals.Get(path...), nil
   301  	}
   302  
   303  	// ok we're going hardcore now
   304  
   305  	return nil, errors.New("no values")
   306  }
   307  
   308  func (m *memory) Load(sources ...source.Source) error {
   309  	var gerrors []string
   310  
   311  	for _, source := range sources {
   312  		set, err := source.Read()
   313  		if err != nil {
   314  			gerrors = append(gerrors,
   315  				fmt.Sprintf("error loading source %s: %v",
   316  					source,
   317  					err))
   318  			// continue processing
   319  			continue
   320  		}
   321  		m.Lock()
   322  		m.sources = append(m.sources, source)
   323  		m.sets = append(m.sets, set)
   324  		idx := len(m.sets) - 1
   325  		m.Unlock()
   326  		if !m.opts.WithWatcherDisabled {
   327  			go m.watch(idx, source)
   328  		}
   329  	}
   330  
   331  	if err := m.reload(); err != nil {
   332  		gerrors = append(gerrors, err.Error())
   333  	}
   334  
   335  	// Return errors
   336  	if len(gerrors) != 0 {
   337  		return errors.New(strings.Join(gerrors, "\n"))
   338  	}
   339  	return nil
   340  }
   341  
   342  func (m *memory) Watch(path ...string) (loader.Watcher, error) {
   343  	if m.opts.WithWatcherDisabled {
   344  		return nil, errors.New("watcher is disabled")
   345  	}
   346  
   347  	value, err := m.Get(path...)
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  
   352  	m.Lock()
   353  
   354  	w := &watcher{
   355  		exit:    make(chan bool),
   356  		path:    path,
   357  		value:   value,
   358  		reader:  m.opts.Reader,
   359  		updates: make(chan updateValue, 1),
   360  		version: m.snap.Version,
   361  	}
   362  
   363  	e := m.watchers.PushBack(w)
   364  
   365  	m.Unlock()
   366  
   367  	go func() {
   368  		<-w.exit
   369  		m.Lock()
   370  		m.watchers.Remove(e)
   371  		m.Unlock()
   372  	}()
   373  
   374  	return w, nil
   375  }
   376  
   377  func (m *memory) String() string {
   378  	return "memory"
   379  }
   380  
   381  func (w *watcher) Next() (*loader.Snapshot, error) {
   382  	update := func(v reader.Value) *loader.Snapshot {
   383  		w.value = v
   384  
   385  		cs := &source.ChangeSet{
   386  			Data:      v.Bytes(),
   387  			Format:    w.reader.String(),
   388  			Source:    "memory",
   389  			Timestamp: time.Now(),
   390  		}
   391  		cs.Checksum = cs.Sum()
   392  
   393  		return &loader.Snapshot{
   394  			ChangeSet: cs,
   395  			Version:   w.version,
   396  		}
   397  
   398  	}
   399  
   400  	for {
   401  		select {
   402  		case <-w.exit:
   403  			return nil, errors.New("watcher stopped")
   404  
   405  		case uv := <-w.updates:
   406  			if uv.version <= w.version {
   407  				continue
   408  			}
   409  
   410  			v := uv.value
   411  
   412  			w.version = uv.version
   413  
   414  			if bytes.Equal(w.value.Bytes(), v.Bytes()) {
   415  				continue
   416  			}
   417  
   418  			return update(v), nil
   419  		}
   420  	}
   421  }
   422  
   423  func (w *watcher) Stop() error {
   424  	select {
   425  	case <-w.exit:
   426  	default:
   427  		close(w.exit)
   428  		close(w.updates)
   429  	}
   430  
   431  	return nil
   432  }
   433  
   434  func genVer() string {
   435  	return fmt.Sprintf("%d", time.Now().UnixNano())
   436  }
   437  
   438  func NewLoader(opts ...loader.Option) loader.Loader {
   439  	options := loader.Options{
   440  		Reader: json.NewReader(),
   441  	}
   442  
   443  	for _, o := range opts {
   444  		o(&options)
   445  	}
   446  
   447  	m := &memory{
   448  		exit:     make(chan bool),
   449  		opts:     options,
   450  		watchers: list.New(),
   451  		sources:  options.Source,
   452  	}
   453  
   454  	m.sets = make([]*source.ChangeSet, len(options.Source))
   455  
   456  	for i, s := range options.Source {
   457  		m.sets[i] = &source.ChangeSet{Source: s.String()}
   458  		if !options.WithWatcherDisabled {
   459  			go m.watch(i, s)
   460  		}
   461  	}
   462  
   463  	return m
   464  }