NewFrameBufferWithOptions starts an X virtual frame buffer running in the background. FrameBufferOptions may be populated to change the behavior of the frame buffer.
(options FrameBufferOptions)
| 316 | // NewFrameBufferWithOptions starts an X virtual frame buffer running in the background. |
| 317 | // FrameBufferOptions may be populated to change the behavior of the frame buffer. |
| 318 | func NewFrameBufferWithOptions(options FrameBufferOptions) (*FrameBuffer, error) { |
| 319 | r, w, err := os.Pipe() |
| 320 | if err != nil { |
| 321 | return nil, err |
| 322 | } |
| 323 | defer r.Close() |
| 324 | |
| 325 | auth, err := ioutil.TempFile("", "selenium-xvfb") |
| 326 | if err != nil { |
| 327 | return nil, err |
| 328 | } |
| 329 | authPath := auth.Name() |
| 330 | if err := auth.Close(); err != nil { |
| 331 | return nil, err |
| 332 | } |
| 333 | |
| 334 | // Xvfb will print the display on which it is listening to file descriptor 3, |
| 335 | // for which we provide a pipe. |
| 336 | arguments := []string{"-displayfd", "3", "-nolisten", "tcp"} |
| 337 | if options.ScreenSize != "" { |
| 338 | var screenSizeExpression = regexp.MustCompile(`^\d+x\d+(?:x\d+)$`) |
| 339 | if !screenSizeExpression.MatchString(options.ScreenSize) { |
| 340 | return nil, fmt.Errorf("invalid screen size: expected 'WxH[xD]', got %q", options.ScreenSize) |
| 341 | } |
| 342 | arguments = append(arguments, "-screen", "0", options.ScreenSize) |
| 343 | } |
| 344 | xvfb := exec.Command("Xvfb", arguments...) |
| 345 | xvfb.ExtraFiles = []*os.File{w} |
| 346 | |
| 347 | // TODO(minusnine): plumb a way to set xvfb.Std{err,out} conditionally. |
| 348 | // TODO(minusnine): Pdeathsig is only supported on Linux. Somehow, make sure |
| 349 | // process cleanup happens as gracefully as possible. |
| 350 | xvfb.Env = append(xvfb.Env, "XAUTHORITY="+authPath) |
| 351 | if err := xvfb.Start(); err != nil { |
| 352 | return nil, err |
| 353 | } |
| 354 | w.Close() |
| 355 | |
| 356 | type resp struct { |
| 357 | display string |
| 358 | err error |
| 359 | } |
| 360 | ch := make(chan resp) |
| 361 | go func() { |
| 362 | bufr := bufio.NewReader(r) |
| 363 | s, err := bufr.ReadString('\n') |
| 364 | ch <- resp{s, err} |
| 365 | }() |
| 366 | |
| 367 | var display string |
| 368 | select { |
| 369 | case resp := <-ch: |
| 370 | if resp.err != nil { |
| 371 | return nil, resp.err |
| 372 | } |
| 373 | display = strings.TrimSpace(resp.display) |
| 374 | if _, err := strconv.Atoi(display); err != nil { |
| 375 | return nil, errors.New("Xvfb did not print the display number") |
searching dependent graphs…