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