github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/accounts/keystore/watch.go (about) 1 // +build darwin,!ios freebsd linux,!arm64 netbsd solaris 2 3 package keystore 4 5 import ( 6 "time" 7 8 "github.com/quickchainproject/quickchain/log" 9 "github.com/rjeczalik/notify" 10 ) 11 12 type watcher struct { 13 ac *accountCache 14 starting bool 15 running bool 16 ev chan notify.EventInfo 17 quit chan struct{} 18 } 19 20 func newWatcher(ac *accountCache) *watcher { 21 return &watcher{ 22 ac: ac, 23 ev: make(chan notify.EventInfo, 10), 24 quit: make(chan struct{}), 25 } 26 } 27 28 // starts the watcher loop in the background. 29 // Start a watcher in the background if that's not already in progress. 30 // The caller must hold w.ac.mu. 31 func (w *watcher) start() { 32 if w.starting || w.running { 33 return 34 } 35 w.starting = true 36 go w.loop() 37 } 38 39 func (w *watcher) close() { 40 close(w.quit) 41 } 42 43 func (w *watcher) loop() { 44 defer func() { 45 w.ac.mu.Lock() 46 w.running = false 47 w.starting = false 48 w.ac.mu.Unlock() 49 }() 50 logger := log.New("path", w.ac.keydir) 51 52 if err := notify.Watch(w.ac.keydir, w.ev, notify.All); err != nil { 53 logger.Trace("Failed to watch keystore folder", "err", err) 54 return 55 } 56 defer notify.Stop(w.ev) 57 logger.Trace("Started watching keystore folder") 58 defer logger.Trace("Stopped watching keystore folder") 59 60 w.ac.mu.Lock() 61 w.running = true 62 w.ac.mu.Unlock() 63 64 // Wait for file system events and reload. 65 // When an event occurs, the reload call is delayed a bit so that 66 // multiple events arriving quickly only cause a single reload. 67 var ( 68 debounceDuration = 500 * time.Millisecond 69 rescanTriggered = false 70 debounce = time.NewTimer(0) 71 ) 72 // Ignore initial trigger 73 if !debounce.Stop() { 74 <-debounce.C 75 } 76 defer debounce.Stop() 77 for { 78 select { 79 case <-w.quit: 80 return 81 case <-w.ev: 82 // Trigger the scan (with delay), if not already triggered 83 if !rescanTriggered { 84 debounce.Reset(debounceDuration) 85 rescanTriggered = true 86 } 87 case <-debounce.C: 88 w.ac.scanAccounts() 89 rescanTriggered = false 90 } 91 } 92 }