gitlab.com/flarenetwork/coreth@v0.1.1/accounts/keystore/watch.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2016 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 // +build darwin,!ios,cgo freebsd linux,!arm64 netbsd solaris 28 29 package keystore 30 31 import ( 32 "time" 33 34 "github.com/ethereum/go-ethereum/log" 35 "github.com/rjeczalik/notify" 36 ) 37 38 type watcher struct { 39 ac *accountCache 40 starting bool 41 running bool 42 ev chan notify.EventInfo 43 quit chan struct{} 44 } 45 46 func newWatcher(ac *accountCache) *watcher { 47 return &watcher{ 48 ac: ac, 49 ev: make(chan notify.EventInfo, 10), 50 quit: make(chan struct{}), 51 } 52 } 53 54 // starts the watcher loop in the background. 55 // Start a watcher in the background if that's not already in progress. 56 // The caller must hold w.ac.mu. 57 func (w *watcher) start() { 58 if w.starting || w.running { 59 return 60 } 61 w.starting = true 62 go w.loop() 63 } 64 65 func (w *watcher) close() { 66 close(w.quit) 67 } 68 69 func (w *watcher) loop() { 70 defer func() { 71 w.ac.mu.Lock() 72 w.running = false 73 w.starting = false 74 w.ac.mu.Unlock() 75 }() 76 logger := log.New("path", w.ac.keydir) 77 78 if err := notify.Watch(w.ac.keydir, w.ev, notify.All); err != nil { 79 logger.Trace("Failed to watch keystore folder", "err", err) 80 return 81 } 82 defer notify.Stop(w.ev) 83 logger.Trace("Started watching keystore folder") 84 defer logger.Trace("Stopped watching keystore folder") 85 86 w.ac.mu.Lock() 87 w.running = true 88 w.ac.mu.Unlock() 89 90 // Wait for file system events and reload. 91 // When an event occurs, the reload call is delayed a bit so that 92 // multiple events arriving quickly only cause a single reload. 93 var ( 94 debounceDuration = 500 * time.Millisecond 95 rescanTriggered = false 96 debounce = time.NewTimer(0) 97 ) 98 // Ignore initial trigger 99 if !debounce.Stop() { 100 <-debounce.C 101 } 102 defer debounce.Stop() 103 for { 104 select { 105 case <-w.quit: 106 return 107 case <-w.ev: 108 // Trigger the scan (with delay), if not already triggered 109 if !rescanTriggered { 110 debounce.Reset(debounceDuration) 111 rescanTriggered = true 112 } 113 case <-debounce.C: 114 w.ac.scanAccounts() 115 rescanTriggered = false 116 } 117 } 118 }