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 }