forked from cerc-io/plugeth
5b9cbe30f8
As the keydir will be automatically created after an account is created, no error message if the watcher is failed.
135 lines
3.5 KiB
Go
135 lines
3.5 KiB
Go
// Copyright 2016 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//go:build (darwin && !ios && cgo) || freebsd || (linux && !arm64) || netbsd || solaris
|
|
// +build darwin,!ios,cgo freebsd linux,!arm64 netbsd solaris
|
|
|
|
package keystore
|
|
|
|
import (
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/fsnotify/fsnotify"
|
|
)
|
|
|
|
type watcher struct {
|
|
ac *accountCache
|
|
running bool // set to true when runloop begins
|
|
runEnded bool // set to true when runloop ends
|
|
starting bool // set to true prior to runloop starting
|
|
quit chan struct{}
|
|
}
|
|
|
|
func newWatcher(ac *accountCache) *watcher {
|
|
return &watcher{
|
|
ac: ac,
|
|
quit: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
// enabled returns false on systems not supported.
|
|
func (*watcher) enabled() bool { return true }
|
|
|
|
// starts the watcher loop in the background.
|
|
// Start a watcher in the background if that's not already in progress.
|
|
// The caller must hold w.ac.mu.
|
|
func (w *watcher) start() {
|
|
if w.starting || w.running {
|
|
return
|
|
}
|
|
w.starting = true
|
|
go w.loop()
|
|
}
|
|
|
|
func (w *watcher) close() {
|
|
close(w.quit)
|
|
}
|
|
|
|
func (w *watcher) loop() {
|
|
defer func() {
|
|
w.ac.mu.Lock()
|
|
w.running = false
|
|
w.starting = false
|
|
w.runEnded = true
|
|
w.ac.mu.Unlock()
|
|
}()
|
|
logger := log.New("path", w.ac.keydir)
|
|
|
|
// Create new watcher.
|
|
watcher, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
log.Error("Failed to start filesystem watcher", "err", err)
|
|
return
|
|
}
|
|
defer watcher.Close()
|
|
if err := watcher.Add(w.ac.keydir); err != nil {
|
|
if !os.IsNotExist(err) {
|
|
logger.Warn("Failed to watch keystore folder", "err", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
logger.Trace("Started watching keystore folder", "folder", w.ac.keydir)
|
|
defer logger.Trace("Stopped watching keystore folder")
|
|
|
|
w.ac.mu.Lock()
|
|
w.running = true
|
|
w.ac.mu.Unlock()
|
|
|
|
// Wait for file system events and reload.
|
|
// When an event occurs, the reload call is delayed a bit so that
|
|
// multiple events arriving quickly only cause a single reload.
|
|
var (
|
|
debounceDuration = 500 * time.Millisecond
|
|
rescanTriggered = false
|
|
debounce = time.NewTimer(0)
|
|
)
|
|
// Ignore initial trigger
|
|
if !debounce.Stop() {
|
|
<-debounce.C
|
|
}
|
|
defer debounce.Stop()
|
|
for {
|
|
select {
|
|
case <-w.quit:
|
|
return
|
|
case _, ok := <-watcher.Events:
|
|
if !ok {
|
|
return
|
|
}
|
|
// Trigger the scan (with delay), if not already triggered
|
|
if !rescanTriggered {
|
|
debounce.Reset(debounceDuration)
|
|
rescanTriggered = true
|
|
}
|
|
// The fsnotify library does provide more granular event-info, it
|
|
// would be possible to refresh individual affected files instead
|
|
// of scheduling a full rescan. For most cases though, the
|
|
// full rescan is quick and obviously simplest.
|
|
case err, ok := <-watcher.Errors:
|
|
if !ok {
|
|
return
|
|
}
|
|
log.Info("Filsystem watcher error", "err", err)
|
|
case <-debounce.C:
|
|
w.ac.scanAccounts()
|
|
rescanTriggered = false
|
|
}
|
|
}
|
|
}
|