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