| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | // Copyright 2017 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/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package usbwallet | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-02-16 15:36:44 +02:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/accounts" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							| 
									
										
										
										
											2017-02-22 16:58:00 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2017-02-16 15:36:44 +02:00
										 |  |  | 	"github.com/karalabe/hid" | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 15:53:02 +02:00
										 |  |  | // LedgerScheme is the protocol scheme prefixing account and wallet URLs. | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | const LedgerScheme = "ledger" | 
					
						
							| 
									
										
										
										
											2017-02-08 15:53:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | // TrezorScheme is the protocol scheme prefixing account and wallet URLs. | 
					
						
							|  |  |  | const TrezorScheme = "trezor" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // refreshCycle is the maximum time between wallet refreshes (if USB hotplug | 
					
						
							|  |  |  | // notifications don't work). | 
					
						
							|  |  |  | const refreshCycle = time.Second | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | // refreshThrottling is the minimum time between wallet refreshes to avoid USB | 
					
						
							|  |  |  | // trashing. | 
					
						
							|  |  |  | const refreshThrottling = 500 * time.Millisecond | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | // Hub is a accounts.Backend that can find and handle generic USB hardware wallets. | 
					
						
							|  |  |  | type Hub struct { | 
					
						
							|  |  |  | 	scheme     string                  // Protocol scheme prefixing account and wallet URLs. | 
					
						
							|  |  |  | 	vendorID   uint16                  // USB vendor identifier used for device discovery | 
					
						
							|  |  |  | 	productIDs []uint16                // USB product identifiers used for device discovery | 
					
						
							| 
									
										
										
										
											2017-10-03 12:18:50 +03:00
										 |  |  | 	usageID    uint16                  // USB usage page identifier used for macOS device discovery | 
					
						
							|  |  |  | 	endpointID int                     // USB endpoint identifier used for non-macOS device discovery | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 	makeDriver func(log.Logger) driver // Factory method to construct a vendor specific driver | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	refreshed   time.Time               // Time instance when the list of wallets was last refreshed | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 	wallets     []accounts.Wallet       // List of USB wallet devices currently tracking | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	updateFeed  event.Feed              // Event feed to notify wallet additions/removals | 
					
						
							|  |  |  | 	updateScope event.SubscriptionScope // Subscription scope tracking current live listeners | 
					
						
							|  |  |  | 	updating    bool                    // Whether the event notification loop is running | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	quit chan chan error | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	stateLock sync.RWMutex // Protects the internals of the hub from racey access | 
					
						
							| 
									
										
										
										
											2017-03-23 17:04:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// TODO(karalabe): remove if hotplug lands on Windows | 
					
						
							|  |  |  | 	commsPend int        // Number of operations blocking enumeration | 
					
						
							|  |  |  | 	commsLock sync.Mutex // Lock protecting the pending counter and enumeration | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewLedgerHub creates a new hardware wallet manager for Ledger devices. | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | func NewLedgerHub() (*Hub, error) { | 
					
						
							| 
									
										
										
										
											2017-10-03 12:18:50 +03:00
										 |  |  | 	return newHub(LedgerScheme, 0x2c97, []uint16{0x0000 /* Ledger Blue */, 0x0001 /* Ledger Nano S */}, 0xffa0, 0, newLedgerDriver) | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewTrezorHub creates a new hardware wallet manager for Trezor devices. | 
					
						
							|  |  |  | func NewTrezorHub() (*Hub, error) { | 
					
						
							| 
									
										
										
										
											2017-10-03 12:18:50 +03:00
										 |  |  | 	return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor 1 */}, 0xff00, 0, newTrezorDriver) | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newHub creates a new hardware wallet manager for generic USB devices. | 
					
						
							| 
									
										
										
										
											2017-10-03 12:18:50 +03:00
										 |  |  | func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) { | 
					
						
							| 
									
										
										
										
											2017-02-16 15:36:44 +02:00
										 |  |  | 	if !hid.Supported() { | 
					
						
							|  |  |  | 		return nil, errors.New("unsupported platform") | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 	hub := &Hub{ | 
					
						
							|  |  |  | 		scheme:     scheme, | 
					
						
							|  |  |  | 		vendorID:   vendorID, | 
					
						
							|  |  |  | 		productIDs: productIDs, | 
					
						
							| 
									
										
										
										
											2017-10-03 12:18:50 +03:00
										 |  |  | 		usageID:    usageID, | 
					
						
							|  |  |  | 		endpointID: endpointID, | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 		makeDriver: makeDriver, | 
					
						
							|  |  |  | 		quit:       make(chan chan error), | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	hub.refreshWallets() | 
					
						
							|  |  |  | 	return hub, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Wallets implements accounts.Backend, returning all the currently tracked USB | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | // devices that appear to be hardware wallets. | 
					
						
							|  |  |  | func (hub *Hub) Wallets() []accounts.Wallet { | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	// Make sure the list of wallets is up to date | 
					
						
							|  |  |  | 	hub.refreshWallets() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 	hub.stateLock.RLock() | 
					
						
							|  |  |  | 	defer hub.stateLock.RUnlock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cpy := make([]accounts.Wallet, len(hub.wallets)) | 
					
						
							|  |  |  | 	copy(cpy, hub.wallets) | 
					
						
							|  |  |  | 	return cpy | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // refreshWallets scans the USB devices attached to the machine and updates the | 
					
						
							|  |  |  | // list of wallets based on the found devices. | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | func (hub *Hub) refreshWallets() { | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	// Don't scan the USB like crazy it the user fetches wallets in a loop | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 	hub.stateLock.RLock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	elapsed := time.Since(hub.refreshed) | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 	hub.stateLock.RUnlock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 	if elapsed < refreshThrottling { | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 	// Retrieve the current list of USB wallet devices | 
					
						
							|  |  |  | 	var devices []hid.DeviceInfo | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if runtime.GOOS == "linux" { | 
					
						
							|  |  |  | 		// hidapi on Linux opens the device during enumeration to retrieve some infos, | 
					
						
							|  |  |  | 		// breaking the Ledger protocol if that is waiting for user confirmation. This | 
					
						
							|  |  |  | 		// is a bug acknowledged at Ledger, but it won't be fixed on old devices so we | 
					
						
							|  |  |  | 		// need to prevent concurrent comms ourselves. The more elegant solution would | 
					
						
							| 
									
										
											  
											
												cmd/clef, signer: initial poc of the standalone signer (#16154)
* signer: introduce external signer command
* cmd/signer, rpc: Implement new signer. Add info about remote user to Context
* signer: refactored request/response, made use of urfave.cli
* cmd/signer: Use common flags
* cmd/signer: methods to validate calldata against abi
* cmd/signer: work on abi parser
* signer: add mutex around UI
* cmd/signer: add json 4byte directory, remove passwords from api
* cmd/signer: minor changes
* cmd/signer: Use ErrRequestDenied, enable lightkdf
* cmd/signer: implement tests
* cmd/signer: made possible for UI to modify tx parameters
* cmd/signer: refactors, removed channels in ui comms, added UI-api via stdin/out
* cmd/signer: Made lowercase json-definitions, added UI-signer test functionality
* cmd/signer: update documentation
* cmd/signer: fix bugs, improve abi detection, abi argument display
* cmd/signer: minor change in json format
* cmd/signer: rework json communication
* cmd/signer: implement mixcase addresses in API, fix json id bug
* cmd/signer: rename fromaccount, update pythonpoc with new json encoding format
* cmd/signer: make use of new abi interface
* signer: documentation
* signer/main: remove redundant  option
* signer: implement audit logging
* signer: create package 'signer', minor changes
* common: add 0x-prefix to mixcaseaddress in json marshalling + validation
* signer, rules, storage: implement rules + ephemeral storage for signer rules
* signer: implement OnApprovedTx, change signing response (API BREAKAGE)
* signer: refactoring + documentation
* signer/rules: implement dispatching to next handler
* signer: docs
* signer/rules: hide json-conversion from users, ensure context is cleaned
* signer: docs
* signer: implement validation rules, change signature of call_info
* signer: fix log flaw with string pointer
* signer: implement custom 4byte databsae that saves submitted signatures
* signer/storage: implement aes-gcm-backed credential storage
* accounts: implement json unmarshalling of url
* signer: fix listresponse, fix gas->uint64
* node: make http/ipc start methods public
* signer: add ipc capability+review concerns
* accounts: correct docstring
* signer: address review concerns
* rpc: go fmt -s
* signer: review concerns+ baptize Clef
* signer,node: move Start-functions to separate file
* signer: formatting
											
										 
											2018-04-16 14:04:32 +02:00
										 |  |  | 		// be to ditch enumeration in favor of hotplug events, but that don't work yet | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 		// on Windows so if we need to hack it anyway, this is more elegant for now. | 
					
						
							|  |  |  | 		hub.commsLock.Lock() | 
					
						
							| 
									
										
										
										
											2017-03-23 17:04:39 +02:00
										 |  |  | 		if hub.commsPend > 0 { // A confirmation is pending, don't refresh | 
					
						
							|  |  |  | 			hub.commsLock.Unlock() | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 	for _, info := range hid.Enumerate(hub.vendorID, 0) { | 
					
						
							|  |  |  | 		for _, id := range hub.productIDs { | 
					
						
							| 
									
										
										
										
											2017-10-03 12:18:50 +03:00
										 |  |  | 			if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 				devices = append(devices, info) | 
					
						
							| 
									
										
										
										
											2017-02-16 15:36:44 +02:00
										 |  |  | 				break | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-16 15:36:44 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 	if runtime.GOOS == "linux" { | 
					
						
							|  |  |  | 		// See rationale before the enumeration why this is needed and only on Linux. | 
					
						
							|  |  |  | 		hub.commsLock.Unlock() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	// Transform the current list of wallets into the new one | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 	hub.stateLock.Lock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-06 02:30:39 -08:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		wallets = make([]accounts.Wallet, 0, len(devices)) | 
					
						
							|  |  |  | 		events  []accounts.WalletEvent | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 	for _, device := range devices { | 
					
						
							|  |  |  | 		url := accounts.URL{Scheme: hub.scheme, Path: device.Path} | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 03:28:22 +02:00
										 |  |  | 		// Drop wallets in front of the next device or those that failed for some reason | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 		for len(hub.wallets) > 0 { | 
					
						
							|  |  |  | 			// Abort if we're past the current device and found an operational one | 
					
						
							|  |  |  | 			_, failure := hub.wallets[0].Status() | 
					
						
							|  |  |  | 			if hub.wallets[0].URL().Cmp(url) >= 0 || failure == nil { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// Drop the stale and failed devices | 
					
						
							| 
									
										
										
										
											2017-08-01 17:45:17 +02:00
										 |  |  | 			events = append(events, accounts.WalletEvent{Wallet: hub.wallets[0], Kind: accounts.WalletDropped}) | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 			hub.wallets = hub.wallets[1:] | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-09 03:28:22 +02:00
										 |  |  | 		// If there are no more wallets or the device is before the next, wrap new wallet | 
					
						
							| 
									
										
										
										
											2017-02-08 15:53:02 +02:00
										 |  |  | 		if len(hub.wallets) == 0 || hub.wallets[0].URL().Cmp(url) > 0 { | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 			logger := log.New("url", url) | 
					
						
							|  |  |  | 			wallet := &wallet{hub: hub, driver: hub.makeDriver(logger), url: &url, info: device, log: logger} | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-01 17:45:17 +02:00
										 |  |  | 			events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived}) | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 			wallets = append(wallets, wallet) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-09 03:28:22 +02:00
										 |  |  | 		// If the device is the same as the first wallet, keep it | 
					
						
							| 
									
										
										
										
											2017-02-08 15:53:02 +02:00
										 |  |  | 		if hub.wallets[0].URL().Cmp(url) == 0 { | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 			wallets = append(wallets, hub.wallets[0]) | 
					
						
							|  |  |  | 			hub.wallets = hub.wallets[1:] | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Drop any leftover wallets and set the new batch | 
					
						
							|  |  |  | 	for _, wallet := range hub.wallets { | 
					
						
							| 
									
										
										
										
											2017-08-01 17:45:17 +02:00
										 |  |  | 		events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletDropped}) | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	hub.refreshed = time.Now() | 
					
						
							|  |  |  | 	hub.wallets = wallets | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 	hub.stateLock.Unlock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Fire all wallet events and return | 
					
						
							|  |  |  | 	for _, event := range events { | 
					
						
							|  |  |  | 		hub.updateFeed.Send(event) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Subscribe implements accounts.Backend, creating an async subscription to | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | // receive notifications on the addition or removal of USB wallets. | 
					
						
							|  |  |  | func (hub *Hub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription { | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	// We need the mutex to reliably start/stop the update loop | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 	hub.stateLock.Lock() | 
					
						
							|  |  |  | 	defer hub.stateLock.Unlock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Subscribe the caller and track the subscriber count | 
					
						
							|  |  |  | 	sub := hub.updateScope.Track(hub.updateFeed.Subscribe(sink)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Subscribers require an active notification loop, start it | 
					
						
							|  |  |  | 	if !hub.updating { | 
					
						
							|  |  |  | 		hub.updating = true | 
					
						
							|  |  |  | 		go hub.updater() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return sub | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | // updater is responsible for maintaining an up-to-date list of wallets managed | 
					
						
							|  |  |  | // by the USB hub, and for firing wallet addition/removal events. | 
					
						
							|  |  |  | func (hub *Hub) updater() { | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2017-08-07 14:11:15 +03:00
										 |  |  | 		// TODO: Wait for a USB hotplug event (not supported yet) or a refresh timeout | 
					
						
							|  |  |  | 		// <-hub.changes | 
					
						
							| 
									
										
										
										
											2017-08-09 12:51:16 +03:00
										 |  |  | 		time.Sleep(refreshCycle) | 
					
						
							| 
									
										
										
										
											2017-08-07 14:11:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 		// Run the wallet refresher | 
					
						
							|  |  |  | 		hub.refreshWallets() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// If all our subscribers left, stop the updater | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 		hub.stateLock.Lock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 		if hub.updateScope.Count() == 0 { | 
					
						
							|  |  |  | 			hub.updating = false | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 			hub.stateLock.Unlock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-20 13:35:56 +02:00
										 |  |  | 		hub.stateLock.Unlock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |