gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/config/context.go (about) 1 package config 2 3 import ( 4 "gitee.com/sy_183/go-common/container" 5 "gitee.com/sy_183/go-common/lock" 6 "gitee.com/sy_183/go-common/log" 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 func ErrorCallback[C any](callback func(err *Error)) Option[C] { 15 return option.Custom[*Context[C]](func(ctx *Context[C]) { 16 ctx.errorCallback = callback 17 }) 18 } 19 20 func LoggerErrorCallback(logger *log.Logger) func(err *Error) { 21 return func(err *Error) { 22 switch err.Type { 23 case ParseError: 24 logger.Fatal("加载配置失败", log.Error(err)) 25 case CheckError: 26 logger.Fatal("检查配置失败", log.Error(err)) 27 case ReloadParseError: 28 logger.ErrorWith("重新加载配置失败", err) 29 case ReloadCheckError: 30 logger.ErrorWith("重新加载配置检查失败", err) 31 } 32 } 33 } 34 35 func AddBytes[C any](bs []byte, typ Type) Option[C] { 36 return option.Custom[*Context[C]](func(ctx *Context[C]) { 37 ctx.AddBytes(bs, typ) 38 }) 39 } 40 41 func SetBytes[C any](bs []byte, typ Type) Option[C] { 42 return option.Custom[*Context[C]](func(ctx *Context[C]) { 43 ctx.SetBytes(bs, typ) 44 }) 45 } 46 47 func AddFile[C any](path string, typ *Type) Option[C] { 48 return option.Custom[*Context[C]](func(ctx *Context[C]) { 49 ctx.AddFile(path, typ) 50 }) 51 } 52 53 func SetFile[C any](path string, typ *Type) Option[C] { 54 return option.Custom[*Context[C]](func(ctx *Context[C]) { 55 ctx.SetFile(path, typ) 56 }) 57 } 58 59 func AddFilePrefix[C any](prefix string, types ...Type) Option[C] { 60 return option.Custom[*Context[C]](func(ctx *Context[C]) { 61 ctx.AddFilePrefix(prefix, types...) 62 }) 63 } 64 65 func SetFilePrefix[C any](prefix string, types ...Type) Option[C] { 66 return option.Custom[*Context[C]](func(ctx *Context[C]) { 67 ctx.SetFilePrefix(prefix, types...) 68 }) 69 } 70 71 type ( 72 OnConfigReloaded[C any] func(oc, nc *C) 73 ConfigReloadChecker[C any] func(oc, nc *C) error 74 ) 75 76 type Context[C any] struct { 77 Parser 78 79 newConfig func() *C 80 config atomic.Pointer[C] 81 initializer sync.Once 82 83 errorCallback func(err *Error) 84 85 configReloadedCallbackId atomic.Uint64 86 configReloadCheckerId atomic.Uint64 87 88 configReloadedCallbacks *container.LinkedMap[uint64, OnConfigReloaded[C]] 89 configReloadedCallbacksLocker sync.Mutex 90 configReloadCheckers *container.LinkedMap[uint64, ConfigReloadChecker[C]] 91 configReloadCheckersLocker sync.Mutex 92 } 93 94 func NewContext[C any](newConfig func() *C, options ...Option[C]) *Context[C] { 95 ctx := &Context[C]{ 96 newConfig: newConfig, 97 configReloadedCallbacks: container.NewLinkedMap[uint64, OnConfigReloaded[C]](0, 0), 98 configReloadCheckers: container.NewLinkedMap[uint64, ConfigReloadChecker[C]](0, 0), 99 } 100 for _, opt := range options { 101 opt.Apply(ctx) 102 } 103 return ctx 104 } 105 106 func (c *Context[C]) RegisterConfigReloadedCallback(callback OnConfigReloaded[C]) uint64 { 107 return lock.LockGet(&c.configReloadedCallbacksLocker, func() uint64 { 108 id := c.configReloadedCallbackId.Add(1) 109 c.configReloadedCallbacks.LoadOrStore(id, callback) 110 return id 111 }) 112 } 113 114 func (c *Context[C]) UnregisterConfigReloadedCallback(id uint64) { 115 lock.LockDo(&c.configReloadedCallbacksLocker, func() { 116 c.configReloadedCallbacks.Remove(id) 117 }) 118 } 119 120 func (c *Context[C]) RegisterConfigReloadChecker(checker ConfigReloadChecker[C]) uint64 { 121 return lock.LockGet(&c.configReloadCheckersLocker, func() uint64 { 122 id := c.configReloadCheckerId.Add(1) 123 c.configReloadCheckers.LoadOrStore(id, checker) 124 return id 125 }) 126 } 127 128 func (c *Context[C]) UnregisterConfigReloadChecker(id uint64) { 129 lock.LockDo(&c.configReloadCheckersLocker, func() { 130 c.configReloadCheckers.Remove(id) 131 }) 132 } 133 134 func (c *Context[C]) configReloaded(oc, nc *C) { 135 lock.LockDo(&c.configReloadedCallbacksLocker, func() { 136 for entry := c.configReloadedCallbacks.HeadEntry(); entry != nil; entry = entry.Next() { 137 entry.Value()(oc, nc) 138 } 139 }) 140 } 141 142 func (c *Context[C]) configReloadCheck(oc, nc *C) error { 143 return lock.LockGet(&c.configReloadCheckersLocker, func() error { 144 for entry := c.configReloadCheckers.HeadEntry(); entry != nil; entry = entry.Next() { 145 if err := entry.Value()(oc, nc); err != nil { 146 return err 147 } 148 } 149 return nil 150 }) 151 } 152 153 func (c *Context[C]) Config() *C { 154 return c.config.Load() 155 } 156 157 func (c *Context[C]) InitConfig() error { 158 return c.ReloadConfig() 159 } 160 161 func (c *Context[C]) ReloadConfig() error { 162 oc := c.Config() 163 var nc *C 164 if c.newConfig == nil { 165 nc = new(C) 166 } else { 167 nc = c.newConfig() 168 } 169 if err := c.Parser.Unmarshal(nc); err != nil { 170 return err 171 } 172 if err := c.configReloadCheck(oc, nc); err != nil { 173 return err 174 } 175 c.config.Store(nc) 176 c.configReloaded(oc, nc) 177 return nil 178 }