[OpenSocial][Rack] Rack で JSON-RPC を処理する。
OpenSocial の、ということに関していえば、それほど大変ではなかった。
config.ru にディスパッチルーチンをかく。
require 'rubygems' require 'json' require File.join(File.dirname(__FILE__), 'lib/service/system') # dispatch the rpc request def dispatch(rpc, req) service, method = rpc["method"].split(".") result = Service::System.apply(service, method, rpc["params"], req) # TODO # Currently shindig implementation required 'data' field, not 'result' field. # This should be changed. { "id" => rpc["id"], "data" => result } end run proc{|env| req = Rack::Request.new(env) begin if req.post? json = JSON.parse(req.body.read) if json.is_a?(Array) [200, {'Content-Type'=>'application/json'}, json.map { |rpc| dispatch(rpc, req) }.to_json ] else [200, {'Content-Type'=>'application/json'}, dispatch(json, req).to_json ] end else [405, {'Content-Type'=>'application/json'}, nil] end rescue => e [500, {'Content-Type'=>'application/json'}, {"error" => e.message, "trace" => e.backtrace}.to_json] end }
OpenSocial では system という名前のサービスで、対応するメソッド名などをリストしなければならないので、Service::System クラスにメソッドのsignatureを定義しておいて、Method#call で呼び出す方針にしたのであります。
具体的には Service::System#apply(service, method, params, request) で、"service.method" が提供されているかどうかをチェックし、params のHashを渡して呼び出す。ついでにoAuthのトークンがrequestオブジェクトに入っているはず(OpenSocial的には Authentication ヘッダー使えってかいてあるように使用が読めるんだが、Shindigだとst=xxxx でクエリにいれているような気がする)なので、Requestオブジェクトも渡してあげます。
# # OpenSocial system service # module Service class System # key valie pairs for available methods, # {service name => array of available methods} AVAILABLE_SERVICES = { :system => [:listMethods, :methodSignatures, :methodHelp], :people => [:get] } class << self # # A proxy method of available methods. This method should be for the dispach routine. # def apply(service, method, params, request) k = service.to_sym m = method.to_sym if AVAILABLE_SERVICES.has_key?(k) && AVAILABLE_SERVICES[k].include?(m) require File.join(File.dirname(__FILE__), service) klass_name = service[0,1].upcase + service[1..-1] klass = Service.const_get(klass_name) klass.method(m).call(params, request) else # TODO raise "not supported" end end end end end
これで、例えば、"people.get" であれば、Service::People.get にマップされるので、
require 'rubygems' require 'restclient' # # OpenSocial system service # module Service class People class << self def get(params={}, req = nil) # ここにCouchDBのView呼び出しの実装をかく { "name" => "Jane Doe", "displayName" => "Jone Doe", "gender" => "female", "id" => "example.org:34KJDCSKJN2HHF0DW20394" } end end end end
ということになります。
それはともかく、ここから先はoAuthしらないと実装できなさそうなので、しばし勉強モードです。