Class: Capybara::Apparition::Browser::Launcher

Inherits:
Object
  • Object
show all
Defined in:
lib/capybara/apparition/driver/launcher.rb

Constant Summary collapse

KILL_TIMEOUT =
5

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(headless:, **options) ⇒ Launcher

Returns a new instance of Launcher.



37
38
39
40
41
42
43
44
45
# File 'lib/capybara/apparition/driver/launcher.rb', line 37

def initialize(headless:, **options)
  @path = ENV['BROWSER_PATH']
  @options = DEFAULT_OPTIONS.merge(options[:browser_options] || {})
  if headless
    @options.merge!(HEADLESS_OPTIONS)
    @options['disable-gpu'] = nil if Capybara::Apparition.windows?
  end
  @options['user-data-dir'] = Dir.mktmpdir
end

Class Method Details

.process_killer(pid) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/capybara/apparition/driver/launcher.rb', line 14

def self.process_killer(pid)
  proc do
    begin
      sleep 1
      if Capybara::Apparition.windows?
        ::Process.kill('KILL', pid)
      else
        ::Process.kill('USR1', pid)
        timer = Capybara::Helpers.timer(expire_in: KILL_TIMEOUT)
        while ::Process.wait(pid, ::Process::WNOHANG).nil?
          sleep 0.05
          next unless timer.expired?

          ::Process.kill('KILL', pid)
          ::Process.wait(pid)
          break
        end
      end
    rescue Errno::ESRCH, Errno::ECHILD # rubocop:disable Lint/SuppressedException
    end
  end
end

.start(*args, **options) ⇒ Object



10
11
12
# File 'lib/capybara/apparition/driver/launcher.rb', line 10

def self.start(*args, **options)
  new(*args, **options).tap(&:start)
end

Instance Method Details

#hostObject



80
81
82
# File 'lib/capybara/apparition/driver/launcher.rb', line 80

def host
  @host ||= ws_url.host
end

#portObject



84
85
86
# File 'lib/capybara/apparition/driver/launcher.rb', line 84

def port
  @port ||= ws_url.port
end

#restartObject



75
76
77
78
# File 'lib/capybara/apparition/driver/launcher.rb', line 75

def restart
  stop
  start
end

#startObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/capybara/apparition/driver/launcher.rb', line 47

def start
  @output = Queue.new

  process_options = {}
  process_options[:pgroup] = true unless Capybara::Apparition.windows?
  cmd = [path] + @options.map { |k, v| v.nil? ? "--#{k}" : "--#{k}=#{v}" }

  stdin, @stdout_stderr, wait_thr = Open3.popen2e(*cmd, process_options)
  stdin.close

  @pid = wait_thr.pid

  @out_thread = Thread.new do
    while !@stdout_stderr.eof? && (data = @stdout_stderr.readpartial(512))
      @output << data
    end
  end

  ObjectSpace.define_finalizer(self, self.class.process_killer(@pid))
end

#stopObject



68
69
70
71
72
73
# File 'lib/capybara/apparition/driver/launcher.rb', line 68

def stop
  return unless @pid

  kill
  ObjectSpace.undefine_finalizer(self)
end

#ws_urlObject



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/capybara/apparition/driver/launcher.rb', line 88

def ws_url
  @ws_url ||= begin
    regexp = %r{DevTools listening on (ws://.*)}
    url = nil

    sleep 3
    loop do
      break if (url = @output.pop.scan(regexp)[0])
    end
    @out_thread.kill
    @out_thread.join # wait for thread to end before closing io
    close_io
    Addressable::URI.parse(url[0])
  end
end