github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/cmd/snap-bootstrap/triggerwatch/triggerwatch.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program 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 General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package triggerwatch 21 22 import ( 23 "errors" 24 "fmt" 25 "time" 26 27 "github.com/snapcore/snapd/logger" 28 ) 29 30 type triggerProvider interface { 31 FindMatchingDevices(filter triggerEventFilter) ([]triggerDevice, error) 32 } 33 34 type triggerDevice interface { 35 WaitForTrigger(chan keyEvent) 36 String() string 37 Close() 38 } 39 40 var ( 41 // trigger mechanism 42 trigger triggerProvider 43 44 // wait for '1' to be pressed 45 triggerFilter = triggerEventFilter{Key: "KEY_1"} 46 47 ErrTriggerNotDetected = errors.New("trigger not detected") 48 ErrNoMatchingInputDevices = errors.New("no matching input devices") 49 ) 50 51 // Wait waits for a trigger on the available trigger devices for a given amount 52 // of time. Returns nil if one was detected, ErrTriggerNotDetected if timeout 53 // was hit, or other non-nil error. 54 func Wait(timeout time.Duration) error { 55 if trigger == nil { 56 logger.Panicf("trigger is unset") 57 } 58 59 devices, err := trigger.FindMatchingDevices(triggerFilter) 60 if err != nil { 61 return fmt.Errorf("cannot list trigger devices: %v", err) 62 } 63 if devices == nil { 64 return ErrNoMatchingInputDevices 65 } 66 67 logger.Noticef("waiting for trigger key: %v", triggerFilter.Key) 68 69 detectKeyCh := make(chan keyEvent, len(devices)) 70 for _, dev := range devices { 71 go dev.WaitForTrigger(detectKeyCh) 72 defer dev.Close() 73 } 74 75 select { 76 case kev := <-detectKeyCh: 77 if kev.Err != nil { 78 return err 79 } 80 // channel got closed without an error 81 logger.Noticef("%s: + got trigger key %v", kev.Dev, triggerFilter.Key) 82 case <-time.After(timeout): 83 return ErrTriggerNotDetected 84 } 85 86 return nil 87 }