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