rest-core 2.1.2 → 3.0.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 +4 -4
- data/.gitignore +1 -2
- data/.travis.yml +3 -5
- data/CHANGES.md +65 -5
- data/Gemfile +10 -5
- data/NOTE.md +1 -1
- data/README.md +194 -128
- data/Rakefile +8 -34
- data/TODO.md +3 -2
- data/example/simple.rb +6 -4
- data/example/use-cases.rb +39 -122
- data/lib/rest-core.rb +14 -5
- data/lib/rest-core/builder.rb +12 -2
- data/lib/rest-core/client.rb +31 -25
- data/lib/rest-core/engine.rb +39 -0
- data/lib/rest-core/engine/http-client.rb +41 -0
- data/lib/rest-core/engine/net-http-persistent.rb +21 -0
- data/lib/rest-core/engine/rest-client.rb +13 -42
- data/lib/rest-core/event_source.rb +91 -0
- data/lib/rest-core/middleware.rb +17 -11
- data/lib/rest-core/middleware/error_detector.rb +1 -6
- data/lib/rest-core/middleware/oauth1_header.rb +1 -0
- data/lib/rest-core/middleware/oauth2_header.rb +20 -8
- data/lib/rest-core/middleware/oauth2_query.rb +1 -0
- data/lib/rest-core/middleware/timeout.rb +5 -19
- data/lib/rest-core/promise.rb +137 -0
- data/lib/rest-core/test.rb +2 -43
- data/lib/rest-core/thread_pool.rb +122 -0
- data/lib/rest-core/timer.rb +30 -0
- data/lib/rest-core/util/hmac.rb +0 -8
- data/lib/rest-core/version.rb +1 -1
- data/lib/rest-core/wrapper.rb +1 -1
- data/rest-core.gemspec +36 -25
- data/task/README.md +54 -0
- data/task/gemgem.rb +150 -156
- data/test/test_builder.rb +2 -2
- data/test/test_cache.rb +8 -8
- data/test/test_client.rb +16 -6
- data/test/test_client_oauth1.rb +1 -1
- data/test/test_event_source.rb +77 -0
- data/test/test_follow_redirect.rb +1 -1
- data/test/test_future.rb +16 -0
- data/test/test_oauth2_header.rb +28 -0
- data/test/test_promise.rb +89 -0
- data/test/test_rest-client.rb +21 -0
- data/test/test_thread_pool.rb +10 -0
- data/test/test_timeout.rb +13 -8
- metadata +61 -37
- data/example/multi.rb +0 -44
- data/lib/rest-core/engine/auto.rb +0 -25
- data/lib/rest-core/engine/em-http-request.rb +0 -90
- data/lib/rest-core/engine/future/future.rb +0 -107
- data/lib/rest-core/engine/future/future_fiber.rb +0 -32
- data/lib/rest-core/engine/future/future_thread.rb +0 -29
- data/lib/rest-core/middleware/timeout/timer_em.rb +0 -26
- data/lib/rest-core/middleware/timeout/timer_thread.rb +0 -36
- data/task/.gitignore +0 -1
- data/test/test_em-http-request.rb +0 -186
data/lib/rest-core/test.rb
CHANGED
@@ -1,19 +1,16 @@
|
|
1
1
|
|
2
|
-
require 'fiber'
|
3
|
-
require 'em-http-request'
|
4
2
|
require 'rest-core'
|
5
3
|
|
6
|
-
require 'rr'
|
7
4
|
require 'webmock'
|
5
|
+
require 'muack'
|
8
6
|
require 'bacon'
|
9
7
|
|
10
8
|
# for testing lighten (serialization)
|
11
9
|
require 'yaml'
|
12
10
|
|
13
|
-
include RR::Adapters::RRMethods
|
14
|
-
include WebMock::API
|
15
11
|
WebMock.disable_net_connect!(:allow_localhost => true)
|
16
12
|
Bacon.summary_on_exit
|
13
|
+
Bacon::Context.send(:include, Muack::API, WebMock::API)
|
17
14
|
|
18
15
|
module Kernel
|
19
16
|
def eq? rhs
|
@@ -34,41 +31,3 @@ module Kernel
|
|
34
31
|
f.close!
|
35
32
|
end
|
36
33
|
end
|
37
|
-
|
38
|
-
# https://github.com/bblimke/webmock/pull/280
|
39
|
-
class ::EventMachine::WebMockHttpClient
|
40
|
-
def build_request_signature
|
41
|
-
headers, body = @req.headers, @req.body
|
42
|
-
|
43
|
-
@conn.middleware.select {|m| m.respond_to?(:request) }.each do |m|
|
44
|
-
headers, body = m.request(self, headers, body)
|
45
|
-
end
|
46
|
-
|
47
|
-
method = @req.method
|
48
|
-
uri = @req.uri.clone
|
49
|
-
auth = @req.headers[:'proxy-authorization']
|
50
|
-
query = @req.query
|
51
|
-
|
52
|
-
if auth
|
53
|
-
userinfo = auth.join(':')
|
54
|
-
userinfo = WebMock::Util::URI.encode_unsafe_chars_in_userinfo(userinfo)
|
55
|
-
if @req
|
56
|
-
@req.proxy.reject! {|k,v| t.to_s == 'authorization' }
|
57
|
-
else
|
58
|
-
options.reject! {|k,v| k.to_s == 'authorization' } #we added it to url userinfo
|
59
|
-
end
|
60
|
-
uri.userinfo = userinfo
|
61
|
-
end
|
62
|
-
|
63
|
-
uri.query = encode_query(@req.uri, query).slice(/\?(.*)/, 1)
|
64
|
-
|
65
|
-
body = form_encode_body(body) if body.is_a?(Hash)
|
66
|
-
|
67
|
-
WebMock::RequestSignature.new(
|
68
|
-
method.downcase.to_sym,
|
69
|
-
uri.to_s,
|
70
|
-
:body => body || (@req.file && File.read(@req.file)),
|
71
|
-
:headers => headers
|
72
|
-
)
|
73
|
-
end
|
74
|
-
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
|
2
|
+
# reference implementation: puma
|
3
|
+
# https://github.com/puma/puma/blob/v2.7.1/lib/puma/thread_pool.rb
|
4
|
+
|
5
|
+
require 'thread'
|
6
|
+
require 'rest-core'
|
7
|
+
|
8
|
+
class RestCore::ThreadPool
|
9
|
+
include RestCore
|
10
|
+
|
11
|
+
class Queue
|
12
|
+
def initialize
|
13
|
+
@queue = []
|
14
|
+
@mutex = Mutex.new
|
15
|
+
@condv = ConditionVariable.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def << task
|
19
|
+
mutex.synchronize do
|
20
|
+
queue << task
|
21
|
+
condv.signal
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def pop timeout=60
|
26
|
+
mutex.synchronize do
|
27
|
+
if queue.empty?
|
28
|
+
condv.wait(mutex, timeout)
|
29
|
+
queue.shift || lambda{ false } # shutdown idle workers
|
30
|
+
else
|
31
|
+
queue.shift
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def clear
|
37
|
+
queue.clear
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
attr_reader :queue, :mutex, :condv
|
42
|
+
end
|
43
|
+
|
44
|
+
class Task < Struct.new(:job)
|
45
|
+
# this should never fail
|
46
|
+
def call
|
47
|
+
job.call unless cancelled
|
48
|
+
end
|
49
|
+
|
50
|
+
# called from the other thread telling us it's timed out
|
51
|
+
def cancel
|
52
|
+
@cancelled = true
|
53
|
+
end
|
54
|
+
protected
|
55
|
+
attr_reader :thread, :mutex, :cancelled
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.[] client_class
|
59
|
+
(@pools ||= {})[client_class] ||= new(client_class)
|
60
|
+
end
|
61
|
+
|
62
|
+
attr_reader :client_class
|
63
|
+
|
64
|
+
def initialize client_class
|
65
|
+
@client_class = client_class
|
66
|
+
@queue = Queue.new
|
67
|
+
@mutex = Mutex.new
|
68
|
+
@workers = []
|
69
|
+
@waiting = 0
|
70
|
+
end
|
71
|
+
|
72
|
+
def inspect
|
73
|
+
"#<#{self.class.name} client_class=#{client_class}>"
|
74
|
+
end
|
75
|
+
|
76
|
+
def max_size
|
77
|
+
client_class.pool_size
|
78
|
+
end
|
79
|
+
|
80
|
+
def idle_time
|
81
|
+
client_class.pool_idle_time
|
82
|
+
end
|
83
|
+
|
84
|
+
def defer &job
|
85
|
+
mutex.synchronize do
|
86
|
+
task = Task.new(job)
|
87
|
+
queue << task
|
88
|
+
spawn_worker if waiting == 0 && workers.size < max_size
|
89
|
+
task
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def trim force=false
|
94
|
+
queue << lambda{ false } if force || waiting > 0
|
95
|
+
end
|
96
|
+
|
97
|
+
# Block on shutting down, and should not add more jobs while shutting down
|
98
|
+
def shutdown
|
99
|
+
workers.size.times{ trim(true) }
|
100
|
+
workers.first.join && trim(true) until workers.empty?
|
101
|
+
queue.clear
|
102
|
+
end
|
103
|
+
|
104
|
+
protected
|
105
|
+
attr_reader :queue, :mutex, :condv, :workers, :waiting
|
106
|
+
|
107
|
+
private
|
108
|
+
def spawn_worker
|
109
|
+
workers << Thread.new{
|
110
|
+
Thread.current.abort_on_exception = !!$DEBUG
|
111
|
+
|
112
|
+
task = nil
|
113
|
+
begin
|
114
|
+
mutex.synchronize{ @waiting += 1 }
|
115
|
+
task = queue.pop(idle_time)
|
116
|
+
mutex.synchronize{ @waiting -= 1 }
|
117
|
+
end while task.call
|
118
|
+
|
119
|
+
mutex.synchronize{ workers.delete(Thread.current) }
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
require 'timers'
|
3
|
+
|
4
|
+
class RestCore::Timer
|
5
|
+
TimerGen = Timers.new
|
6
|
+
|
7
|
+
attr_accessor :timeout, :error
|
8
|
+
def initialize timeout, error, &block
|
9
|
+
self.timeout = timeout
|
10
|
+
self.error = error
|
11
|
+
self.block = block
|
12
|
+
start
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_timeout &block
|
16
|
+
self.block = block
|
17
|
+
end
|
18
|
+
|
19
|
+
def cancel
|
20
|
+
timer.cancel
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
return if timeout.nil? || timeout.zero?
|
25
|
+
self.timer = TimerGen.after(timeout){ block.call }
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
attr_accessor :block, :timer
|
30
|
+
end
|
data/lib/rest-core/util/hmac.rb
CHANGED
@@ -4,19 +4,11 @@ require 'openssl'
|
|
4
4
|
module RestCore; end
|
5
5
|
module RestCore::Hmac
|
6
6
|
module_function
|
7
|
-
# Fallback to ruby-hmac gem in case system openssl
|
8
|
-
# lib doesn't support SHA256 (OSX 10.5)
|
9
7
|
def sha256 key, data
|
10
8
|
OpenSSL::HMAC.digest('sha256', key, data)
|
11
|
-
rescue RuntimeError
|
12
|
-
require 'hmac-sha2'
|
13
|
-
HMAC::SHA256.digest(key, data)
|
14
9
|
end
|
15
10
|
|
16
11
|
def sha1 key, data
|
17
12
|
OpenSSL::HMAC.digest('sha1', key, data)
|
18
|
-
rescue RuntimeError
|
19
|
-
require 'hmac-sha1'
|
20
|
-
HMAC::SHA1.digest(key, data)
|
21
13
|
end
|
22
14
|
end
|
data/lib/rest-core/version.rb
CHANGED
data/lib/rest-core/wrapper.rb
CHANGED
data/rest-core.gemspec
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: rest-core 3.0.0 ruby lib
|
2
3
|
|
3
4
|
Gem::Specification.new do |s|
|
4
5
|
s.name = "rest-core"
|
5
|
-
s.version = "
|
6
|
+
s.version = "3.0.0"
|
6
7
|
|
7
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
-
s.
|
9
|
-
"
|
10
|
-
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
s.email = ["dev (XD) cardinalblue.com"]
|
9
|
+
s.require_paths = ["lib"]
|
10
|
+
s.authors = ["Lin Jen-Shin (godfat)"]
|
11
|
+
s.date = "2014-05-04"
|
12
|
+
s.description = "Modular Ruby clients interface for REST APIs.\n\nThere has been an explosion in the number of REST APIs available today.\nTo address the need for a way to access these APIs easily and elegantly,\nwe have developed rest-core, which consists of composable middleware\nthat allows you to build a REST client for any REST API. Or in the case of\ncommon APIs such as Facebook, Github, and Twitter, you can simply use the\ndedicated clients provided by [rest-more][].\n\n[rest-more]: https://github.com/godfat/rest-more"
|
13
|
+
s.email = ["godfat (XD) godfat.org"]
|
14
14
|
s.files = [
|
15
15
|
".gitignore",
|
16
16
|
".gitmodules",
|
@@ -22,7 +22,6 @@ Gem::Specification.new do |s|
|
|
22
22
|
"README.md",
|
23
23
|
"Rakefile",
|
24
24
|
"TODO.md",
|
25
|
-
"example/multi.rb",
|
26
25
|
"example/simple.rb",
|
27
26
|
"example/use-cases.rb",
|
28
27
|
"lib/rest-core.rb",
|
@@ -31,15 +30,14 @@ Gem::Specification.new do |s|
|
|
31
30
|
"lib/rest-core/client/simple.rb",
|
32
31
|
"lib/rest-core/client/universal.rb",
|
33
32
|
"lib/rest-core/client_oauth1.rb",
|
34
|
-
"lib/rest-core/engine
|
33
|
+
"lib/rest-core/engine.rb",
|
35
34
|
"lib/rest-core/engine/dry.rb",
|
36
|
-
"lib/rest-core/engine/
|
37
|
-
"lib/rest-core/engine/
|
38
|
-
"lib/rest-core/engine/future/future_fiber.rb",
|
39
|
-
"lib/rest-core/engine/future/future_thread.rb",
|
35
|
+
"lib/rest-core/engine/http-client.rb",
|
36
|
+
"lib/rest-core/engine/net-http-persistent.rb",
|
40
37
|
"lib/rest-core/engine/rest-client.rb",
|
41
38
|
"lib/rest-core/error.rb",
|
42
39
|
"lib/rest-core/event.rb",
|
40
|
+
"lib/rest-core/event_source.rb",
|
43
41
|
"lib/rest-core/middleware.rb",
|
44
42
|
"lib/rest-core/middleware/auth_basic.rb",
|
45
43
|
"lib/rest-core/middleware/bypass.rb",
|
@@ -60,11 +58,12 @@ Gem::Specification.new do |s|
|
|
60
58
|
"lib/rest-core/middleware/oauth2_header.rb",
|
61
59
|
"lib/rest-core/middleware/oauth2_query.rb",
|
62
60
|
"lib/rest-core/middleware/timeout.rb",
|
63
|
-
"lib/rest-core/middleware/timeout/timer_em.rb",
|
64
|
-
"lib/rest-core/middleware/timeout/timer_thread.rb",
|
65
61
|
"lib/rest-core/patch/multi_json.rb",
|
66
62
|
"lib/rest-core/patch/rest-client.rb",
|
63
|
+
"lib/rest-core/promise.rb",
|
67
64
|
"lib/rest-core/test.rb",
|
65
|
+
"lib/rest-core/thread_pool.rb",
|
66
|
+
"lib/rest-core/timer.rb",
|
68
67
|
"lib/rest-core/util/hmac.rb",
|
69
68
|
"lib/rest-core/util/json.rb",
|
70
69
|
"lib/rest-core/util/parse_query.rb",
|
@@ -72,7 +71,7 @@ Gem::Specification.new do |s|
|
|
72
71
|
"lib/rest-core/version.rb",
|
73
72
|
"lib/rest-core/wrapper.rb",
|
74
73
|
"rest-core.gemspec",
|
75
|
-
"task
|
74
|
+
"task/README.md",
|
76
75
|
"task/gemgem.rb",
|
77
76
|
"test/test_auth_basic.rb",
|
78
77
|
"test/test_builder.rb",
|
@@ -81,25 +80,27 @@ Gem::Specification.new do |s|
|
|
81
80
|
"test/test_client_oauth1.rb",
|
82
81
|
"test/test_default_payload.rb",
|
83
82
|
"test/test_default_query.rb",
|
84
|
-
"test/test_em-http-request.rb",
|
85
83
|
"test/test_error_detector.rb",
|
86
84
|
"test/test_error_detector_http.rb",
|
87
85
|
"test/test_error_handler.rb",
|
86
|
+
"test/test_event_source.rb",
|
88
87
|
"test/test_follow_redirect.rb",
|
88
|
+
"test/test_future.rb",
|
89
89
|
"test/test_json_request.rb",
|
90
90
|
"test/test_json_response.rb",
|
91
91
|
"test/test_oauth1_header.rb",
|
92
|
+
"test/test_oauth2_header.rb",
|
92
93
|
"test/test_payload.rb",
|
94
|
+
"test/test_promise.rb",
|
93
95
|
"test/test_rest-client.rb",
|
94
96
|
"test/test_simple.rb",
|
97
|
+
"test/test_thread_pool.rb",
|
95
98
|
"test/test_timeout.rb",
|
96
99
|
"test/test_universal.rb",
|
97
100
|
"test/test_wrapper.rb"]
|
98
|
-
s.homepage = "https://github.com/
|
101
|
+
s.homepage = "https://github.com/godfat/rest-core"
|
99
102
|
s.licenses = ["Apache License 2.0"]
|
100
|
-
s.
|
101
|
-
s.require_paths = ["lib"]
|
102
|
-
s.rubygems_version = "2.0.3"
|
103
|
+
s.rubygems_version = "2.2.2"
|
103
104
|
s.summary = "Modular Ruby clients interface for REST APIs."
|
104
105
|
s.test_files = [
|
105
106
|
"test/test_auth_basic.rb",
|
@@ -109,17 +110,21 @@ Gem::Specification.new do |s|
|
|
109
110
|
"test/test_client_oauth1.rb",
|
110
111
|
"test/test_default_payload.rb",
|
111
112
|
"test/test_default_query.rb",
|
112
|
-
"test/test_em-http-request.rb",
|
113
113
|
"test/test_error_detector.rb",
|
114
114
|
"test/test_error_detector_http.rb",
|
115
115
|
"test/test_error_handler.rb",
|
116
|
+
"test/test_event_source.rb",
|
116
117
|
"test/test_follow_redirect.rb",
|
118
|
+
"test/test_future.rb",
|
117
119
|
"test/test_json_request.rb",
|
118
120
|
"test/test_json_response.rb",
|
119
121
|
"test/test_oauth1_header.rb",
|
122
|
+
"test/test_oauth2_header.rb",
|
120
123
|
"test/test_payload.rb",
|
124
|
+
"test/test_promise.rb",
|
121
125
|
"test/test_rest-client.rb",
|
122
126
|
"test/test_simple.rb",
|
127
|
+
"test/test_thread_pool.rb",
|
123
128
|
"test/test_timeout.rb",
|
124
129
|
"test/test_universal.rb",
|
125
130
|
"test/test_wrapper.rb"]
|
@@ -128,11 +133,17 @@ Gem::Specification.new do |s|
|
|
128
133
|
s.specification_version = 4
|
129
134
|
|
130
135
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
131
|
-
s.add_runtime_dependency(%q<
|
136
|
+
s.add_runtime_dependency(%q<httpclient>, [">= 0"])
|
137
|
+
s.add_runtime_dependency(%q<mime-types>, [">= 0"])
|
138
|
+
s.add_runtime_dependency(%q<timers>, [">= 0"])
|
132
139
|
else
|
133
|
-
s.add_dependency(%q<
|
140
|
+
s.add_dependency(%q<httpclient>, [">= 0"])
|
141
|
+
s.add_dependency(%q<mime-types>, [">= 0"])
|
142
|
+
s.add_dependency(%q<timers>, [">= 0"])
|
134
143
|
end
|
135
144
|
else
|
136
|
-
s.add_dependency(%q<
|
145
|
+
s.add_dependency(%q<httpclient>, [">= 0"])
|
146
|
+
s.add_dependency(%q<mime-types>, [">= 0"])
|
147
|
+
s.add_dependency(%q<timers>, [">= 0"])
|
137
148
|
end
|
138
149
|
end
|
data/task/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Gemgem
|
2
|
+
|
3
|
+
## DESCRIPTION:
|
4
|
+
|
5
|
+
Provided tasks:
|
6
|
+
|
7
|
+
rake clean # Remove ignored files
|
8
|
+
rake gem:build # Build gem
|
9
|
+
rake gem:install # Install gem
|
10
|
+
rake gem:release # Release gem
|
11
|
+
rake gem:spec # Generate gemspec
|
12
|
+
rake test # Run tests in memory
|
13
|
+
|
14
|
+
## REQUIREMENTS:
|
15
|
+
|
16
|
+
* Tested with MRI (official CRuby) 1.9.3, 2.0.0, Rubinius and JRuby.
|
17
|
+
|
18
|
+
## INSTALLATION:
|
19
|
+
|
20
|
+
git submodule add git://github.com/godfat/gemgem.git task
|
21
|
+
|
22
|
+
And in Rakefile:
|
23
|
+
|
24
|
+
``` ruby
|
25
|
+
begin
|
26
|
+
require "#{dir = File.dirname(__FILE__)}/task/gemgem"
|
27
|
+
rescue LoadError
|
28
|
+
sh 'git submodule update --init'
|
29
|
+
exec Gem.ruby, '-S', $PROGRAM_NAME, *ARGV
|
30
|
+
end
|
31
|
+
|
32
|
+
Gemgem.init(dir) do |s|
|
33
|
+
s.name = 'your-gem'
|
34
|
+
s.version = '0.1.0'
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
## LICENSE:
|
39
|
+
|
40
|
+
Apache License 2.0
|
41
|
+
|
42
|
+
Copyright (c) 2011-2013, Lin Jen-Shin (godfat)
|
43
|
+
|
44
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
45
|
+
you may not use this file except in compliance with the License.
|
46
|
+
You may obtain a copy of the License at
|
47
|
+
|
48
|
+
<http://www.apache.org/licenses/LICENSE-2.0>
|
49
|
+
|
50
|
+
Unless required by applicable law or agreed to in writing, software
|
51
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
52
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
53
|
+
See the License for the specific language governing permissions and
|
54
|
+
limitations under the License.
|