-
Notifications
You must be signed in to change notification settings - Fork 0
/
driver.go
128 lines (105 loc) · 2.52 KB
/
driver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package adbi
import (
"errors"
"fmt"
"io"
"os"
"os/exec"
"strings"
"sync"
"time"
log "github.com/sirupsen/logrus"
)
type Commander struct {
cmd *exec.Cmd
in io.WriteCloser
lastActive time.Time
m *sync.Mutex
stopCh chan interface{}
}
func New() (*Commander, error) {
cmd := exec.Command("adb", "shell")
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, err
}
err = cmd.Start()
if err != nil {
return nil, err
}
cmndr := &Commander{
cmd: cmd,
in: stdin,
lastActive: time.Now(),
m: &sync.Mutex{},
stopCh: make(chan interface{}),
}
// go cmndr.ping(179 * time.Second)
return cmndr, nil
}
func (c *Commander) Signal(key Keyevent) error {
return c.SignalWithRepeat(key, 1)
}
func (c *Commander) SignalWithRepeat(key Keyevent, n int) error {
inputEvent := key.TriggerWithRepeat(n)
if _, err := c.in.Write(inputEvent); err != nil {
// Communication with the Android device failed.
log.WithFields(log.Fields{
"error": err,
"key": rune(key),
}).Error("KeyEvent send failed")
// We can assume the server is down, or restarting.
// Let's return an error, kill cmd, and close the channel.
defer close(c.stopCh)
defer c.cmd.Wait()
return errors.New("server connection lost")
}
log.Info(strings.Trim(string(inputEvent), "\n"))
return nil
}
func (c *Commander) Raw(cmd string) error {
if _, err := c.in.Write([]byte(fmt.Sprintf("input %s\n", cmd))); err != nil {
// Communication with the Android device failed.
log.WithFields(log.Fields{
"error": err,
"key": rune('\x00'),
}).Error(fmt.Sprintf("%s send failed", cmd))
// We can assume the server is down, or restarting.
// Let's return an error, kill cmd, and close the channel.
defer close(c.stopCh)
defer c.cmd.Wait()
return errors.New("server connection lost")
}
log.Info(strings.Trim(cmd, "\n"))
return nil
}
func (c *Commander) Quit() {
c.in.Write([]byte("exit\n"))
log.Info("Quitting")
c.cmd.Wait()
os.Exit(0)
}
// Ensure device stays awake. Purpose: FireTV Cube.
func (c *Commander) ping(dur time.Duration) {
ticker := time.NewTicker(dur)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if time.Since(c.lastActive) < dur {
break
}
c.m.Lock()
c.Signal(Keyevent('w'))
c.m.Unlock()
case <-c.stopCh:
return
}
}
}
// Wait for server to reconnect.
func WaitForAndroid() {
log.Info("Waiting for a new adb connection. (Hint: adb connect <ip[:port]>)")
exec.Command("adb", "wait-for-device").Run()
log.Info("Success!")
}