class Rack::RPC::Endpoint::JSONRPC::Server

@see groups.google.com/group/json-rpc/web/json-rpc-2-0

Public Class Methods

new(server, options = {}) click to toggle source

@param [Rack::RPC::Server] server @param [Hash{Symbol => Object}] options

# File lib/rack/rpc/endpoint/jsonrpc.rb, line 17
def initialize(server, options = {})
  @server, @options = server, options.dup
end

Public Instance Methods

execute(request) click to toggle source

@param [Rack::Request] request @return [Rack::Response]

# File lib/rack/rpc/endpoint/jsonrpc.rb, line 24
def execute(request)
  # Store the request so that it can be accessed from the server methods:
  @server.request = request if @server.respond_to?(:request=)

  request_body = request.body.read
  request_body.force_encoding(Encoding::UTF_8) if request_body.respond_to?(:force_encoding) # Ruby 1.9+

  Rack::Response.new([process(request_body, request)], 200, {
    'Content-Type' => (request.content_type || CONTENT_TYPE).to_s,
  })
end
process(input, context = nil) click to toggle source

@param [String] input @param [Object] context @return [String]

# File lib/rack/rpc/endpoint/jsonrpc.rb, line 40
def process(input, context = nil)
  response = nil
  begin
    response = case (json = JSON.parse(input))
      when Array then process_batch(json, context)
      when Hash  then process_request(json, context)
    end
  rescue JSON::ParserError => exception
    response = JSONRPC::Response.new
    response.error = JSONRPC::ParseError.new(:message => exception.to_s)
  end
  response.to_json + "\n"
end
process_batch(batch, context = nil) click to toggle source

@param [Array<Hash>] batch @param [Object] context @return [Array]

# File lib/rack/rpc/endpoint/jsonrpc.rb, line 58
def process_batch(batch, context = nil)
  batch.map { |struct| process_request(struct, context) }
end
process_request(struct, context = nil) click to toggle source

@param [Hash] struct @param [Object] context @return [Hash]

# File lib/rack/rpc/endpoint/jsonrpc.rb, line 66
def process_request(struct, context = nil)
  response = JSONRPC::Response.new
  begin
    request = JSONRPC::Request.new(struct, context)
    response.id = request.id

    raise ::TypeError, "invalid JSON-RPC request" unless request.valid?

    case operator = @server.class[request.method]
      when nil
        raise ::NoMethodError, "undefined operation `#{request.method}'"
      when Class # a Rack::RPC::Operation subclass
        response.result = operator.new(request).execute
      else
        response.result = @server.__send__(operator, *request.params)
    end

  rescue ::TypeError => exception # FIXME
    response.error = JSONRPC::ClientError.new(:message => exception.to_s)

  rescue ::NoMethodError => exception
    response.error = JSONRPC::NoMethodError.new(:message => exception.to_s)

  rescue ::ArgumentError => exception
    response.error = JSONRPC::ArgumentError.new(:message => exception.to_s)

  rescue ::Rack::RPC::Error => exception
    response.error = JSONRPC::Error.new(:message => exception.to_s,
                                        :code => exception.code,
                                        :data => exception.data)

  rescue => exception
    response.error = JSONRPC::InternalError.new(:message => exception.to_s)
  end

  response.to_hash.delete_if { |k, v| v.nil? }
end