class Ferrum::Browser::Process
Constants
- KILL_TIMEOUT
- PROCESS_TIMEOUT
- WAIT_KILLED
Attributes
browser_version[R]
command[R]
default_user_agent[R]
host[R]
pid[R]
port[R]
protocol_version[R]
v8_version[R]
webkit_version[R]
ws_url[R]
xvfb[R]
Public Class Methods
directory_remover(path)
click to toggle source
# File lib/ferrum/browser/process.rb, line 54 def self.directory_remover(path) proc { FileUtils.remove_entry(path) rescue Errno::ENOENT } end
new(options)
click to toggle source
# File lib/ferrum/browser/process.rb, line 58 def initialize(options) if options[:url] url = URI.join(options[:url].to_s, "/json/version") response = JSON.parse(::Net::HTTP.get(url)) set_ws_url(response["webSocketDebuggerUrl"]) parse_browser_versions return end @pid = @xvfb = @user_data_dir = nil @logger = options[:logger] @process_timeout = options.fetch(:process_timeout, PROCESS_TIMEOUT) tmpdir = Dir.mktmpdir("ferrum_user_data_dir_") ObjectSpace.define_finalizer(self, self.class.directory_remover(tmpdir)) @user_data_dir = tmpdir @command = Command.build(options, tmpdir) end
process_killer(pid)
click to toggle source
# File lib/ferrum/browser/process.rb, line 33 def self.process_killer(pid) proc do begin if Ferrum.windows? ::Process.kill("KILL", pid) else ::Process.kill("USR1", pid) start = Ferrum.monotonic_time while ::Process.wait(pid, ::Process::WNOHANG).nil? sleep(WAIT_KILLED) next unless Ferrum.timeout?(start, KILL_TIMEOUT) ::Process.kill("KILL", pid) ::Process.wait(pid) break end end rescue Errno::ESRCH, Errno::ECHILD end end end
start(*args)
click to toggle source
# File lib/ferrum/browser/process.rb, line 29 def self.start(*args) new(*args).tap(&:start) end
Public Instance Methods
restart()
click to toggle source
# File lib/ferrum/browser/process.rb, line 113 def restart stop start end
start()
click to toggle source
# File lib/ferrum/browser/process.rb, line 77 def start # Don't do anything as browser is already running as external process. return if ws_url begin read_io, write_io = IO.pipe process_options = { in: File::NULL } process_options[:pgroup] = true unless Ferrum.windows? process_options[:out] = process_options[:err] = write_io if @command.xvfb? @xvfb = Xvfb.start(@command.options) ObjectSpace.define_finalizer(self, self.class.process_killer(@xvfb.pid)) end @pid = ::Process.spawn(Hash(@xvfb&.to_env), *@command.to_a, process_options) ObjectSpace.define_finalizer(self, self.class.process_killer(@pid)) parse_ws_url(read_io, @process_timeout) parse_browser_versions ensure close_io(read_io, write_io) end end
stop()
click to toggle source
# File lib/ferrum/browser/process.rb, line 102 def stop if @pid kill(@pid) kill(@xvfb.pid) if @xvfb&.pid @pid = nil end remove_user_data_dir if @user_data_dir ObjectSpace.undefine_finalizer(self) end
Private Instance Methods
close_io(*ios)
click to toggle source
# File lib/ferrum/browser/process.rb, line 172 def close_io(*ios) ios.each do |io| begin io.close unless io.closed? rescue IOError raise unless RUBY_ENGINE == "jruby" end end end
kill(pid)
click to toggle source
# File lib/ferrum/browser/process.rb, line 120 def kill(pid) self.class.process_killer(pid).call end
parse_browser_versions()
click to toggle source
# File lib/ferrum/browser/process.rb, line 159 def parse_browser_versions return unless ws_url.is_a?(Addressable::URI) version_url = URI.parse(ws_url.merge(scheme: "http", path: "/json/version")) response = JSON.parse(::Net::HTTP.get(version_url)) @v8_version = response["V8-Version"] @browser_version = response["Browser"] @webkit_version = response["WebKit-Version"] @default_user_agent = response["User-Agent"] @protocol_version = response["Protocol-Version"] end
parse_ws_url(read_io, timeout)
click to toggle source
# File lib/ferrum/browser/process.rb, line 129 def parse_ws_url(read_io, timeout) output = "" start = Ferrum.monotonic_time max_time = start + timeout regexp = /DevTools listening on (ws:\/\/.*)/ while (now = Ferrum.monotonic_time) < max_time begin output += read_io.read_nonblock(512) rescue IO::WaitReadable IO.select([read_io], nil, nil, max_time - now) else if output.match(regexp) set_ws_url(output.match(regexp)[1].strip) break end end end unless ws_url @logger.puts(output) if @logger raise ProcessTimeoutError.new(timeout, output) end end
remove_user_data_dir()
click to toggle source
# File lib/ferrum/browser/process.rb, line 124 def remove_user_data_dir self.class.directory_remover(@user_data_dir).call @user_data_dir = nil end
set_ws_url(url)
click to toggle source
# File lib/ferrum/browser/process.rb, line 153 def set_ws_url(url) @ws_url = Addressable::URI.parse(url) @host = @ws_url.host @port = @ws_url.port end