class DEBUGGER__::ThreadClient

def process_cdp args

def process_cdp args
  type = args.shift
  req = args.shift
  case type
  when :backtrace
    exception = nil
    result = {
      reason: 'other',
      callFrames: @target_frames.map.with_index{|frame, i|
        exception = frame.raised_exception if frame == current_frame && frame.has_raised_exception
        path = frame.realpath || frame.path
        if frame.iseq.nil?
          lineno = 0
        else
          lineno = frame.iseq.first_line - 1
        end
        {
          callFrameId: SecureRandom.hex(16),
          functionName: frame.name,
          functionLocation: {
            # scriptId: N, # filled by SESSION
            lineNumber: lineno
          },
          location: {
            # scriptId: N, # filled by SESSION
            lineNumber: frame.location.lineno - 1 # The line number is 0-based.
          },
          url: path,
          scopeChain: [
            {
              type: 'local',
              object: {
                type: 'object',
                objectId: rand.to_s
              }
            },
            {
              type: 'script',
              object: {
                type: 'object',
                objectId: rand.to_s
              }
            },
            {
              type: 'global',
              object: {
                type: 'object',
                objectId: rand.to_s
              }
            }
          ],
          this: {
            type: 'object'
          }
        }
      }
    }
    if exception
      result[:data] = evaluate_result exception
      result[:reason] = 'exception'
    end
    event! :protocol_result, :backtrace, req, result
  when :evaluate
    res = {}
    fid, expr, group = args
    frame = @target_frames[fid]
    message = nil
    if frame && (b = frame.eval_binding)
      special_local_variables frame do |name, var|
        b.local_variable_set(name, var) if /\%/ !~name
      end
      result = nil
      case group
      when 'popover'
        case expr
        # Chrome doesn't read instance variables
        when /\A\$\S/
          safe_global_variables.each{|gvar|
            if gvar.to_s == expr
              result = eval(gvar.to_s)
              break false
            end
          } and (message = "Error: Not defined global variable: #{expr.inspect}")
        when /(\A((::[A-Z]|[A-Z])\w*)+)/
          unless result = search_const(b, $1)
            message = "Error: Not defined constant: #{expr.inspect}"
          end
        else
          begin
            result = b.local_variable_get(expr)
          rescue NameError
            # try to check method
            if M_RESPOND_TO_P.bind_call(b.receiver, expr, include_all: true)
              result = M_METHOD.bind_call(b.receiver, expr)
            else
              message = "Error: Can not evaluate: #{expr.inspect}"
            end
          end
        end
      when 'console', 'watch-group'
        begin
          orig_stdout = $stdout
          $stdout = StringIO.new
          result = b.eval(expr.to_s, '(DEBUG CONSOLE)')
        rescue Exception => e
          result = e
          res[:exceptionDetails] = exceptionDetails(e, 'Uncaught')
        ensure
          output = $stdout.string
          $stdout = orig_stdout
        end
      else
        message = "Error: unknown objectGroup: #{group}"
      end
    else
      result = Exception.new("Error: Can not evaluate on this frame")
    end
    res[:result] = evaluate_result(result)
    event! :protocol_result, :evaluate, req, message: message, response: res, output: output
  when :scope
    fid = args.shift
    frame = @target_frames[fid]
    if b = frame.binding
      vars = b.local_variables.map{|name|
        v = b.local_variable_get(name)
        variable(name, v)
      }
      special_local_variables frame do |name, val|
        vars.unshift variable(name, val)
      end
      vars.unshift variable('%self', b.receiver)
    elsif lvars = frame.local_variables
      vars = lvars.map{|var, val|
        variable(var, val)
      }
    else
      vars = [variable('%self', frame.self)]
      special_local_variables frame do |name, val|
        vars.unshift variable(name, val)
      end
    end
    event! :protocol_result, :scope, req, vars
  when :properties
    oid = args.shift
    result = []
    prop = []
    if obj = @obj_map[oid]
      case obj
      when Array
        result = obj.map.with_index{|o, i|
          variable i.to_s, o
        }
      when Hash
        result = obj.map{|k, v|
          variable(k, v)
        }
      when Struct
        result = obj.members.map{|m|
          variable(m, obj[m])
        }
      when String
        prop = [
          internalProperty('#length', obj.length),
          internalProperty('#encoding', obj.encoding)
        ]
      when Class, Module
        result = obj.instance_variables.map{|iv|
          variable(iv, obj.instance_variable_get(iv))
        }
        prop = [internalProperty('%ancestors', obj.ancestors[1..])]
      when Range
        prop = [
          internalProperty('#begin', obj.begin),
          internalProperty('#end', obj.end),
        ]
      end
      result += M_INSTANCE_VARIABLES.bind_call(obj).map{|iv|
        variable(iv, M_INSTANCE_VARIABLE_GET.bind_call(obj, iv))
      }
      prop += [internalProperty('#class', M_CLASS.bind_call(obj))]
    end
    event! :protocol_result, :properties, req, result: result, internalProperties: prop
  when :exception
    oid = args.shift
    exc = nil
    if obj = @obj_map[oid]
      exc = exceptionDetails obj, obj.to_s
    end
    event! :protocol_result, :exception, req, exceptionDetails: exc
  end
end