Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit 6c3449f

Browse files
committed
Refactor parseDevToolsURL
Separates the parsing from concurrently waiting. Advantages: + Separation of concerns. + Parsing logic or error handling can be changed and test separately. + Simplified channel handling. + Scanner returns when it grabs the devToolsURL. + Scanner error handling is managed where it belongs to (in the parser code). + Supports multiple errors.
1 parent b704a91 commit 6c3449f

File tree

1 file changed

+55
-35
lines changed

1 file changed

+55
-35
lines changed

common/browser_process.go

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -181,49 +181,69 @@ func execute(
181181

182182
// parseDevToolsURL grabs the WebSocket address from Chrome's output and returns
183183
// it. If the process ends abruptly, it will return the first error from stderr.
184-
func parseDevToolsURL(ctx context.Context, cmd command) (string, error) { //nolint: cyclop
185-
var (
186-
lines = make(chan string)
187-
errCh = make(chan error)
188-
)
184+
func parseDevToolsURL(ctx context.Context, cmd command) (_ string, err error) {
185+
parser := &devToolsURLParser{
186+
sc: bufio.NewScanner(cmd.stderr),
187+
}
188+
done := make(chan struct{})
189189
go func() {
190-
scanner := bufio.NewScanner(cmd.stderr)
191-
for scanner.Scan() {
192-
lines <- scanner.Text()
193-
}
194-
if err := scanner.Err(); err != nil {
195-
errCh <- err
190+
for parser.scan() {
196191
}
192+
close(done)
197193
}()
194+
for err == nil {
195+
select {
196+
case <-done:
197+
err = parser.err()
198+
case <-ctx.Done():
199+
err = ctx.Err()
200+
case <-cmd.done:
201+
err = errors.New("browser process ended unexpectedly")
202+
}
203+
}
204+
if parser.url != "" {
205+
err = nil
206+
}
207+
208+
return parser.url, err
209+
}
210+
211+
type devToolsURLParser struct {
212+
sc *bufio.Scanner
213+
214+
errs []error
215+
url string
216+
}
217+
218+
func (p *devToolsURLParser) scan() bool {
219+
if !p.sc.Scan() {
220+
return false
221+
}
198222

199223
const urlPrefix = "DevTools listening on "
200-
var stdErr error
201224

202-
preferStdErr := func(e error) error {
203-
if stdErr != nil {
204-
return stdErr
225+
line := p.sc.Text()
226+
if strings.HasPrefix(line, urlPrefix) {
227+
p.url = strings.TrimPrefix(strings.TrimSpace(line), urlPrefix)
228+
}
229+
if strings.Contains(line, ":ERROR:") {
230+
if i := strings.Index(line, "] "); i > 0 {
231+
p.errs = append(p.errs, errors.New(line[i+2:]))
205232
}
206-
return e
207233
}
208234

209-
for {
210-
select {
211-
case line := <-lines:
212-
if strings.HasPrefix(line, urlPrefix) {
213-
return strings.TrimPrefix(strings.TrimSpace(line), urlPrefix), nil
214-
}
215-
// TODO: Capture more than one error?
216-
if stdErr == nil && strings.Contains(line, ":ERROR:") {
217-
if i := strings.Index(line, "] "); i > 0 {
218-
stdErr = errors.New(line[i+2:])
219-
}
220-
}
221-
case err := <-errCh:
222-
return "", preferStdErr(err)
223-
case <-cmd.done:
224-
return "", preferStdErr(errors.New("browser process ended unexpectedly"))
225-
case <-ctx.Done():
226-
return "", preferStdErr(fmt.Errorf("%w", ctx.Err()))
227-
}
235+
return p.url == ""
236+
}
237+
238+
func (p *devToolsURLParser) err() error {
239+
if p.url != "" {
240+
return io.EOF
241+
}
242+
if len(p.errs) > 0 {
243+
return p.errs[0]
244+
}
245+
if err := p.sc.Err(); err != nil {
246+
return fmt.Errorf("%w", err)
228247
}
248+
return nil
229249
}

0 commit comments

Comments
 (0)