jimson 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.3.0 / 2011-08-11
2
+
3
+ * Major enhancements
4
+
5
+ * Replace eventmachine-httpserver with rack for more cross-platform goodness
6
+
1
7
  == 0.2.3 / 2011-08-01
2
8
 
3
9
  * Bug fixes
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.3
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 Exception, StandardError
84
- raise Jimson::ClientError::InternalError.new($!)
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)
@@ -1,24 +1,27 @@
1
1
  module Jimson
2
2
  module ClientError
3
- class InvalidResponse < Exception
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 < Exception
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 < Exception
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 < Exception
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 'eventmachine'
2
- require 'evma_httpserver'
3
- require 'logger'
1
+ require 'rack'
2
+ require 'rack/request'
3
+ require 'rack/response'
4
+ require 'rack/showexceptions'
4
5
  require 'json'
5
- require 'jimson/server_error'
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, :logger
146
-
147
- def initialize(handler, host = '0.0.0.0', port = 8999, logger = Logger.new(STDOUT))
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
- @host = host
150
- @port = port
151
- @logger = logger
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
- Jimson::HttpServer.handler = @handler
156
- EM.run do
157
- EM::start_server(@host, @port, Jimson::HttpServer)
158
- @logger.info("Server listening on #{@host}:#{@port} with handler '#{@handler}'")
159
- end
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
@@ -7,7 +7,7 @@ require 'json'
7
7
 
8
8
  SPEC_URL = 'http://localhost:8999'
9
9
 
10
- pid = Process.spawn(File.dirname(__FILE__) + '/em_helper.rb')
10
+ pid = Process.spawn(File.dirname(__FILE__) + '/server_helper.rb')
11
11
 
12
12
  RSpec.configure do |config|
13
13
  config.after(:all) do
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
- date: 2011-08-01 00:00:00 -05:00
14
- default_executable:
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
- prerelease: false
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
- requirement: &id002 !ruby/object:Gem::Requirement
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: 0.12.10
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
- requirement: &id003 !ruby/object:Gem::Requirement
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: 0.2.1
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
- requirement: &id004 !ruby/object:Gem::Requirement
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/em_helper.rb
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: "0"
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: "0"
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
106
89
  requirements: []
107
-
108
90
  rubyforge_project:
109
- rubygems_version: 1.6.2
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/em_helper.rb
98
+ - spec/server_helper.rb
117
99
  - spec/spec_helper.rb