json-rpc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ Json Rpc
2
+ ========
3
+
4
+ Implementation of [JSON RPC 2.0](http://groups.google.com/group/json-rpc/web/json-rpc-2-0) protocol.
5
+ It allows you to create easily json rpc server.
6
+
7
+ Usage
8
+ -----
9
+
10
+ Simple Rack example:
11
+
12
+ ~~~~~~ {ruby}
13
+ require 'json-rpc'
14
+
15
+ class SyncApp
16
+ include JsonRpc
17
+ def call env
18
+ result = dispatch(env) { |e|
19
+ logger.info "#{e}"
20
+ }
21
+ result
22
+ end
23
+
24
+ def rpc_sum a, b
25
+ a + b
26
+ end
27
+ end
28
+ run SyncApp.new
29
+ ~~~~~~
30
+
31
+ Asynchronous Event Machine example:
32
+
33
+ ~~~~~~ {ruby}
34
+ require 'json-rpc'
35
+
36
+ class AsyncApp
37
+ include JsonRpc
38
+ AsyncResponse = [-1, {}, []].freeze
39
+ def call env
40
+ result = dispatch(env)
41
+ env['async.callback'].call result
42
+ AsyncResponse
43
+ end
44
+
45
+ def rpc_sum a, b
46
+ result = Rpc::AsyncResult.new
47
+ EventMachine::next_tick do
48
+ result.reply a + b
49
+ result.succeed
50
+ end
51
+ result
52
+ end
53
+ end
54
+ ~~~~~~
55
+
56
+ ### License
57
+ Copyright 2011 [Helios Technologies Ltd.](http://www.heliostech.hk)
58
+
59
+ Licensed under the Apache License, Version 2.0 (the "License");
60
+ you may not use this file except in compliance with the License.
61
+ You may obtain a copy of the License at
62
+
63
+ http://www.apache.org/licenses/LICENSE-2.0
64
+
65
+ Unless required by applicable law or agreed to in writing, software
66
+ distributed under the License is distributed on an "AS IS" BASIS,
67
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
68
+ See the License for the specific language governing permissions and
69
+ limitations under the License.
@@ -0,0 +1,28 @@
1
+ # -*- RUBY -*-
2
+ $: << File::join(File::dirname(__FILE__), "..", "lib")
3
+ require 'json-rpc'
4
+
5
+ class AsyncApp
6
+ include JsonRpc
7
+
8
+ AsyncResponse = [-1, {}, []].freeze
9
+
10
+ def call env
11
+ result = dispatch(env) { |e|
12
+ puts "#{e} backtrace: #{e.backtrace.join "\n"}"
13
+ }
14
+ env['async.callback'].call result
15
+ AsyncResponse
16
+ end
17
+
18
+ def rpc_sum a, b
19
+ result = Rpc::AsyncResult.new
20
+ EventMachine::next_tick do
21
+ result.reply a + b
22
+ result.succeed
23
+ end
24
+ result
25
+ end
26
+ end
27
+
28
+ run AsyncApp.new
@@ -0,0 +1,20 @@
1
+ # -*- RUBY -*-
2
+ $: << File::join(File::dirname(__FILE__), "..", "lib")
3
+ require 'json-rpc'
4
+
5
+ class SyncApp
6
+ include JsonRpc
7
+
8
+ def call env
9
+ result = dispatch(env) { |e|
10
+ logger.info "#{e} backtrace: #{e.backtrace.join "\n"}"
11
+ }
12
+ result
13
+ end
14
+
15
+ def rpc_sum a, b
16
+ a + b
17
+ end
18
+ end
19
+
20
+ run SyncApp.new
data/lib/json-rpc.rb ADDED
@@ -0,0 +1,127 @@
1
+ require 'json'
2
+ require 'eventmachine'
3
+ require 'uri'
4
+
5
+ module JsonRpc
6
+
7
+ # Call the correct method for each query
8
+ # The method should be prefixed by rpc_
9
+ # If the method doesn't exists, an error will be return in JSON
10
+ # More details in http://groups.google.com/group/json-rpc/web/json-rpc-2-0
11
+ def rpc_call env, &ecb
12
+ begin
13
+ request = Rpc::parse env
14
+ status = Rpc::validate request
15
+ result = Rpc::route request, self
16
+
17
+ rescue Rpc::Error => e
18
+ status = e.status
19
+ result = e.result
20
+ ecb.call(e) if ecb
21
+ end
22
+
23
+ [status, {'Content-Type' => Rpc::ContentType}, result]
24
+ end
25
+
26
+ module Rpc
27
+ Version = "2.0".freeze
28
+ Prefix = "rpc_".freeze
29
+ ContentType = "application/json".freeze
30
+
31
+ ErrorProtocol = {
32
+ :parse_error => [500, -32700, "Parse error"],
33
+ :invalid_request => [400, -32600, "Invalid Request"],
34
+ :method_not_found => [404, -32601, "Method not found"],
35
+ :invalid_params => [500, -32602, "Invalid params"],
36
+ :internal_error => [500, -32603, "Internal error"],
37
+ }
38
+
39
+ class Error < RuntimeError
40
+ attr_reader :status, :code, :msg
41
+ attr_accessor :id
42
+ def initialize status, code, msg
43
+ @status, @code, @msg = status, code, msg
44
+ end
45
+ def result
46
+ res = {"jsonrpc" => "2.0", "id" => id,
47
+ "error" => {"code" => code, "message" => msg}
48
+ }
49
+ res.delete_if { |k, v| v == nil}
50
+ res.to_json
51
+ end
52
+ end
53
+
54
+ def self.error index, id = nil
55
+ id = nil unless id.is_a? Fixnum
56
+ ex = Rpc::Error.new *ErrorProtocol[index]
57
+ ex.id = id
58
+ ex
59
+ end
60
+
61
+ def self.validate request
62
+ return 200 if request["jsonrpc"] == Version and
63
+ request["method"].kind_of?(String) and
64
+ request["method"] != ""
65
+ raise error :invalid_request, request["id"]
66
+ end
67
+
68
+ def self.parse env
69
+ begin
70
+ case env["REQUEST_METHOD"]
71
+ when "POST"
72
+ JSON.parse(env["rack.input"].read)
73
+ when "GET"
74
+ req = Rack::Request.new(env)
75
+ obj = req.params
76
+ obj["id"] = obj["id"] ? obj["id"].to_i : nil
77
+ obj["params"] = JSON::parse(obj["params"])
78
+ obj
79
+ else
80
+ raise error :invalid_request
81
+ end
82
+
83
+ rescue JSON::ParserError, Exception
84
+ raise error :parse_error
85
+ end
86
+ end
87
+
88
+ def self.route request, ctrl
89
+ method, params = Prefix + request["method"], request["params"]
90
+
91
+ unless ctrl.respond_to? method
92
+ raise error :method_not_found, request["id"]
93
+ end
94
+
95
+ result = ctrl.send(method, *params)
96
+ if result.is_a? AsyncResult
97
+ result.id = request["id"]
98
+ return result
99
+ end
100
+ forge_response result, request["id"]
101
+ end
102
+
103
+ def self.forge_response result, id = nil
104
+ return nil if id == nil
105
+ {"jsonrpc" => "2.0", "id" => id, "result" => result}.to_json
106
+ end
107
+
108
+ # The class RpcDeferrable is useful helps you to build a Json Rpc server
109
+ # into an asynchronous way
110
+ class AsyncResult
111
+ include EventMachine::Deferrable
112
+
113
+ attr_reader :response
114
+ attr_accessor :id
115
+
116
+ def reply obj
117
+ @callback.call(Rpc::forge_response(obj, @id))
118
+ end
119
+
120
+ #FIXME thin specific
121
+ def each &blk
122
+ @callback = blk
123
+ end
124
+ end
125
+
126
+ end
127
+ end
@@ -0,0 +1,59 @@
1
+ require 'test/unit'
2
+ require 'rack/mock'
3
+ require 'json-rpc'
4
+ require 'uri'
5
+
6
+ class All < Test::Unit::TestCase
7
+ include JsonRpc
8
+
9
+ ReqSubtract = {"jsonrpc"=>"2.0", "method"=>"subtract", "params"=>[42, 23], "id"=>1}
10
+ ReqSubtractString = JSON::dump(ReqSubtract)
11
+
12
+ def test_post_parse
13
+ opts = {
14
+ :input => ReqSubtractString,
15
+ :method => 'POST'
16
+ }
17
+ rs = Rpc::parse Rack::MockRequest.env_for("", opts)
18
+ assert_equal ReqSubtract, rs
19
+ end
20
+
21
+ def test_get_parse
22
+ opts = {:method => 'GET'}
23
+ rs = Rpc::parse Rack::MockRequest.env_for("/?method=subtract&params=[42,23]&id=1&jsonrpc=2.0")
24
+ assert_equal ReqSubtract, rs
25
+ end
26
+
27
+ def test_invalid_json_post_parse
28
+ req_string = '{"jsonrpc": "2.0", "method": "subtract", "params": [42, 2'
29
+
30
+ # POST REQUEST
31
+ opts = {:input => req_string,
32
+ :method => 'POST'
33
+ }
34
+ assert_raise(Rpc::Error) {
35
+ rs = Rpc::parse Rack::MockRequest.env_for("", opts)
36
+ }
37
+ end
38
+
39
+ def test_validate
40
+ req_hash = { "jsonrpc" => "2.0", "method" => "s", "params" => 1, "id" => 22 }
41
+ assert_nothing_raised {
42
+ Rpc::validate req_hash
43
+ }
44
+ req_hash = { "method" => "s", "params" => 1, "id" => 22 }
45
+ assert_raise(Rpc::Error) {
46
+ Rpc::validate req_hash
47
+ }
48
+ req_hash = { "jsonrpc" => "2.0", "method" => "s", "params" => 1, "id" => "22" }
49
+ assert_raise(Rpc::Error) {
50
+ Rpc::validate req_hash
51
+ }
52
+ end
53
+
54
+ def test_response_forging
55
+ assert_equal({"jsonrpc" => "2.0", "result" => 12, "id" => 7},
56
+ JSON.parse(Rpc::forge_response(12, 7)))
57
+ assert_equal(nil, Rpc::forge_response(12))
58
+ end
59
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: json-rpc
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Helios Technologies Ltd.
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-06-15 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Implementation of JSON RPC 2.0 protocol. It allows you to create easily a json rpc server in pure Rack, in Rails, or asynchronous using Thin and EventMachine.
22
+ email: contact@heliostech.hk
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/json-rpc.rb
31
+ - test/test_rpc_module.rb
32
+ - example/async_app.ru
33
+ - example/rack_app.ru
34
+ - README.md
35
+ has_rdoc: true
36
+ homepage: https://github.com/helios-technologies/json-rpc
37
+ licenses: []
38
+
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ segments:
50
+ - 0
51
+ version: "0"
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ requirements: []
61
+
62
+ rubyforge_project: "[none]"
63
+ rubygems_version: 1.3.7
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: JSON RPC 2.0 library for rack applications
67
+ test_files: []
68
+