jimson 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +6 -0
- data/VERSION +1 -1
- data/lib/jimson/client.rb +4 -2
- data/lib/jimson/client_error.rb +7 -4
- data/lib/jimson/http_server.rb +138 -0
- data/lib/jimson/server.rb +29 -150
- data/spec/{em_helper.rb → server_helper.rb} +0 -0
- data/spec/spec_helper.rb +1 -1
- metadata +46 -64
data/CHANGELOG.rdoc
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/jimson/client.rb
CHANGED
@@ -80,8 +80,10 @@ module Jimson
|
|
80
80
|
|
81
81
|
return data['result']
|
82
82
|
|
83
|
-
rescue
|
84
|
-
raise
|
83
|
+
rescue Jimson::ClientError::Generic, Jimson::ServerError::Generic => e
|
84
|
+
raise e
|
85
|
+
rescue Exception, StandardError => e
|
86
|
+
raise Jimson::ClientError::InternalError.new(e)
|
85
87
|
end
|
86
88
|
|
87
89
|
def valid_response?(data)
|
data/lib/jimson/client_error.rb
CHANGED
@@ -1,24 +1,27 @@
|
|
1
1
|
module Jimson
|
2
2
|
module ClientError
|
3
|
-
class
|
3
|
+
class Generic < Exception
|
4
|
+
end
|
5
|
+
|
6
|
+
class InvalidResponse < Generic
|
4
7
|
def initialize()
|
5
8
|
super('Invalid or empty response from server.')
|
6
9
|
end
|
7
10
|
end
|
8
11
|
|
9
|
-
class InvalidJSON <
|
12
|
+
class InvalidJSON < Generic
|
10
13
|
def initialize(json)
|
11
14
|
super("Couldn't parse JSON string received from server:\n#{json}")
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
15
|
-
class InternalError <
|
18
|
+
class InternalError < Generic
|
16
19
|
def initialize(e)
|
17
20
|
super("An internal client error occurred when processing the request: #{e}\n#{e.backtrace.join("\n")}")
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
21
|
-
class UnknownServerError <
|
24
|
+
class UnknownServerError < Generic
|
22
25
|
def initialize(code, message)
|
23
26
|
super("The server specified an error the client doesn't know about: #{code} #{message}")
|
24
27
|
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'jimson/server_error'
|
2
|
+
|
3
|
+
module Jimson
|
4
|
+
class HttpServer
|
5
|
+
|
6
|
+
JSON_RPC_VERSION = '2.0'
|
7
|
+
|
8
|
+
def initialize(handler)
|
9
|
+
@handler = handler
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
req = Rack::Request.new(env)
|
14
|
+
resp = Rack::Response.new
|
15
|
+
return resp.finish if !req.post?
|
16
|
+
resp.write process(req.body.read)
|
17
|
+
resp.finish
|
18
|
+
end
|
19
|
+
|
20
|
+
def process(content)
|
21
|
+
begin
|
22
|
+
request = parse_request(content)
|
23
|
+
if request.is_a?(Array)
|
24
|
+
raise Jimson::ServerError::InvalidRequest.new if request.empty?
|
25
|
+
response = request.map { |req| handle_request(req) }
|
26
|
+
else
|
27
|
+
response = handle_request(request)
|
28
|
+
end
|
29
|
+
rescue Jimson::ServerError::ParseError, Jimson::ServerError::InvalidRequest => e
|
30
|
+
response = error_response(e)
|
31
|
+
rescue Jimson::ServerError::Generic => e
|
32
|
+
response = error_response(e, request)
|
33
|
+
rescue StandardError, Exception
|
34
|
+
response = error_response(Jimson::ServerError::InternalError.new)
|
35
|
+
end
|
36
|
+
|
37
|
+
response.compact! if response.is_a?(Array)
|
38
|
+
|
39
|
+
return nil if response.nil? || (response.respond_to?(:empty?) && response.empty?)
|
40
|
+
|
41
|
+
response.to_json
|
42
|
+
end
|
43
|
+
|
44
|
+
def handle_request(request)
|
45
|
+
response = nil
|
46
|
+
begin
|
47
|
+
if !validate_request(request)
|
48
|
+
response = error_response(Jimson::ServerError::InvalidRequest.new)
|
49
|
+
else
|
50
|
+
response = create_response(request)
|
51
|
+
end
|
52
|
+
rescue Jimson::ServerError::Generic => e
|
53
|
+
response = error_response(e, request)
|
54
|
+
end
|
55
|
+
|
56
|
+
response
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_request(request)
|
60
|
+
required_keys = %w(jsonrpc method)
|
61
|
+
required_types = {
|
62
|
+
'jsonrpc' => [String],
|
63
|
+
'method' => [String],
|
64
|
+
'params' => [Hash, Array],
|
65
|
+
'id' => [String, Fixnum, NilClass]
|
66
|
+
}
|
67
|
+
|
68
|
+
return false if !request.is_a?(Hash)
|
69
|
+
|
70
|
+
required_keys.each do |key|
|
71
|
+
return false if !request.has_key?(key)
|
72
|
+
end
|
73
|
+
|
74
|
+
required_types.each do |key, types|
|
75
|
+
return false if request.has_key?(key) && !types.any? { |type| request[key].is_a?(type) }
|
76
|
+
end
|
77
|
+
|
78
|
+
return false if request['jsonrpc'] != JSON_RPC_VERSION
|
79
|
+
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def create_response(request)
|
84
|
+
params = request['params']
|
85
|
+
begin
|
86
|
+
if params.is_a?(Hash)
|
87
|
+
result = @handler.send(request['method'], params)
|
88
|
+
else
|
89
|
+
result = @handler.send(request['method'], *params)
|
90
|
+
end
|
91
|
+
rescue NoMethodError
|
92
|
+
raise Jimson::ServerError::MethodNotFound.new
|
93
|
+
rescue ArgumentError
|
94
|
+
raise Jimson::ServerError::InvalidParams.new
|
95
|
+
rescue
|
96
|
+
raise Jimson::ServerError::ApplicationError.new($!)
|
97
|
+
end
|
98
|
+
|
99
|
+
response = success_response(request, result)
|
100
|
+
|
101
|
+
# A Notification is a Request object without an "id" member.
|
102
|
+
# The Server MUST NOT reply to a Notification, including those
|
103
|
+
# that are within a batch request.
|
104
|
+
response = nil if !request.has_key?('id')
|
105
|
+
|
106
|
+
response
|
107
|
+
end
|
108
|
+
|
109
|
+
def error_response(error, request = nil)
|
110
|
+
resp = {
|
111
|
+
'jsonrpc' => JSON_RPC_VERSION,
|
112
|
+
'error' => error.to_h,
|
113
|
+
}
|
114
|
+
if !!request && request.has_key?('id')
|
115
|
+
resp['id'] = request['id']
|
116
|
+
else
|
117
|
+
resp['id'] = nil
|
118
|
+
end
|
119
|
+
|
120
|
+
resp
|
121
|
+
end
|
122
|
+
|
123
|
+
def success_response(request, result)
|
124
|
+
{
|
125
|
+
'jsonrpc' => JSON_RPC_VERSION,
|
126
|
+
'result' => result,
|
127
|
+
'id' => request['id']
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def parse_request(post)
|
132
|
+
data = JSON.parse(post)
|
133
|
+
rescue
|
134
|
+
raise Jimson::ServerError::ParseError.new
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
data/lib/jimson/server.rb
CHANGED
@@ -1,162 +1,41 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require '
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/request'
|
3
|
+
require 'rack/response'
|
4
|
+
require 'rack/showexceptions'
|
4
5
|
require 'json'
|
5
|
-
require 'jimson/
|
6
|
+
require 'jimson/http_server'
|
6
7
|
|
7
8
|
module Jimson
|
8
|
-
class HttpServer < EM::Connection
|
9
|
-
include EM::HttpServer
|
10
|
-
|
11
|
-
JSON_RPC_VERSION = '2.0'
|
12
|
-
|
13
|
-
def self.handler=(handler)
|
14
|
-
@@handler = handler
|
15
|
-
end
|
16
|
-
|
17
|
-
def process_http_request
|
18
|
-
resp = EM::DelegatedHttpResponse.new( self )
|
19
|
-
resp.status = 200
|
20
|
-
resp.content = process_post(@http_post_content)
|
21
|
-
resp.send_response
|
22
|
-
end
|
23
|
-
|
24
|
-
def process_post(content)
|
25
|
-
begin
|
26
|
-
request = parse_request(@http_post_content)
|
27
|
-
if request.is_a?(Array)
|
28
|
-
raise Jimson::ServerError::InvalidRequest.new if request.empty?
|
29
|
-
response = request.map { |req| handle_request(req) }
|
30
|
-
else
|
31
|
-
response = handle_request(request)
|
32
|
-
end
|
33
|
-
rescue Jimson::ServerError::ParseError, Jimson::ServerError::InvalidRequest => e
|
34
|
-
response = error_response(e)
|
35
|
-
rescue Jimson::ServerError::Generic => e
|
36
|
-
response = error_response(e, request)
|
37
|
-
rescue StandardError, Exception
|
38
|
-
response = error_response(Jimson::ServerError::InternalError.new)
|
39
|
-
end
|
40
|
-
|
41
|
-
response.compact! if response.is_a?(Array)
|
42
|
-
|
43
|
-
return nil if response.nil? || (response.respond_to?(:empty?) && response.empty?)
|
44
|
-
|
45
|
-
response.to_json
|
46
|
-
end
|
47
|
-
|
48
|
-
def handle_request(request)
|
49
|
-
response = nil
|
50
|
-
begin
|
51
|
-
if !validate_request(request)
|
52
|
-
response = error_response(Jimson::ServerError::InvalidRequest.new)
|
53
|
-
else
|
54
|
-
response = create_response(request)
|
55
|
-
end
|
56
|
-
rescue Jimson::ServerError::Generic => e
|
57
|
-
response = error_response(e, request)
|
58
|
-
end
|
59
|
-
|
60
|
-
response
|
61
|
-
end
|
62
|
-
|
63
|
-
def validate_request(request)
|
64
|
-
required_keys = %w(jsonrpc method)
|
65
|
-
required_types = {
|
66
|
-
'jsonrpc' => [String],
|
67
|
-
'method' => [String],
|
68
|
-
'params' => [Hash, Array],
|
69
|
-
'id' => [String, Fixnum, NilClass]
|
70
|
-
}
|
71
|
-
|
72
|
-
return false if !request.is_a?(Hash)
|
73
|
-
|
74
|
-
required_keys.each do |key|
|
75
|
-
return false if !request.has_key?(key)
|
76
|
-
end
|
77
|
-
|
78
|
-
required_types.each do |key, types|
|
79
|
-
return false if request.has_key?(key) && !types.any? { |type| request[key].is_a?(type) }
|
80
|
-
end
|
81
|
-
|
82
|
-
return false if request['jsonrpc'] != JSON_RPC_VERSION
|
83
|
-
|
84
|
-
true
|
85
|
-
end
|
86
|
-
|
87
|
-
def create_response(request)
|
88
|
-
params = request['params']
|
89
|
-
begin
|
90
|
-
if params.is_a?(Hash)
|
91
|
-
result = @@handler.send(request['method'], params)
|
92
|
-
else
|
93
|
-
result = @@handler.send(request['method'], *params)
|
94
|
-
end
|
95
|
-
rescue NoMethodError
|
96
|
-
raise Jimson::ServerError::MethodNotFound.new
|
97
|
-
rescue ArgumentError
|
98
|
-
raise Jimson::ServerError::InvalidParams.new
|
99
|
-
rescue
|
100
|
-
raise Jimson::ServerError::ApplicationError.new($!)
|
101
|
-
end
|
102
|
-
|
103
|
-
response = success_response(request, result)
|
104
|
-
|
105
|
-
# A Notification is a Request object without an "id" member.
|
106
|
-
# The Server MUST NOT reply to a Notification, including those
|
107
|
-
# that are within a batch request.
|
108
|
-
response = nil if !request.has_key?('id')
|
109
|
-
|
110
|
-
response
|
111
|
-
end
|
112
|
-
|
113
|
-
def error_response(error, request = nil)
|
114
|
-
resp = {
|
115
|
-
'jsonrpc' => JSON_RPC_VERSION,
|
116
|
-
'error' => error.to_h,
|
117
|
-
}
|
118
|
-
if !!request && request.has_key?('id')
|
119
|
-
resp['id'] = request['id']
|
120
|
-
else
|
121
|
-
resp['id'] = nil
|
122
|
-
end
|
123
|
-
|
124
|
-
resp
|
125
|
-
end
|
126
|
-
|
127
|
-
def success_response(request, result)
|
128
|
-
{
|
129
|
-
'jsonrpc' => JSON_RPC_VERSION,
|
130
|
-
'result' => result,
|
131
|
-
'id' => request['id']
|
132
|
-
}
|
133
|
-
end
|
134
|
-
|
135
|
-
def parse_request(post)
|
136
|
-
data = JSON.parse(post)
|
137
|
-
rescue
|
138
|
-
raise Jimson::ServerError::ParseError.new
|
139
|
-
end
|
140
|
-
|
141
|
-
end
|
142
|
-
|
143
9
|
class Server
|
144
10
|
|
145
|
-
attr_accessor :handler, :host, :port
|
146
|
-
|
147
|
-
|
11
|
+
attr_accessor :handler, :host, :port
|
12
|
+
|
13
|
+
#
|
14
|
+
# +handler+ is an instance of the class to expose as a JSON-RPC server
|
15
|
+
#
|
16
|
+
# +opts+ may include:
|
17
|
+
# * :host - the hostname or ip to bind to
|
18
|
+
# * :port - the port to listen on
|
19
|
+
# * :server - the rack handler to use, e.g. 'webrick' or 'thin'
|
20
|
+
#
|
21
|
+
def initialize(handler, opts = {})
|
148
22
|
@handler = handler
|
149
|
-
@
|
150
|
-
@
|
151
|
-
@
|
23
|
+
@app = Jimson::HttpServer.new(@handler)
|
24
|
+
@host = opts[:host] || '0.0.0.0'
|
25
|
+
@port = opts[:port] || 8999
|
26
|
+
@server = opts[:server] || 'webrick'
|
152
27
|
end
|
153
28
|
|
29
|
+
#
|
30
|
+
# Starts the server so it can process requests
|
31
|
+
#
|
154
32
|
def start
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
33
|
+
Rack::Server.start(
|
34
|
+
:server => @server,
|
35
|
+
:app => @app,
|
36
|
+
:Host => @host,
|
37
|
+
:Port => @port
|
38
|
+
)
|
160
39
|
end
|
161
40
|
|
162
41
|
end
|
File without changes
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,71 +1,56 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: jimson
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
4
5
|
prerelease:
|
5
|
-
version: 0.2.3
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Chris Kite
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-08-11 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
17
15
|
name: rest-client
|
18
|
-
|
19
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &17785440 !ruby/object:Gem::Requirement
|
20
17
|
none: false
|
21
|
-
requirements:
|
22
|
-
- -
|
23
|
-
- !ruby/object:Gem::Version
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
24
21
|
version: 1.6.3
|
25
22
|
type: :runtime
|
26
|
-
version_requirements: *id001
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: eventmachine
|
29
23
|
prerelease: false
|
30
|
-
|
24
|
+
version_requirements: *17785440
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: json
|
27
|
+
requirement: &17780040 !ruby/object:Gem::Requirement
|
31
28
|
none: false
|
32
|
-
requirements:
|
33
|
-
- -
|
34
|
-
- !ruby/object:Gem::Version
|
35
|
-
version:
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.5.1
|
36
33
|
type: :runtime
|
37
|
-
version_requirements: *id002
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
name: eventmachine_httpserver
|
40
34
|
prerelease: false
|
41
|
-
|
35
|
+
version_requirements: *17780040
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rack
|
38
|
+
requirement: &17779580 !ruby/object:Gem::Requirement
|
42
39
|
none: false
|
43
|
-
requirements:
|
44
|
-
- -
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version:
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.3'
|
47
44
|
type: :runtime
|
48
|
-
version_requirements: *id003
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: json
|
51
45
|
prerelease: false
|
52
|
-
|
53
|
-
none: false
|
54
|
-
requirements:
|
55
|
-
- - ">="
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
version: 1.5.1
|
58
|
-
type: :runtime
|
59
|
-
version_requirements: *id004
|
46
|
+
version_requirements: *17779580
|
60
47
|
description:
|
61
48
|
email:
|
62
49
|
executables: []
|
63
|
-
|
64
50
|
extensions: []
|
65
|
-
|
66
|
-
extra_rdoc_files:
|
51
|
+
extra_rdoc_files:
|
67
52
|
- README.rdoc
|
68
|
-
files:
|
53
|
+
files:
|
69
54
|
- VERSION
|
70
55
|
- LICENSE.txt
|
71
56
|
- CHANGELOG.rdoc
|
@@ -77,41 +62,38 @@ files:
|
|
77
62
|
- lib/jimson/server_error.rb
|
78
63
|
- lib/jimson/response.rb
|
79
64
|
- lib/jimson/request.rb
|
65
|
+
- lib/jimson/http_server.rb
|
80
66
|
- lib/jimson/client.rb
|
81
67
|
- spec/server_spec.rb
|
82
68
|
- spec/client_spec.rb
|
83
|
-
- spec/
|
69
|
+
- spec/server_helper.rb
|
84
70
|
- spec/spec_helper.rb
|
85
|
-
has_rdoc: true
|
86
71
|
homepage: http://www.github.com/chriskite/jimson
|
87
72
|
licenses: []
|
88
|
-
|
89
73
|
post_install_message:
|
90
74
|
rdoc_options: []
|
91
|
-
|
92
|
-
require_paths:
|
75
|
+
require_paths:
|
93
76
|
- lib
|
94
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
78
|
none: false
|
96
|
-
requirements:
|
97
|
-
- -
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
version:
|
100
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
84
|
none: false
|
102
|
-
requirements:
|
103
|
-
- -
|
104
|
-
- !ruby/object:Gem::Version
|
105
|
-
version:
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
106
89
|
requirements: []
|
107
|
-
|
108
90
|
rubyforge_project:
|
109
|
-
rubygems_version: 1.6
|
91
|
+
rubygems_version: 1.8.6
|
110
92
|
signing_key:
|
111
93
|
specification_version: 3
|
112
94
|
summary: JSON-RPC 2.0 client and server
|
113
|
-
test_files:
|
95
|
+
test_files:
|
114
96
|
- spec/server_spec.rb
|
115
97
|
- spec/client_spec.rb
|
116
|
-
- spec/
|
98
|
+
- spec/server_helper.rb
|
117
99
|
- spec/spec_helper.rb
|