Class: Capybara::Chrome::RDPClient
- Inherits:
-
Object
- Object
- Capybara::Chrome::RDPClient
- Includes:
- Debug
- Defined in:
- lib/capybara/chrome/rdp_client.rb
Overview
Chrome Remote Debugging Protocol (RDP) Client
Instance Attribute Summary collapse
-
#browser ⇒ Object
readonly
Returns the value of attribute browser.
-
#handler_calls ⇒ Object
readonly
Returns the value of attribute handler_calls.
-
#handlers ⇒ Object
readonly
Returns the value of attribute handlers.
-
#listen_mutex ⇒ Object
readonly
Returns the value of attribute listen_mutex.
-
#loader_ids ⇒ Object
readonly
Returns the value of attribute loader_ids.
-
#response_events ⇒ Object
readonly
Returns the value of attribute response_events.
-
#response_messages ⇒ Object
readonly
Returns the value of attribute response_messages.
-
#ws ⇒ Object
readonly
Returns the value of attribute ws.
Instance Method Summary collapse
- #discover_ws_url ⇒ Object
- #generate_unique_id ⇒ Object
-
#initialize(chrome_host:, chrome_port:, browser:) ⇒ RDPClient
constructor
A new instance of RDPClient.
- #on(event_name, &block) ⇒ Object
- #process_messages ⇒ Object
- #read_and_process(timeout = 0) ⇒ Object
- #recover_chrome_crash ⇒ Object
- #reset ⇒ Object
-
#send_cmd(command, params = {}) ⇒ Object
Errno::EPIPE.
- #send_cmd!(command, params = {}) ⇒ Object
- #send_msg(msg) ⇒ Object
- #start ⇒ Object
- #wait_for(event_name, timeout = Capybara.default_max_wait_time) ⇒ Object
Methods included from Debug
Constructor Details
#initialize(chrome_host:, chrome_port:, browser:) ⇒ RDPClient
Returns a new instance of RDPClient.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/capybara/chrome/rdp_client.rb', line 11 def initialize(chrome_host:, chrome_port:, browser:) @chrome_host = chrome_host @chrome_port = chrome_port @browser = browser @last_id = 0 @ws = nil @ws_thread = nil @ws_mutex = Mutex.new @handlers = Hash.new { |hash, key| hash[key] = [] } @listen_mutex = Mutex.new @response_messages = {} @response_events = [] @read_mutex = Mutex.new @handler_mutex = Mutex.new @loader_ids = [] @handler_calls = [] end |
Instance Attribute Details
#browser ⇒ Object (readonly)
Returns the value of attribute browser.
9 10 11 |
# File 'lib/capybara/chrome/rdp_client.rb', line 9 def browser @browser end |
#handler_calls ⇒ Object (readonly)
Returns the value of attribute handler_calls.
9 10 11 |
# File 'lib/capybara/chrome/rdp_client.rb', line 9 def handler_calls @handler_calls end |
#handlers ⇒ Object (readonly)
Returns the value of attribute handlers.
9 10 11 |
# File 'lib/capybara/chrome/rdp_client.rb', line 9 def handlers @handlers end |
#listen_mutex ⇒ Object (readonly)
Returns the value of attribute listen_mutex.
9 10 11 |
# File 'lib/capybara/chrome/rdp_client.rb', line 9 def listen_mutex @listen_mutex end |
#loader_ids ⇒ Object (readonly)
Returns the value of attribute loader_ids.
9 10 11 |
# File 'lib/capybara/chrome/rdp_client.rb', line 9 def loader_ids @loader_ids end |
#response_events ⇒ Object (readonly)
Returns the value of attribute response_events.
9 10 11 |
# File 'lib/capybara/chrome/rdp_client.rb', line 9 def response_events @response_events end |
#response_messages ⇒ Object (readonly)
Returns the value of attribute response_messages.
9 10 11 |
# File 'lib/capybara/chrome/rdp_client.rb', line 9 def @response_messages end |
#ws ⇒ Object (readonly)
Returns the value of attribute ws.
9 10 11 |
# File 'lib/capybara/chrome/rdp_client.rb', line 9 def ws @ws end |
Instance Method Details
#discover_ws_url ⇒ Object
177 178 179 180 181 182 |
# File 'lib/capybara/chrome/rdp_client.rb', line 177 def discover_ws_url response = open("http://#{@chrome_host}:#{@chrome_port}/json") data = JSON.parse(response.read) first_page = data.detect {|e| e["type"] == "page"} @ws_url = first_page["webSocketDebuggerUrl"] end |
#generate_unique_id ⇒ Object
36 37 38 |
# File 'lib/capybara/chrome/rdp_client.rb', line 36 def generate_unique_id @last_id += 1 end |
#on(event_name, &block) ⇒ Object
99 100 101 |
# File 'lib/capybara/chrome/rdp_client.rb', line 99 def on(event_name, &block) handlers[event_name] << block end |
#process_messages ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/capybara/chrome/rdp_client.rb', line 135 def n = 0 while @ws..any? do n += 1 msg_raw = @ws..shift if msg_raw msg = JSON.parse(msg_raw) if msg["method"] hs = handlers[msg["method"]] if hs.any? @handler_calls << [msg["method"], msg["params"]] end @response_events << msg else @response_messages[msg["id"]] = msg if msg["exceptionDetails"] puts JSException.new(val["exceptionDetails"]["exception"].inspect) end end else p ["no msg_raw", msg_raw] end end n end |
#read_and_process(timeout = 0) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/capybara/chrome/rdp_client.rb', line 161 def read_and_process(timeout=0) return unless Thread.current == Thread.main ready = select [@ws.socket.io], [], [], timeout if ready @ws.parse_input end if !@calling_handlers @calling_handlers = true while obj = @handler_calls.shift do handlers[obj[0]].each {|h| h.call obj[1]} end @calling_handlers = false end end |
#recover_chrome_crash ⇒ Object
80 81 82 83 84 |
# File 'lib/capybara/chrome/rdp_client.rb', line 80 def recover_chrome_crash $stderr.puts "Chrome Crashed... #{Capybara::Chrome.wants_to_quit.inspect} #{::RSpec.wants_to_quit.inspect}" unless Capybara::Chrome.wants_to_quit browser.restart_chrome browser.start_remote end |
#reset ⇒ Object
29 30 31 32 33 34 |
# File 'lib/capybara/chrome/rdp_client.rb', line 29 def reset @calling_handlers = false .clear response_events.clear loader_ids.clear end |
#send_cmd(command, params = {}) ⇒ Object
Errno::EPIPE
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/capybara/chrome/rdp_client.rb', line 48 def send_cmd(command, params={}) msg_id = send_cmd!(command, params) debug "waiting #{command} #{msg_id}" msg = nil begin until msg = @response_messages[msg_id] read_and_process(1) end @response_messages.delete msg_id rescue Timeout::Error puts "TimeoutError #{command} #{params.inspect} #{msg_id}" send_cmd! "Runtime.terminateExecution" puts "Recovering" recover_chrome_crash raise ResponseTimeoutError rescue WebSocketError => e puts "send_cmd received websocket error #{e.inspect}" recover_chrome_crash raise e rescue Errno::EPIPE, EOFError => e puts "send_cmd received EPIPE or EOF error #{e.inspect}" recover_chrome_crash raise e rescue => e puts "send_cmd caught error #{e.inspect} when issuing #{command} #{params.inspect}" puts caller raise e end return msg["result"] end |
#send_cmd!(command, params = {}) ⇒ Object
40 41 42 43 44 45 |
# File 'lib/capybara/chrome/rdp_client.rb', line 40 def send_cmd!(command, params={}) debug command, params msg_id = generate_unique_id send_msg({method: command, params: params, id: msg_id}.to_json) msg_id end |
#send_msg(msg) ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/capybara/chrome/rdp_client.rb', line 86 def send_msg(msg) retries ||= 0 ws.send_msg(msg) rescue Errno::EPIPE, EOFError => exception retries += 1 recover_chrome_crash if retries < 5 && !::Capybara::Chrome.wants_to_quit retry else raise exception end end |
#start ⇒ Object
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/capybara/chrome/rdp_client.rb', line 184 def start browser.wait_for_chrome browser.with_retry do discover_ws_url end @ws = RDPWebSocketClient.new @ws_url send_cmd! "Network.enable" send_cmd! "Network.clearBrowserCookies" send_cmd! "Page.enable" send_cmd! "DOM.enable" send_cmd! "CSS.enable" send_cmd! "Page.setDownloadBehavior", behavior: "allow", downloadPath: Capybara::Chrome.configuration.download_path helper_js = File.(File.join("..", "..", "chrome_remote_helper.js"), File.dirname(__FILE__)) send_cmd! "Page.addScriptToEvaluateOnNewDocument", source: File.read(helper_js) Thread.abort_on_exception = true return end |
#wait_for(event_name, timeout = Capybara.default_max_wait_time) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/capybara/chrome/rdp_client.rb', line 103 def wait_for(event_name, timeout=Capybara.default_max_wait_time) @response_events.clear msg = nil loop do msgs = @response_events.select {|v| v["method"] == event_name} if msgs.any? if block_given? do_return = msgs.detect do |m| val = yield m["params"] end if do_return msg = do_return.dup @response_events.delete do_return break else read_and_process(1) next end else msg = msgs.first.dup msgs.each {|m| @response_events.delete m} break end else end read_and_process(1) end return msg && msg["params"] rescue Timeout::Error nil end |