fork download
  1. #!/usr/bin/env ruby
  2. # -*- coding: utf-8 -*-
  3. require 'json'
  4.  
  5. module RPC
  6. class InvalidRequestError < StandardError; end
  7. class UndefinedMethodError < StandardError; end
  8.  
  9. class Request
  10. attr_reader :method, :params, :id
  11.  
  12. def initialize(method, *args)
  13. options = args.last.is_a?(Hash) ? args.pop : {}
  14. @method = method
  15. @params = args
  16. @id = options[:id]
  17. end
  18.  
  19. def to_json
  20. JSON.dump({:method => @method, :params => @params, :id => @id})
  21. end
  22.  
  23. def self.parse(str)
  24. json = JSON.parse(str) rescue {}
  25. method, params, id = json.values_at('method', 'params', 'id')
  26. raise InvalidRequestError if method.nil?
  27. self.new(method, *(params || []), :id => id)
  28. end
  29. end
  30.  
  31. class Response
  32. attr_reader :result, :error, :id
  33.  
  34. def initialize(result, *args)
  35. options = args.last.is_a?(Hash) ? args.pop : {}
  36. @result = result
  37. @error = nil
  38. @result, @error = @error, @result if options[:error]
  39. @id = options[:id]
  40. end
  41.  
  42. def to_json
  43. JSON.dump({:result => @result, :error => @error, :id => @id})
  44. end
  45. end
  46.  
  47. module Receiver
  48. def self.included(base)
  49. base.send :include, InstanceMethods
  50. base.send :extend, ClassMethods
  51. end
  52.  
  53. module ClassMethods
  54. def attr_rpc(*methods)
  55. methods.each do |method|
  56. rpc_methods << method.to_s
  57. end
  58. rpc_methods.uniq!
  59. end
  60.  
  61. def rpc_methods
  62. @rpc_methods ||= []
  63. end
  64. end
  65.  
  66. module InstanceMethods
  67. def process_request(data)
  68. begin
  69. request = Request.parse(data)
  70. raise UndefinedMethodError unless self.class.rpc_methods.include?(request.method)
  71. id = request.id
  72. result = self.send(request.method, *request.params)
  73. error = false
  74. rescue => e
  75. id = nil
  76. result = e.to_s
  77. error = true
  78. ensure
  79. return Response.new(result, :id => id, :error => error)
  80. end
  81. end
  82. end
  83. end
  84. end
  85.  
  86. class Server
  87. include RPC::Receiver
  88. attr_rpc :mul
  89.  
  90. def mul(a, b)
  91. a.to_i * b.to_i
  92. end
  93. end
  94.  
  95. server = Server.new
  96. req = RPC::Request.new('mul', 3, 4, :id => Time.now.to_i)
  97. puts req.to_json
  98. res = server.process_request(req.to_json)
  99. puts res.to_json
Success #stdin #stdout 0.01s 5156KB
stdin
Standard input is empty
stdout
{"method":"mul","params":[3,4],"id":1320144764}
{"result":12,"error":null,"id":1320144764}