| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | // 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/>. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-28 03:09:58 +01:00
										 |  |  | // +build darwin,!ios freebsd linux,!arm64 netbsd solaris | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | package keystore | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	"github.com/rjeczalik/notify" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type watcher struct { | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	ac       *accountCache | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	starting bool | 
					
						
							|  |  |  | 	running  bool | 
					
						
							|  |  |  | 	ev       chan notify.EventInfo | 
					
						
							|  |  |  | 	quit     chan struct{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func newWatcher(ac *accountCache) *watcher { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	return &watcher{ | 
					
						
							|  |  |  | 		ac:   ac, | 
					
						
							|  |  |  | 		ev:   make(chan notify.EventInfo, 10), | 
					
						
							|  |  |  | 		quit: make(chan struct{}), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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.ac.mu.Unlock() | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2017-02-22 16:58:00 +02:00
										 |  |  | 	logger := log.New("path", w.ac.keydir) | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 16:58:00 +02:00
										 |  |  | 	if err := notify.Watch(w.ac.keydir, w.ev, notify.All); err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-27 13:17:58 +02:00
										 |  |  | 		logger.Trace("Failed to watch keystore folder", "err", err) | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer notify.Stop(w.ev) | 
					
						
							| 
									
										
										
										
											2017-02-22 16:58:00 +02:00
										 |  |  | 	logger.Trace("Started watching keystore folder") | 
					
						
							|  |  |  | 	defer logger.Trace("Stopped watching keystore folder") | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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 ( | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 		debounceDuration = 500 * time.Millisecond | 
					
						
							|  |  |  | 		rescanTriggered  = false | 
					
						
							| 
									
										
										
										
											2017-11-20 12:35:30 +01:00
										 |  |  | 		debounce         = time.NewTimer(0) | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2017-11-20 12:35:30 +01:00
										 |  |  | 	// Ignore initial trigger | 
					
						
							|  |  |  | 	if !debounce.Stop() { | 
					
						
							|  |  |  | 		<-debounce.C | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	defer debounce.Stop() | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-w.quit: | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		case <-w.ev: | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 			// Trigger the scan (with delay), if not already triggered | 
					
						
							|  |  |  | 			if !rescanTriggered { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 				debounce.Reset(debounceDuration) | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 				rescanTriggered = true | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		case <-debounce.C: | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 			w.ac.scanAccounts() | 
					
						
							|  |  |  | 			rescanTriggered = false | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |