Module: DEBUGGER__::UI_CDP
Relationships & Source Files | |
Namespace Children | |
Modules:
| |
Classes:
| |
Exceptions:
| |
Defined in: | lib/debug/server_cdp.rb |
Constant Summary
-
INVALID_REQUEST =
# File 'lib/debug/server_cdp.rb', line 328-32600
-
SHOW_PROTOCOL =
# File 'lib/debug/server_cdp.rb', line 13ENV['RUBY_DEBUG_CDP_SHOW_PROTOCOL'] == '1'
Class Method Summary
Instance Method Summary
- #activate_bp(bps)
- #cleanup_reader
- #deactivate_bp
- #del_bp(bps, k)
- #fire_event(event, **result)
- #get_source_code(path)
- #process
- #puts(result)
-
#readline(prompt)
Called by the SESSION thread.
- #respond(req, **result)
- #respond_fail(req, **result)
- #send_event(method, **params)
- #send_fail_response(req, **res)
- #send_response(req, **res)
- #sock(skip: false) {|$stderr| ... }
Class Method Details
.get_chrome_path
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 66
def get_chrome_path return CONFIG[:chrome_path] if CONFIG[:chrome_path] # The process to check OS is based on `selenium` project. case RbConfig::CONFIG['host_os'] when /mswin|msys|mingw|cygwin|emc/ 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe' when /darwin|mac os/ '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome' when /linux/ 'google-chrome' else raise "Unsupported OS" end end
.run_new_chrome
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 82
def run_new_chrome dir = Dir.mktmpdir # The command line flags are based on: https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Chrome_Desktop#connecting stdin, stdout, stderr, wait_thr = *Open3.popen3("#{get_chrome_path} --remote-debugging-port=0 --no-first-run --no-default-browser-check --user-data-dir=#{dir}") stdin.close stdout.close data = stderr.readpartial 4096 if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/ port = $1 path = $2 end stderr.close at_exit{ CONFIG[:skip_path] = [//] # skip all FileUtils.rm_rf dir } [port, path, wait_thr.pid] end
.setup_chrome(addr)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 16
def setup_chrome addr return if CONFIG[:chrome_path] == '' port, path, pid = run_new_chrome begin s = Socket.tcp '127.0.0.1', port rescue Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL return end ws_client = WebSocketClient.new(s) ws_client.handshake port, path ws_client.send id: 1, method: 'Target.getTargets' loop do res = ws_client.extract_data case when res['id'] == 1 && target_info = res.dig('result', 'targetInfos') page = target_info.find{|t| t['type'] == 'page'} ws_client.send id: 2, method: 'Target.attachToTarget', params: { targetId: page['targetId'], flatten: true } when res['id'] == 2 s_id = res.dig('result', 'sessionId') ws_client.send sessionId: s_id, id: 3, method: 'Page.enable' when res['id'] == 3 s_id = res['sessionId'] ws_client.send sessionId: s_id, id: 4, method: 'Page.getFrameTree' when res['id'] == 4 s_id = res['sessionId'] f_id = res.dig('result', 'frameTree', 'frame', 'id') ws_client.send sessionId: s_id, id: 5, method: 'Page.navigate', params: { url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{addr}/#{SecureRandom.uuid}", frameId: f_id } when res['method'] == 'Page.loadEventFired' break end end pid rescue Errno::ENOENT nil end
Instance Method Details
#activate_bp(bps)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 507
def activate_bp bps bps.each_key{|k| if k.match /^\d:(\d):(.*)/ line = $1 path = $2 SESSION.add_line_breakpoint(path, line.to_i + 1) else SESSION.add_catch_breakpoint 'Exception' end } end
#cleanup_reader
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 524
def cleanup_reader super Process.kill :KILL, @chrome_pid if @chrome_pid end
#deactivate_bp
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 519
def deactivate_bp @q_msg << 'del' @q_ans << 'y' end
#del_bp(bps, k)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 490
def del_bp bps, k return bps unless idx = bps[k] bps.delete k bps.each_key{|i| bps[i] -= 1 if bps[i] > idx} @q_msg << "del #{idx}" bps end
#fire_event(event, **result)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 545
def fire_event event, **result if result.empty? send_event event else send_event event, **result end end
#get_source_code(path)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 499
def get_source_code path return @src_map[path] if @src_map[path] src = File.read(path) @src_map[path] = src src end
#process
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 330
def process bps = {} @src_map = {} loop do req = @ws_server.extract_data case req['method'] ## boot/configuration when 'Debugger.getScriptSource' @q_msg << req when 'Debugger.enable' send_response req @q_msg << req when 'Runtime.enable' send_response req send_event 'Runtime.executionContextCreated', context: { id: SecureRandom.hex(16), origin: "http://#{@local_addr.inspect_sockaddr}", name: '' } when 'Runtime.getIsolateId' send_response req, id: SecureRandom.hex when 'Runtime.terminateExecution' send_response req exit when 'Page.startScreencast', 'Emulation.setTouchEmulationEnabled', 'Emulation.setEmitTouchEventsForMouse', 'Runtime.compileScript', 'Page.getResourceContent', 'Overlay.setPausedInDebuggerMessage', 'Runtime.releaseObjectGroup', 'Runtime.discardConsoleEntries', 'Log.clear', 'Runtime.runIfWaitingForDebugger' send_response req ## control when 'Debugger.resume' send_response req send_event 'Debugger.resumed' @q_msg << 'c' @q_msg << req when 'Debugger.stepOver' begin @session.check_postmortem send_response req send_event 'Debugger.resumed' @q_msg << 'n' rescue PostmortemError send_fail_response req, code: INVALID_REQUEST, message: "'stepOver' is not supported while postmortem mode" ensure @q_msg << req end when 'Debugger.stepInto' begin @session.check_postmortem send_response req send_event 'Debugger.resumed' @q_msg << 's' rescue PostmortemError send_fail_response req, code: INVALID_REQUEST, message: "'stepInto' is not supported while postmortem mode" ensure @q_msg << req end when 'Debugger.stepOut' begin @session.check_postmortem send_response req send_event 'Debugger.resumed' @q_msg << 'fin' rescue PostmortemError send_fail_response req, code: INVALID_REQUEST, message: "'stepOut' is not supported while postmortem mode" ensure @q_msg << req end when 'Debugger.setSkipAllPauses' skip = req.dig('params', 'skip') if skip deactivate_bp else activate_bp bps end send_response req # breakpoint when 'Debugger.getPossibleBreakpoints' @q_msg << req when 'Debugger.setBreakpointByUrl' line = req.dig('params', 'lineNumber') if regexp = req.dig('params', 'urlRegex') path = regexp.match(/(.*)\|/)[1].gsub("\\", "") cond = req.dig('params', 'condition') src = get_source_code path end_line = src.lines.count line = end_line if line > end_line b_id = "1:#{line}:#{regexp}" if cond != '' SESSION.add_line_breakpoint(path, line + 1, cond: cond) else SESSION.add_line_breakpoint(path, line + 1) end bps[b_id] = bps.size # Because we need to return scriptId, responses are returned in SESSION thread. req['params']['scriptId'] = path req['params']['lineNumber'] = line req['params']['breakpointId'] = b_id @q_msg << req elsif url = req.dig('params', 'url') b_id = "#{line}:#{url}" send_response req, breakpointId: b_id, locations: [] elsif hash = req.dig('params', 'scriptHash') b_id = "#{line}:#{hash}" send_response req, breakpointId: b_id, locations: [] else raise 'Unsupported' end when 'Debugger.removeBreakpoint' b_id = req.dig('params', 'breakpointId') bps = del_bp bps, b_id send_response req when 'Debugger.setBreakpointsActive' active = req.dig('params', 'active') if active activate_bp bps else deactivate_bp # TODO: Change this part because catch breakpoints should not be deactivated. end send_response req when 'Debugger.setPauseOnExceptions' state = req.dig('params', 'state') ex = 'Exception' case state when 'none' @q_msg << 'config postmortem = false' bps = del_bp bps, ex when 'uncaught' @q_msg << 'config postmortem = true' bps = del_bp bps, ex when 'all' @q_msg << 'config postmortem = false' SESSION.add_catch_breakpoint ex bps[ex] = bps.size end send_response req when 'Debugger.evaluateOnCallFrame', 'Runtime.getProperties' @q_msg << req end end rescue Detach @q_msg << 'continue' end
#puts(result)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 557
def puts result # STDERR.puts "puts: #{result}" # send_event 'output', category: 'stderr', output: "PUTS!!: " + result.to_s end
#readline(prompt)
Called by the SESSION thread
# File 'lib/debug/server_cdp.rb', line 531
def readline prompt return 'c' unless @q_msg @q_msg.pop || 'kill!' end
#respond(req, **result)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 537
def respond req, **result send_response req, **result end
#respond_fail(req, **result)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 541
def respond_fail req, **result send_fail_response req, **result end
#send_event(method, **params)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 320
def send_event method, **params if params.empty? @ws_server.send method: method, params: {} else @ws_server.send method: method, params: params end end
#send_fail_response(req, **res)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 316
def send_fail_response req, **res @ws_server.send id: req['id'], error: res end
#send_response(req, **res)
[ GitHub ]# File 'lib/debug/server_cdp.rb', line 308
def send_response req, **res if res.empty? @ws_server.send id: req['id'], result: {} else @ws_server.send id: req['id'], result: res end end
#sock(skip: false) {|$stderr| ... }
# File 'lib/debug/server_cdp.rb', line 553
def sock skip: false yield $stderr end