gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/config.v2/context.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"gitee.com/sy_183/go-common/container"
     6  	"gitee.com/sy_183/go-common/lock"
     7  	"gitee.com/sy_183/go-common/option"
     8  	"sync"
     9  	"sync/atomic"
    10  )
    11  
    12  type Option[C any] option.CustomOption[*Context[C]]
    13  
    14  var ErrLoaderNotFound = errors.New("loader not found")
    15  
    16  type (
    17  	OnConfigReloaded[C any]    func(oc, nc *C)
    18  	ConfigReloadChecker[C any] func(oc, nc *C) error
    19  )
    20  
    21  type Context[C any] struct {
    22  	loader    Loader
    23  	newConfig func() *C
    24  	config    atomic.Pointer[C]
    25  
    26  	configReloadedCallbackId      atomic.Uint64
    27  	configReloadedCallbacks       *container.LinkedMap[uint64, OnConfigReloaded[C]]
    28  	configReloadedCallbacksLocker sync.Mutex
    29  
    30  	configReloadCheckerId      atomic.Uint64
    31  	configReloadCheckers       *container.LinkedMap[uint64, ConfigReloadChecker[C]]
    32  	configReloadCheckersLocker sync.Mutex
    33  }
    34  
    35  func NewContext[C any](loader Loader, newConfig func() *C, options ...Option[C]) *Context[C] {
    36  	ctx := &Context[C]{
    37  		loader:    loader,
    38  		newConfig: newConfig,
    39  
    40  		configReloadedCallbacks: container.NewLinkedMap[uint64, OnConfigReloaded[C]](0, 0),
    41  		configReloadCheckers:    container.NewLinkedMap[uint64, ConfigReloadChecker[C]](0, 0),
    42  	}
    43  	for _, opt := range options {
    44  		opt.Apply(ctx)
    45  	}
    46  	return ctx
    47  }
    48  
    49  func (c *Context[C]) Loader() Loader {
    50  	return c.loader
    51  }
    52  
    53  func (c *Context[C]) SetLoader(loader Loader) {
    54  	c.loader = loader
    55  }
    56  
    57  func (c *Context[C]) NewConfig() *C {
    58  	return c.newConfig()
    59  }
    60  
    61  func (c *Context[C]) RegisterConfigReloadedCallback(callback OnConfigReloaded[C]) uint64 {
    62  	return lock.LockGet(&c.configReloadedCallbacksLocker, func() uint64 {
    63  		id := c.configReloadedCallbackId.Add(1)
    64  		c.configReloadedCallbacks.LoadOrStore(id, callback)
    65  		return id
    66  	})
    67  }
    68  
    69  func (c *Context[C]) UnregisterConfigReloadedCallback(id uint64) {
    70  	lock.LockDo(&c.configReloadedCallbacksLocker, func() {
    71  		c.configReloadedCallbacks.Remove(id)
    72  	})
    73  }
    74  
    75  func (c *Context[C]) RegisterConfigReloadChecker(checker ConfigReloadChecker[C]) uint64 {
    76  	return lock.LockGet(&c.configReloadCheckersLocker, func() uint64 {
    77  		id := c.configReloadCheckerId.Add(1)
    78  		c.configReloadCheckers.LoadOrStore(id, checker)
    79  		return id
    80  	})
    81  }
    82  
    83  func (c *Context[C]) UnregisterConfigReloadChecker(id uint64) {
    84  	lock.LockDo(&c.configReloadCheckersLocker, func() {
    85  		c.configReloadCheckers.Remove(id)
    86  	})
    87  }
    88  
    89  func (c *Context[C]) configReloaded(oc, nc *C) {
    90  	lock.LockDo(&c.configReloadedCallbacksLocker, func() {
    91  		for entry := c.configReloadedCallbacks.HeadEntry(); entry != nil; entry = entry.Next() {
    92  			entry.Value()(oc, nc)
    93  		}
    94  	})
    95  }
    96  
    97  func (c *Context[C]) configReloadCheck(oc, nc *C) error {
    98  	return lock.LockGet(&c.configReloadCheckersLocker, func() error {
    99  		for entry := c.configReloadCheckers.HeadEntry(); entry != nil; entry = entry.Next() {
   100  			if err := entry.Value()(oc, nc); err != nil {
   101  				return err
   102  			}
   103  		}
   104  		return nil
   105  	})
   106  }
   107  
   108  func (c *Context[C]) Config() *C {
   109  	return c.config.Load()
   110  }
   111  
   112  func (c *Context[C]) InitConfig() error {
   113  	return c.ReloadConfig()
   114  }
   115  
   116  func (c *Context[C]) ReloadConfig() error {
   117  	if c.loader == nil {
   118  		return ErrLoaderNotFound
   119  	}
   120  	oc := c.Config()
   121  	var nc *C
   122  	if c.newConfig == nil {
   123  		nc = new(C)
   124  	} else {
   125  		nc = c.newConfig()
   126  	}
   127  	node, err := c.loader.Load()
   128  	if err != nil {
   129  		return err
   130  	}
   131  	if node != nil {
   132  		if err = node.Decode(nc); err != nil {
   133  			return err
   134  		}
   135  	}
   136  	if err = c.configReloadCheck(oc, nc); err != nil {
   137  		return err
   138  	}
   139  	if err = PostHandle(nc); err != nil {
   140  		return err
   141  	}
   142  	c.config.Store(nc)
   143  	c.configReloaded(oc, nc)
   144  	return nil
   145  }