-
Notifications
You must be signed in to change notification settings - Fork 1
/
browser.go
136 lines (121 loc) · 2.83 KB
/
browser.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
129
130
131
132
133
134
135
136
package cdp
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"sort"
"syscall"
"time"
)
// Browser contains information required to stop an exec'd browser at a later point in time.
type Browser struct {
Port int
PID int
TempDir string
LogFile *os.File
Log *log.Logger
ConsoleFile *os.File
Console *log.Logger
}
// NewBrowser accepts the path to the browser's binary, the port, and any arguments that need to be passed to the binary.
func NewBrowser(path string, port int, logfile string, args ...string) *Browser {
b := &Browser{}
var err error
b.LogFile, err = os.Create(logfile)
if err != nil {
panic(err)
}
b.Log = log.New(b.LogFile, "", log.Llongfile|log.LstdFlags|log.Lmicroseconds)
b.ConsoleFile, err = os.Create(logfile + ".console")
if err != nil {
panic(err)
}
b.Console = log.New(b.ConsoleFile, "", log.Lshortfile|log.LstdFlags)
b.Port = port
// Add required values
required := []string{"--no-first-run", "--no-default-browser-check"}
for _, req := range required {
sort.Strings(args)
at := sort.SearchStrings(args, req)
if at == len(args) || args[at] != req {
args = append(args, req)
}
}
// Temp directory
dir, err := ioutil.TempDir("", "cdp-")
if err != nil {
panic(err)
}
b.TempDir = dir
args = append(args, fmt.Sprintf("--user-data-dir=%s", b.TempDir))
// Debugging port of the browser
debuggingPort := fmt.Sprintf("--remote-debugging-port=%d", b.Port)
args = append(args, debuggingPort)
log.Printf("Args %+v", args)
cmd := exec.Command(path, args...)
// Prepare to send output to the log file
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
panic(err)
}
// Start the browser
if err := cmd.Start(); err != nil {
panic(err)
}
b.PID = cmd.Process.Pid
// The browser does need a moment to start up. This will probably differ on different systems.
time.Sleep(time.Second * 1)
// Feed output to the log
go func() {
sout := bufio.NewScanner(stdout)
for sout.Scan() {
log.Print(sout.Text())
}
if err := sout.Err(); err != nil {
log.Printf("error: %s", err)
}
}()
go func() {
serr := bufio.NewScanner(stderr)
for serr.Scan() {
log.Print(serr.Text())
}
if err := serr.Err(); err != nil {
log.Printf("error: %s", err)
}
}()
return b
}
// Stop kills the running browser process.
func (b *Browser) Stop() {
log.Print("stopping the browser")
if b.PID == 0 {
log.Print("no process id for the browser")
return
}
err := syscall.Kill(b.PID, syscall.SIGKILL)
if err != nil {
panic(err)
}
if b.TempDir != "" {
err := os.RemoveAll(b.TempDir)
if err != nil {
log.Printf("error: %s", err)
}
}
err = b.LogFile.Close()
if err != nil {
log.Printf("error: %s", err)
}
err = b.ConsoleFile.Close()
if err != nil {
log.Printf("error: %s", err)
}
}