github.com/micro/go-micro/v2@v2.9.1/config/default.go (about) 1 package config 2 3 import ( 4 "bytes" 5 "sync" 6 "time" 7 8 "github.com/micro/go-micro/v2/config/loader" 9 "github.com/micro/go-micro/v2/config/loader/memory" 10 "github.com/micro/go-micro/v2/config/reader" 11 "github.com/micro/go-micro/v2/config/reader/json" 12 "github.com/micro/go-micro/v2/config/source" 13 ) 14 15 type config struct { 16 exit chan bool 17 opts Options 18 19 sync.RWMutex 20 // the current snapshot 21 snap *loader.Snapshot 22 // the current values 23 vals reader.Values 24 } 25 26 type watcher struct { 27 lw loader.Watcher 28 rd reader.Reader 29 path []string 30 value reader.Value 31 } 32 33 func newConfig(opts ...Option) (Config, error) { 34 var c config 35 36 c.Init(opts...) 37 go c.run() 38 39 return &c, nil 40 } 41 42 func (c *config) Init(opts ...Option) error { 43 c.opts = Options{ 44 Reader: json.NewReader(), 45 } 46 c.exit = make(chan bool) 47 for _, o := range opts { 48 o(&c.opts) 49 } 50 51 // default loader uses the configured reader 52 if c.opts.Loader == nil { 53 c.opts.Loader = memory.NewLoader(memory.WithReader(c.opts.Reader)) 54 } 55 56 err := c.opts.Loader.Load(c.opts.Source...) 57 if err != nil { 58 return err 59 } 60 61 c.snap, err = c.opts.Loader.Snapshot() 62 if err != nil { 63 return err 64 } 65 66 c.vals, err = c.opts.Reader.Values(c.snap.ChangeSet) 67 if err != nil { 68 return err 69 } 70 71 return nil 72 } 73 74 func (c *config) Options() Options { 75 return c.opts 76 } 77 78 func (c *config) run() { 79 watch := func(w loader.Watcher) error { 80 for { 81 // get changeset 82 snap, err := w.Next() 83 if err != nil { 84 return err 85 } 86 87 c.Lock() 88 89 if c.snap.Version >= snap.Version { 90 c.Unlock() 91 continue 92 } 93 94 // save 95 c.snap = snap 96 97 // set values 98 c.vals, _ = c.opts.Reader.Values(snap.ChangeSet) 99 100 c.Unlock() 101 } 102 } 103 104 for { 105 w, err := c.opts.Loader.Watch() 106 if err != nil { 107 time.Sleep(time.Second) 108 continue 109 } 110 111 done := make(chan bool) 112 113 // the stop watch func 114 go func() { 115 select { 116 case <-done: 117 case <-c.exit: 118 } 119 w.Stop() 120 }() 121 122 // block watch 123 if err := watch(w); err != nil { 124 // do something better 125 time.Sleep(time.Second) 126 } 127 128 // close done chan 129 close(done) 130 131 // if the config is closed exit 132 select { 133 case <-c.exit: 134 return 135 default: 136 } 137 } 138 } 139 140 func (c *config) Map() map[string]interface{} { 141 c.RLock() 142 defer c.RUnlock() 143 return c.vals.Map() 144 } 145 146 func (c *config) Scan(v interface{}) error { 147 c.RLock() 148 defer c.RUnlock() 149 return c.vals.Scan(v) 150 } 151 152 // sync loads all the sources, calls the parser and updates the config 153 func (c *config) Sync() error { 154 if err := c.opts.Loader.Sync(); err != nil { 155 return err 156 } 157 158 snap, err := c.opts.Loader.Snapshot() 159 if err != nil { 160 return err 161 } 162 163 c.Lock() 164 defer c.Unlock() 165 166 c.snap = snap 167 vals, err := c.opts.Reader.Values(snap.ChangeSet) 168 if err != nil { 169 return err 170 } 171 c.vals = vals 172 173 return nil 174 } 175 176 func (c *config) Close() error { 177 select { 178 case <-c.exit: 179 return nil 180 default: 181 close(c.exit) 182 } 183 return nil 184 } 185 186 func (c *config) Get(path ...string) reader.Value { 187 c.RLock() 188 defer c.RUnlock() 189 190 // did sync actually work? 191 if c.vals != nil { 192 return c.vals.Get(path...) 193 } 194 195 // no value 196 return newValue() 197 } 198 199 func (c *config) Set(val interface{}, path ...string) { 200 c.Lock() 201 defer c.Unlock() 202 203 if c.vals != nil { 204 c.vals.Set(val, path...) 205 } 206 207 return 208 } 209 210 func (c *config) Del(path ...string) { 211 c.Lock() 212 defer c.Unlock() 213 214 if c.vals != nil { 215 c.vals.Del(path...) 216 } 217 218 return 219 } 220 221 func (c *config) Bytes() []byte { 222 c.RLock() 223 defer c.RUnlock() 224 225 if c.vals == nil { 226 return []byte{} 227 } 228 229 return c.vals.Bytes() 230 } 231 232 func (c *config) Load(sources ...source.Source) error { 233 if err := c.opts.Loader.Load(sources...); err != nil { 234 return err 235 } 236 237 snap, err := c.opts.Loader.Snapshot() 238 if err != nil { 239 return err 240 } 241 242 c.Lock() 243 defer c.Unlock() 244 245 c.snap = snap 246 vals, err := c.opts.Reader.Values(snap.ChangeSet) 247 if err != nil { 248 return err 249 } 250 c.vals = vals 251 252 return nil 253 } 254 255 func (c *config) Watch(path ...string) (Watcher, error) { 256 value := c.Get(path...) 257 258 w, err := c.opts.Loader.Watch(path...) 259 if err != nil { 260 return nil, err 261 } 262 263 return &watcher{ 264 lw: w, 265 rd: c.opts.Reader, 266 path: path, 267 value: value, 268 }, nil 269 } 270 271 func (c *config) String() string { 272 return "config" 273 } 274 275 func (w *watcher) Next() (reader.Value, error) { 276 for { 277 s, err := w.lw.Next() 278 if err != nil { 279 return nil, err 280 } 281 282 // only process changes 283 if bytes.Equal(w.value.Bytes(), s.ChangeSet.Data) { 284 continue 285 } 286 287 v, err := w.rd.Values(s.ChangeSet) 288 if err != nil { 289 return nil, err 290 } 291 292 w.value = v.Get() 293 return w.value, nil 294 } 295 } 296 297 func (w *watcher) Stop() error { 298 return w.lw.Stop() 299 }