class DEBUGGER__::Session

def process_protocol_request req

def process_protocol_request req
  case req['method']
  when 'Debugger.stepOver', 'Debugger.stepInto', 'Debugger.stepOut', 'Debugger.resume', 'Debugger.enable'
    request_tc [:cdp, :backtrace, req]
  when 'Debugger.evaluateOnCallFrame'
    frame_id = req.dig('params', 'callFrameId')
    group = req.dig('params', 'objectGroup')
    if fid = @frame_map[frame_id]
      expr = req.dig('params', 'expression')
      request_tc [:cdp, :evaluate, req, fid, expr, group]
    else
      fail_response req,
                    code: INVALID_PARAMS,
                    message: "'callFrameId' is an invalid"
    end
  when 'Runtime.getProperties', 'Runtime.getExceptionDetails'
    oid = req.dig('params', 'objectId') || req.dig('params', 'errorObjectId')
    if ref = @obj_map[oid]
      case ref[0]
      when 'local'
        frame_id = ref[1]
        fid = @frame_map[frame_id]
        request_tc [:cdp, :scope, req, fid]
      when 'global'
        vars = safe_global_variables.sort.map do |name|
          begin
            gv = eval(name.to_s)
          rescue Errno::ENOENT
            gv = nil
          end
          prop = {
            name: name,
            value: {
              description: gv.inspect
            },
            configurable: true,
            enumerable: true
          }
          type, subtype = get_type(gv)
          prop[:value][:type] = type
          prop[:value][:subtype] = subtype if subtype
          prop
        end
        @ui.respond req, result: vars
        return :retry
      when 'properties'
        request_tc [:cdp, :properties, req, oid]
      when 'exception'
        request_tc [:cdp, :exception, req, oid]
      when 'script'
        # TODO: Support script and global types
        @ui.respond req, result: []
        return :retry
      else
        raise "Unknown type: #{ref.inspect}"
      end
    else
      fail_response req,
                    code: INVALID_PARAMS,
                    message: "'objectId' is an invalid"
    end
  when 'Debugger.getScriptSource'
    s_id = req.dig('params', 'scriptId')
    if src = @src_map[s_id]
      @ui.respond req, scriptSource: src
    else
      fail_response req,
                    code: INVALID_PARAMS,
                    message: "'scriptId' is an invalid"
    end
    return :retry
  when 'Debugger.getPossibleBreakpoints'
    s_id = req.dig('params', 'start', 'scriptId')
    if src = @src_map[s_id]
      lineno = req.dig('params', 'start', 'lineNumber')
      end_line = src.lines.count
      lineno = end_line  if lineno > end_line
      @ui.respond req,
                  locations: [{
                    scriptId: s_id,
                    lineNumber: lineno
                  }]
    else
      fail_response req,
                    code: INVALID_PARAMS,
                    message: "'scriptId' is an invalid"
    end
    return :retry
  when 'Debugger.setBreakpointByUrl'
    path = req.dig('params', 'scriptId')
    if s_id = @scr_id_map[path]
      lineno = req.dig('params', 'lineNumber')
      b_id = req.dig('params', 'breakpointId')
      @ui.respond req,
                  breakpointId: b_id,
                  locations: [{
                      scriptId: s_id,
                      lineNumber: lineno
                  }]
    else
      fail_response req,
                    code: INTERNAL_ERROR,
                    message: 'The target script is not found...'
    end
    return :retry
  end
end