gitee.com/sasukebo/go-micro/v4@v4.7.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 "gitee.com/sasukebo/go-micro/v4/config/loader" 13 "gitee.com/sasukebo/go-micro/v4/config/reader" 14 "gitee.com/sasukebo/go-micro/v4/config/reader/json" 15 "gitee.com/sasukebo/go-micro/v4/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 if vals, err := m.opts.Reader.Values(set); err != nil { 144 m.vals = vals 145 } 146 m.snap = &loader.Snapshot{ 147 ChangeSet: set, 148 Version: genVer(), 149 } 150 151 m.Unlock() 152 153 // update watchers 154 m.update() 155 156 return nil 157 } 158 159 func (m *memory) update() { 160 watchers := make([]*watcher, 0, m.watchers.Len()) 161 162 m.RLock() 163 for e := m.watchers.Front(); e != nil; e = e.Next() { 164 watchers = append(watchers, e.Value.(*watcher)) 165 } 166 167 vals := m.vals 168 snap := m.snap 169 m.RUnlock() 170 171 for _, w := range watchers { 172 if w.version >= snap.Version { 173 continue 174 } 175 176 uv := updateValue{ 177 version: m.snap.Version, 178 value: vals.Get(w.path...), 179 } 180 181 select { 182 case w.updates <- uv: 183 default: 184 } 185 } 186 } 187 188 // Snapshot returns a snapshot of the current loaded config 189 func (m *memory) Snapshot() (*loader.Snapshot, error) { 190 if m.loaded() { 191 m.RLock() 192 snap := loader.Copy(m.snap) 193 m.RUnlock() 194 return snap, nil 195 } 196 197 // not loaded, sync 198 if err := m.Sync(); err != nil { 199 return nil, err 200 } 201 202 // make copy 203 m.RLock() 204 snap := loader.Copy(m.snap) 205 m.RUnlock() 206 207 return snap, nil 208 } 209 210 // Sync loads all the sources, calls the parser and updates the config 211 func (m *memory) Sync() error { 212 //nolint:prealloc 213 var sets []*source.ChangeSet 214 215 m.Lock() 216 217 // read the source 218 var gerr []string 219 220 for _, source := range m.sources { 221 ch, err := source.Read() 222 if err != nil { 223 gerr = append(gerr, err.Error()) 224 continue 225 } 226 sets = append(sets, ch) 227 } 228 229 // merge sets 230 set, err := m.opts.Reader.Merge(sets...) 231 if err != nil { 232 m.Unlock() 233 return err 234 } 235 236 // set values 237 vals, err := m.opts.Reader.Values(set) 238 if err != nil { 239 m.Unlock() 240 return err 241 } 242 m.vals = vals 243 m.snap = &loader.Snapshot{ 244 ChangeSet: set, 245 Version: genVer(), 246 } 247 248 m.Unlock() 249 250 // update watchers 251 m.update() 252 253 if len(gerr) > 0 { 254 return fmt.Errorf("source loading errors: %s", strings.Join(gerr, "\n")) 255 } 256 257 return nil 258 } 259 260 func (m *memory) Close() error { 261 select { 262 case <-m.exit: 263 return nil 264 default: 265 close(m.exit) 266 } 267 return nil 268 } 269 270 func (m *memory) Get(path ...string) (reader.Value, error) { 271 if !m.loaded() { 272 if err := m.Sync(); err != nil { 273 return nil, err 274 } 275 } 276 277 m.Lock() 278 defer m.Unlock() 279 280 // did sync actually work? 281 if m.vals != nil { 282 return m.vals.Get(path...), nil 283 } 284 285 // assuming vals is nil 286 // create new vals 287 288 ch := m.snap.ChangeSet 289 290 // we are truly screwed, trying to load in a hacked way 291 v, err := m.opts.Reader.Values(ch) 292 if err != nil { 293 return nil, err 294 } 295 296 // lets set it just because 297 m.vals = v 298 299 if m.vals != nil { 300 return m.vals.Get(path...), nil 301 } 302 303 // ok we're going hardcore now 304 305 return nil, errors.New("no values") 306 } 307 308 func (m *memory) Load(sources ...source.Source) error { 309 var gerrors []string 310 311 for _, source := range sources { 312 set, err := source.Read() 313 if err != nil { 314 gerrors = append(gerrors, 315 fmt.Sprintf("error loading source %s: %v", 316 source, 317 err)) 318 // continue processing 319 continue 320 } 321 m.Lock() 322 m.sources = append(m.sources, source) 323 m.sets = append(m.sets, set) 324 idx := len(m.sets) - 1 325 m.Unlock() 326 if !m.opts.WithWatcherDisabled { 327 go m.watch(idx, source) 328 } 329 } 330 331 if err := m.reload(); err != nil { 332 gerrors = append(gerrors, err.Error()) 333 } 334 335 // Return errors 336 if len(gerrors) != 0 { 337 return errors.New(strings.Join(gerrors, "\n")) 338 } 339 return nil 340 } 341 342 func (m *memory) Watch(path ...string) (loader.Watcher, error) { 343 if m.opts.WithWatcherDisabled { 344 return nil, errors.New("watcher is disabled") 345 } 346 347 value, err := m.Get(path...) 348 if err != nil { 349 return nil, err 350 } 351 352 m.Lock() 353 354 w := &watcher{ 355 exit: make(chan bool), 356 path: path, 357 value: value, 358 reader: m.opts.Reader, 359 updates: make(chan updateValue, 1), 360 version: m.snap.Version, 361 } 362 363 e := m.watchers.PushBack(w) 364 365 m.Unlock() 366 367 go func() { 368 <-w.exit 369 m.Lock() 370 m.watchers.Remove(e) 371 m.Unlock() 372 }() 373 374 return w, nil 375 } 376 377 func (m *memory) String() string { 378 return "memory" 379 } 380 381 func (w *watcher) Next() (*loader.Snapshot, error) { 382 update := func(v reader.Value) *loader.Snapshot { 383 w.value = v 384 385 cs := &source.ChangeSet{ 386 Data: v.Bytes(), 387 Format: w.reader.String(), 388 Source: "memory", 389 Timestamp: time.Now(), 390 } 391 cs.Checksum = cs.Sum() 392 393 return &loader.Snapshot{ 394 ChangeSet: cs, 395 Version: w.version, 396 } 397 398 } 399 400 for { 401 select { 402 case <-w.exit: 403 return nil, errors.New("watcher stopped") 404 405 case uv := <-w.updates: 406 if uv.version <= w.version { 407 continue 408 } 409 410 v := uv.value 411 412 w.version = uv.version 413 414 if bytes.Equal(w.value.Bytes(), v.Bytes()) { 415 continue 416 } 417 418 return update(v), nil 419 } 420 } 421 } 422 423 func (w *watcher) Stop() error { 424 select { 425 case <-w.exit: 426 default: 427 close(w.exit) 428 close(w.updates) 429 } 430 431 return nil 432 } 433 434 func genVer() string { 435 return fmt.Sprintf("%d", time.Now().UnixNano()) 436 } 437 438 func NewLoader(opts ...loader.Option) loader.Loader { 439 options := loader.Options{ 440 Reader: json.NewReader(), 441 } 442 443 for _, o := range opts { 444 o(&options) 445 } 446 447 m := &memory{ 448 exit: make(chan bool), 449 opts: options, 450 watchers: list.New(), 451 sources: options.Source, 452 } 453 454 m.sets = make([]*source.ChangeSet, len(options.Source)) 455 456 for i, s := range options.Source { 457 m.sets[i] = &source.ChangeSet{Source: s.String()} 458 if !options.WithWatcherDisabled { 459 go m.watch(i, s) 460 } 461 } 462 463 return m 464 }