class Selenium::WebDriver::DevTools
Constants
- RESPONSE_WAIT_INTERVAL
- RESPONSE_WAIT_TIMEOUT
Public Class Methods
new(url:)
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 33 def initialize(url:) @callback_threads = ThreadGroup.new @messages = [] @session_id = nil @url = url process_handshake @socket_thread = attach_socket_listener start_session end
Public Instance Methods
callbacks()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 51 def callbacks @callbacks ||= Hash.new { |callbacks, event| callbacks[event] = [] } end
close()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 45 def close @callback_threads.list.each(&:exit) @socket_thread.exit socket.close end
method_missing(method, *_args)
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 74 def method_missing(method, *_args) desired_class = "Selenium::DevTools::V#{Selenium::DevTools.version}::#{method.capitalize}" return unless Object.const_defined?(desired_class) self.class.class_eval do define_method(method) do Object.const_get(desired_class).new(self) end end send(method) end
respond_to_missing?(method, *_args)
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 87 def respond_to_missing?(method, *_args) desired_class = "Selenium::DevTools::V#{Selenium::DevTools.version}::#{method.capitalize}" Object.const_defined?(desired_class) end
send_cmd(method, **params)
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 55 def send_cmd(method, **params) id = next_id data = {id: id, method: method, params: params.reject { |_, v| v.nil? }} data[:sessionId] = @session_id if @session_id data = JSON.generate(data) WebDriver.logger.debug "DevTools -> #{data}" out_frame = WebSocket::Frame::Outgoing::Client.new(version: ws.version, data: data, type: 'text') socket.write(out_frame.to_s) message = wait.until do @messages.find { |m| m['id'] == id } end raise Error::WebDriverError, error_message(message['error']) if message['error'] message end
Private Instance Methods
attach_socket_listener()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 99 def attach_socket_listener Thread.new do Thread.current.abort_on_exception = true Thread.current.report_on_exception = false until socket.eof? incoming_frame << socket.readpartial(1024) while (frame = incoming_frame.next) message = process_frame(frame) next unless message['method'] params = message['params'] callbacks[message['method']].each do |callback| @callback_threads.add(callback_thread(params, &callback)) end end end end end
callback_thread(params) { |params| ... }
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 144 def callback_thread(params) Thread.new do Thread.current.abort_on_exception = true # We might end up blocked forever when we have an error in event. # For example, if network interception event raises error, # the browser will keep waiting for the request to be proceeded # before returning back to the original thread. In this case, # we should at least print the error. Thread.current.report_on_exception = true yield params end end
error_message(error)
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 187 def error_message(error) [error['code'], error['message'], error['data']].join(': ') end
incoming_frame()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 127 def incoming_frame @incoming_frame ||= WebSocket::Frame::Incoming::Client.new(version: ws.version) end
next_id()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 182 def next_id @id ||= 0 @id += 1 end
process_frame(frame)
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 131 def process_frame(frame) message = frame.to_s # Firefox will periodically fail on unparsable empty frame return {} if message.empty? message = JSON.parse(message) @messages << message WebDriver.logger.debug "DevTools <- #{message}" message end
process_handshake()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 94 def process_handshake socket.print(ws.to_s) ws << socket.readpartial(1024) end
socket()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 163 def socket @socket ||= begin if URI(@url).scheme == 'wss' socket = TCPSocket.new(ws.host, ws.port) socket = OpenSSL::SSL::SSLSocket.new(socket, OpenSSL::SSL::SSLContext.new) socket.sync_close = true socket.connect socket else TCPSocket.new(ws.host, ws.port) end end end
start_session()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 120 def start_session targets = target.get_targets.dig('result', 'targetInfos') page_target = targets.find { |target| target['type'] == 'page' } session = target.attach_to_target(target_id: page_target['targetId'], flatten: true) @session_id = session.dig('result', 'sessionId') end
wait()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 159 def wait @wait ||= Wait.new(timeout: RESPONSE_WAIT_TIMEOUT, interval: RESPONSE_WAIT_INTERVAL) end
ws()
click to toggle source
# File lib/selenium/webdriver/devtools.rb, line 178 def ws @ws ||= WebSocket::Handshake::Client.new(url: @url) end