jimson-reloaded 0.12.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 398634f92c8530750c7a6fe8966e2dbb6dec17a3999d5ea97c83b3481f610c0b
4
+ data.tar.gz: dda0d5e556736f80f2e8702510aa5302717dd0708fed75388b15179dd62fea21
5
+ SHA512:
6
+ metadata.gz: ac184436f5551653a2709a3a18826e6e85ee62d26ef842faf45afde95823c5c68fc4b44035124e9273c1317e6e75c394cb8c578b074d3c6c795b9ac0cffb3a11
7
+ data.tar.gz: db750df41bff5e0bc2e0e41160ed358c2f4cf77ea27c5386cba0a21838149a6111ad4ed4cb567e276d146736069f8176736dd3704ed89eea42384f1d87b82ed3
data/CHANGELOG.md ADDED
@@ -0,0 +1,109 @@
1
+ # 0.12.0 /
2
+
3
+ * Unified Bignum and Fixnum to Integer
4
+ * Add ability to specify custom content type
5
+ * Add data returned to invalid response exception
6
+ * Add support for named parameters
7
+ * Add Router :ns_sep option for custom namespace
8
+ * Fix json variable name on invalid json response
9
+ * made it possible to overwrite advanced RestClient values, like ssl_ca_file
10
+
11
+ # 0.11.0 / 2016-03-13
12
+
13
+ * Minor enhancements
14
+
15
+ * Update dependency versions for Ruby 2.*
16
+ * Remove Gemfile.lock
17
+
18
+ # 0.10.0 / 2013-06-28
19
+
20
+ * Minor enhancements
21
+
22
+ * Update dependency versions
23
+
24
+ # 0.9.1 / 2012-09-18
25
+
26
+ * Bug fixes
27
+
28
+ * Allow opts to be passed to Server.with_routes
29
+
30
+ # 0.9.0 / 2012-08-22
31
+
32
+ * Minor enhancements
33
+
34
+ * Add show_errors option to server, which will cause application errors to include the error name and the first line of the backtrace
35
+
36
+ # 0.8.0 / 2012-08-17
37
+
38
+ * Major enhancements
39
+
40
+ * Add namespaced method calls to client (e.g. 'client[:foo].sum(1,2,3) # calls foo.sum')
41
+ * Add Server.with_routes to quickly created a routed server
42
+
43
+ # 0.7.1 / 2012-08-16
44
+
45
+ * Bug fixes
46
+
47
+ * Fix handling of array params in client, which were erroneously being flattened
48
+
49
+ # 0.7.0 / 2012-04-13
50
+
51
+ * Major enhancements
52
+
53
+ * Add namespaced routing
54
+
55
+ * Bug fixes
56
+
57
+ * Fix deprecation warning about RDoc task in Rakefile
58
+
59
+ # 0.6.0 / 2012-03-14
60
+
61
+ * Minor enhancements
62
+
63
+ * Add ability to pass options to Rack and RestClient
64
+
65
+ # 0.5.0 / 2012-03-06
66
+
67
+ * Major enhancements
68
+
69
+ * Switch to MultiJson from json gem
70
+
71
+ * Bug fixes
72
+
73
+ * Allow BigNum in 'id' field of request and response
74
+
75
+ # 0.3.1 / 2011-08-11
76
+
77
+ * Minor enhancements
78
+
79
+ * Refactor the way the server is intantiated/started to work better with config.ru
80
+
81
+ # 0.3.0 / 2011-08-11
82
+
83
+ * Major enhancements
84
+
85
+ * Replace eventmachine-httpserver with rack for more cross-platform goodness
86
+
87
+ # 0.2.3 / 2011-08-01
88
+
89
+ * Bug fixes
90
+
91
+ * Fix argument error in client error handling
92
+
93
+ # 0.2.2 / 2011-07-28
94
+
95
+ * Bug fixes
96
+
97
+ * Fix invalid local variable error in client error handling
98
+
99
+ # 0.2.1 / 2011-07-27
100
+
101
+ * Bug fixes
102
+
103
+ * Fix error in client handling some errors caused by errant 'new' keyword
104
+
105
+ # 0.2.0 / 2011-07-20
106
+
107
+ * Major enhancements
108
+
109
+ * Replace patron with rest-client for JRuby compatibility in the client
data/LICENSE.txt ADDED
@@ -0,0 +1,17 @@
1
+ Permission is hereby granted, free of charge, to any person obtaining a copy
2
+ of this software and associated documentation files (the "Software"), to deal
3
+ in the Software without restriction, including without limitation the rights
4
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5
+ copies of the Software, and to permit persons to whom the Software is
6
+ furnished to do so, subject to the following conditions:
7
+
8
+ The above copyright notice and this permission notice shall be included in
9
+ all copies or substantial portions of the Software.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Jimson-Reloaded
2
+
3
+ This is a fork of [chriskite/jimson](https://github.com/chriskite/jimson). I merged all open PRs of the original unmaintaned gem and will maintain it as `jimson-reloaded`. PRs are welcome 🤗.
4
+
5
+ ### JSON-RPC 2.0 Client and Server for Ruby
6
+
7
+ [![Build Status](https://github.com/railslove/jimson/actions/workflows/ruby.yml/badge.svg?branch=main)](https://github.com/railslove/jimson/actions/workflows/ruby.yml)
8
+
9
+ ## Client: Quick Start
10
+
11
+ ```ruby
12
+ require 'jimson-reloaded'
13
+ client = Jimson::Client.new("http://www.example.com:8999") # the URL for the JSON-RPC 2.0 server to connect to
14
+ result = client.sum(1,2) # call the 'sum' method on the RPC server and save the result '3'
15
+ ```
16
+
17
+ ## Server: Quick Start
18
+
19
+ ```ruby
20
+ require 'jimson-reloaded'
21
+
22
+ class MyHandler
23
+ extend Jimson::Handler
24
+
25
+ def sum(a,b)
26
+ a + b
27
+ end
28
+ end
29
+
30
+ server = Jimson::Server.new(MyHandler.new)
31
+ server.start # serve with webrick on http://0.0.0.0:8999/
32
+ ```
33
+
34
+ ## JSON Engine
35
+
36
+ Jimson uses multi\_json, so you can load the JSON library of your choice in your application and Jimson will use it automatically.
37
+
38
+ For example, require the 'json' gem in your application:
39
+
40
+ ```ruby
41
+ require 'json'
42
+ ```
43
+
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/lib/')
2
+ require 'jimson/version'
3
+ require 'rubygems'
4
+ require 'rake'
5
+ require 'rspec/core/rake_task'
6
+
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ require 'rubygems/tasks'
9
+
10
+ Gem::Tasks.new
11
+
12
+ desc "Run all specs"
13
+ RSpec::Core::RakeTask.new(:rspec) do |spec|
14
+ spec.pattern = 'spec/**/*_spec.rb'
15
+ end
16
+
17
+ task :default => :rspec
18
+
19
+ require 'rdoc/task'
20
+
21
+ Rake::RDocTask.new do |rdoc|
22
+ rdoc.rdoc_dir = 'rdoc'
23
+ rdoc.title = "jimson #{Jimson::VERSION}"
24
+ rdoc.rdoc_files.include('README*')
25
+ rdoc.rdoc_files.include('lib/**/*.rb')
26
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'jimson/handler'
3
+ require 'jimson/router'
4
+ require 'jimson/server'
5
+ require 'jimson/client'
6
+
7
+ module Jimson
8
+ end
@@ -0,0 +1,182 @@
1
+ require 'blankslate'
2
+ require 'multi_json'
3
+ require 'rest-client'
4
+ require 'jimson/request'
5
+ require 'jimson/response'
6
+
7
+ module Jimson
8
+ class ClientHelper
9
+ JSON_RPC_VERSION = '2.0'
10
+
11
+ def self.make_id
12
+ rand(10**12)
13
+ end
14
+
15
+ def initialize(url, opts = {}, namespace = nil, client_opts = {})
16
+ @url = url
17
+ URI.parse(@url) # for the sake of validating the url
18
+ @batch = []
19
+ @opts = opts
20
+ @namespace = namespace
21
+ @opts[:content_type] ||= 'application/json'
22
+ @client_opts = client_opts
23
+ end
24
+
25
+ def process_call(sym, args)
26
+ resp = send_single_request(sym.to_s, args)
27
+
28
+ begin
29
+ data = MultiJson.decode(resp)
30
+ rescue
31
+ raise Client::Error::InvalidJSON.new(resp)
32
+ end
33
+
34
+ return process_single_response(data)
35
+
36
+ rescue Exception, StandardError => e
37
+ e.extend(Client::Error) unless e.is_a?(Client::Error)
38
+ raise e
39
+ end
40
+
41
+ def send_single_request(method, args)
42
+ namespaced_method = @namespace.nil? ? method : "#@namespace#{method}"
43
+ post_data = MultiJson.encode({
44
+ 'jsonrpc' => JSON_RPC_VERSION,
45
+ 'method' => namespaced_method,
46
+ 'params' => args,
47
+ 'id' => self.class.make_id
48
+ })
49
+ resp = RestClient::Request.execute(@client_opts.merge(:method => :post, :url => @url, :payload => post_data, :headers => @opts))
50
+ if resp.nil? || resp.body.nil? || resp.body.empty?
51
+ raise Client::Error::InvalidResponse.new(resp)
52
+ end
53
+
54
+ return resp.body
55
+ end
56
+
57
+ def send_batch_request(batch)
58
+ post_data = MultiJson.encode(batch)
59
+ resp = RestClient::Request.execute(@client_opts.merge(:method => :post, :url => @url, :payload => post_data, :headers => @opts))
60
+ if resp.nil? || resp.body.nil? || resp.body.empty?
61
+ raise Client::Error::InvalidResponse.new(resp)
62
+ end
63
+
64
+ return resp.body
65
+ end
66
+
67
+ def process_batch_response(responses)
68
+ responses.each do |resp|
69
+ saved_response = @batch.map { |r| r[1] }.select { |r| r.id == resp['id'] }.first
70
+ raise Client::Error::InvalidResponse.new if saved_response.nil?
71
+ saved_response.populate!(resp)
72
+ end
73
+ end
74
+
75
+ def process_single_response(data)
76
+ raise Client::Error::InvalidResponse.new(data) if !valid_response?(data)
77
+
78
+ if !!data['error']
79
+ code = data['error']['code']
80
+ msg = data['error']['message']
81
+ raise Client::Error::ServerError.new(code, msg)
82
+ end
83
+
84
+ return data['result']
85
+ end
86
+
87
+ def valid_response?(data)
88
+ return false if !data.is_a?(Hash)
89
+
90
+ return false if data['jsonrpc'] != JSON_RPC_VERSION
91
+
92
+ return false if !data.has_key?('id')
93
+
94
+ return false if data.has_key?('error') && data.has_key?('result')
95
+
96
+ if data.has_key?('error')
97
+ if !data['error'].is_a?(Hash) || !data['error'].has_key?('code') || !data['error'].has_key?('message')
98
+ return false
99
+ end
100
+
101
+ if !data['error']['code'].is_a?(Integer) || !data['error']['message'].is_a?(String)
102
+ return false
103
+ end
104
+ end
105
+
106
+ return true
107
+
108
+ rescue
109
+ return false
110
+ end
111
+
112
+ def push_batch_request(request)
113
+ request.id = self.class.make_id
114
+ response = Response.new(request.id)
115
+ @batch << [request, response]
116
+ return response
117
+ end
118
+
119
+ def send_batch
120
+ batch = @batch.map(&:first) # get the requests
121
+ response = send_batch_request(batch)
122
+
123
+ begin
124
+ responses = MultiJson.decode(response)
125
+ rescue
126
+ raise Client::Error::InvalidJSON.new(response)
127
+ end
128
+
129
+ process_batch_response(responses)
130
+ @batch = []
131
+ end
132
+
133
+ end
134
+
135
+ class BatchClient < BlankSlate
136
+
137
+ def initialize(helper)
138
+ @helper = helper
139
+ end
140
+
141
+ def method_missing(sym, *args, &block)
142
+ request = Jimson::Request.new(sym.to_s, args)
143
+ @helper.push_batch_request(request)
144
+ end
145
+
146
+ end
147
+
148
+ class Client < BlankSlate
149
+ reveal :instance_variable_get
150
+ reveal :inspect
151
+ reveal :to_s
152
+
153
+ def self.batch(client)
154
+ helper = client.instance_variable_get(:@helper)
155
+ batch_client = BatchClient.new(helper)
156
+ yield batch_client
157
+ helper.send_batch
158
+ end
159
+
160
+ def initialize(url, opts = {}, namespace = nil, client_opts = {})
161
+ @url, @opts, @namespace, @client_opts = url, opts, namespace, client_opts
162
+ @helper = ClientHelper.new(url, opts, namespace, client_opts)
163
+ end
164
+
165
+ def method_missing(sym, *args, &block)
166
+ args = args.first if args.size == 1 && args.first.is_a?(Hash)
167
+ @helper.process_call(sym, args)
168
+ end
169
+
170
+ def [](method, *args)
171
+ if method.is_a?(Symbol)
172
+ # namespace requested
173
+ new_ns = @namespace.nil? ? "#{method}." : "#@namespace#{method}."
174
+ return Client.new(@url, @opts, new_ns)
175
+ end
176
+ @helper.process_call(method, args)
177
+ end
178
+
179
+ end
180
+ end
181
+
182
+ require 'jimson/client/error'
@@ -0,0 +1,23 @@
1
+ module Jimson
2
+ class Client
3
+ module Error
4
+ class InvalidResponse < StandardError
5
+ def initialize(response = nil)
6
+ super("Invalid or empty response from server:\n#{response.inspect}")
7
+ end
8
+ end
9
+
10
+ class InvalidJSON < StandardError
11
+ def initialize(json)
12
+ super("Couldn't parse JSON string received from server:\n#{json}")
13
+ end
14
+ end
15
+
16
+ class ServerError < StandardError
17
+ def initialize(code, message)
18
+ super("Server error #{code}: #{message}")
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ module Jimson
2
+ module Handler
3
+
4
+ def jimson_default_methods
5
+ self.instance_methods.map(&:to_s) - Object.methods.map(&:to_s)
6
+ end
7
+
8
+ def jimson_expose(*methods)
9
+ @jimson_exposed_methods ||= []
10
+ @jimson_exposed_methods += methods.map(&:to_s)
11
+ end
12
+
13
+ def jimson_exclude(*methods)
14
+ @jimson_excluded_methods ||= []
15
+ @jimson_excluded_methods += methods.map(&:to_s)
16
+ end
17
+
18
+ def jimson_exposed_methods
19
+ @jimson_exposed_methods ||= []
20
+ @jimson_excluded_methods ||= []
21
+ (jimson_default_methods - @jimson_excluded_methods + @jimson_exposed_methods).sort
22
+ end
23
+
24
+ end
25
+ end