rest-core 2.1.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
require 'rest-core/promise'
|
3
|
+
require 'rest-core/middleware'
|
4
|
+
|
5
|
+
class RestCore::Engine
|
6
|
+
include RestCore::Middleware
|
7
|
+
|
8
|
+
def call env, &k
|
9
|
+
promise = Promise.new(env, k, env[ASYNC])
|
10
|
+
promise.defer{ request(promise, env) }
|
11
|
+
env.merge(RESPONSE_BODY => promise.future_body,
|
12
|
+
RESPONSE_STATUS => promise.future_status,
|
13
|
+
RESPONSE_HEADERS => promise.future_headers,
|
14
|
+
RESPONSE_SOCKET => promise.future_socket,
|
15
|
+
FAIL => promise.future_failures,
|
16
|
+
PROMISE => promise)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def payload_and_headers env
|
21
|
+
Payload.generate_with_headers(env[REQUEST_PAYLOAD], env[REQUEST_HEADERS])
|
22
|
+
end
|
23
|
+
|
24
|
+
def calculate_timeout timer
|
25
|
+
return [] unless timer
|
26
|
+
[timer.timeout, timer.timeout]
|
27
|
+
end
|
28
|
+
|
29
|
+
def normalize_headers headers
|
30
|
+
headers.inject({}){ |r, (k, v)|
|
31
|
+
r[k.to_s.upcase.tr('-', '_')] = if v.kind_of?(Array) && v.size == 1
|
32
|
+
v.first
|
33
|
+
else
|
34
|
+
v
|
35
|
+
end
|
36
|
+
r
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
require 'httpclient'
|
3
|
+
require 'rest-core/engine'
|
4
|
+
|
5
|
+
class RestCore::HttpClient < RestCore::Engine
|
6
|
+
private
|
7
|
+
def request promise, env
|
8
|
+
client = ::HTTPClient.new
|
9
|
+
client.cookie_manager = nil
|
10
|
+
client.follow_redirect_count = 0
|
11
|
+
client.transparent_gzip_decompression = true
|
12
|
+
payload, headers = payload_and_headers(env)
|
13
|
+
|
14
|
+
if env[HIJACK]
|
15
|
+
request_async(client, payload, headers, promise, env)
|
16
|
+
else
|
17
|
+
request_sync(client, payload, headers, promise, env)
|
18
|
+
end
|
19
|
+
rescue Exception => e
|
20
|
+
promise.reject(e)
|
21
|
+
end
|
22
|
+
|
23
|
+
def request_sync client, payload, headers, promise, env
|
24
|
+
client.connect_timeout, client.receive_timeout =
|
25
|
+
calculate_timeout(env[TIMER])
|
26
|
+
|
27
|
+
res = client.request(env[REQUEST_METHOD], request_uri(env), nil,
|
28
|
+
payload, {'User-Agent' => 'Ruby'}.merge(headers))
|
29
|
+
|
30
|
+
promise.fulfill(res.content, res.status,
|
31
|
+
normalize_headers(res.header.all))
|
32
|
+
end
|
33
|
+
|
34
|
+
def request_async client, payload, headers, promise, env
|
35
|
+
res = client.request_async(env[REQUEST_METHOD], request_uri(env), nil,
|
36
|
+
payload, {'User-Agent' => 'Ruby'}.merge(headers)).pop
|
37
|
+
|
38
|
+
promise.fulfill('', res.status,
|
39
|
+
normalize_headers(res.header.all), res.content)
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require 'net/http/persistent'
|
3
|
+
require 'rest-core/engine'
|
4
|
+
|
5
|
+
class RestCore::NetHttpPersistent < RestCore::Engine
|
6
|
+
def request promise, env
|
7
|
+
http = ::Net::HTTP::Persistent.new
|
8
|
+
http.open_timeout, http.read_timeout = calculate_timeout(env[TIMER])
|
9
|
+
payload, headers = payload_and_headers(env)
|
10
|
+
|
11
|
+
uri = ::URI.parse(request_uri(env))
|
12
|
+
req = ::Net::HTTP.const_get(env[REQUEST_METHOD].to_s.capitalize).
|
13
|
+
new(uri, headers)
|
14
|
+
req.body_stream = payload
|
15
|
+
res = http.request(uri, req)
|
16
|
+
|
17
|
+
promise.fulfill(res.body, res.code.to_i, normalize_headers(res.to_hash))
|
18
|
+
rescue Exception => e
|
19
|
+
promise.reject(e)
|
20
|
+
end
|
21
|
+
end
|
@@ -1,58 +1,29 @@
|
|
1
1
|
|
2
2
|
require 'restclient'
|
3
3
|
require 'rest-core/patch/rest-client'
|
4
|
+
require 'rest-core/engine'
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
include RestCore::Middleware
|
10
|
-
def call env, &k
|
11
|
-
future = Future::FutureThread.new(env, k, env[ASYNC])
|
12
|
-
|
13
|
-
# we can implement thread pool in the future
|
14
|
-
t = future.wrap{ request(future, env) }
|
15
|
-
|
16
|
-
env[TIMER].on_timeout{
|
17
|
-
t.kill
|
18
|
-
future.on_error(env[TIMER].error)
|
19
|
-
} if env[TIMER]
|
20
|
-
|
21
|
-
env.merge(RESPONSE_BODY => future.proxy_body,
|
22
|
-
RESPONSE_STATUS => future.proxy_status,
|
23
|
-
RESPONSE_HEADERS => future.proxy_headers,
|
24
|
-
FUTURE => future)
|
25
|
-
end
|
26
|
-
|
27
|
-
def request future, env
|
28
|
-
payload, headers = Payload.generate_with_headers(env[REQUEST_PAYLOAD],
|
29
|
-
env[REQUEST_HEADERS])
|
6
|
+
class RestCore::RestClient < RestCore::Engine
|
7
|
+
def request promise, env
|
8
|
+
open_timeout, read_timeout = calculate_timeout(env[TIMER])
|
9
|
+
payload, headers = payload_and_headers(env)
|
30
10
|
res = ::RestClient::Request.execute(:method => env[REQUEST_METHOD],
|
31
11
|
:url => request_uri(env) ,
|
32
12
|
:payload => payload ,
|
33
13
|
:headers => headers ,
|
34
|
-
:max_redirects => 0
|
35
|
-
|
36
|
-
|
14
|
+
:max_redirects => 0 ,
|
15
|
+
:open_timeout => open_timeout ,
|
16
|
+
:timeout => read_timeout )
|
17
|
+
promise.fulfill(res.body, res.code, normalize_headers(res.raw_headers))
|
37
18
|
rescue ::RestClient::Exception => e
|
38
19
|
if res = e.response
|
39
20
|
# we don't want to raise an exception for 404 requests
|
40
|
-
|
21
|
+
promise.fulfill(res.body, res.code, normalize_headers(res.raw_headers))
|
41
22
|
else
|
42
|
-
|
23
|
+
promise.reject(e)
|
43
24
|
end
|
44
|
-
rescue Exception => e
|
45
|
-
future.on_error(e)
|
46
|
-
end
|
47
25
|
|
48
|
-
|
49
|
-
|
50
|
-
r[k.to_s.upcase.tr('-', '_')] = if v.kind_of?(Array) && v.size == 1
|
51
|
-
v.first
|
52
|
-
else
|
53
|
-
v
|
54
|
-
end
|
55
|
-
r
|
56
|
-
}
|
26
|
+
rescue Exception => e
|
27
|
+
promise.reject(e)
|
57
28
|
end
|
58
29
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
|
2
|
+
require 'thread'
|
3
|
+
require 'rest-core'
|
4
|
+
|
5
|
+
class RestCore::EventSource < Struct.new(:client, :path, :query, :opts,
|
6
|
+
:socket)
|
7
|
+
include RestCore
|
8
|
+
def start
|
9
|
+
self.mutex = Mutex.new
|
10
|
+
self.condv = ConditionVariable.new
|
11
|
+
@onopen ||= nil
|
12
|
+
@onmessage_for ||= nil
|
13
|
+
@onerror ||= nil
|
14
|
+
|
15
|
+
o = {REQUEST_HEADERS => {'Accept' => 'text/event-stream'},
|
16
|
+
HIJACK => true}.merge(opts)
|
17
|
+
client.get(path, query, o){ |sock| onopen(sock) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def closed?
|
21
|
+
!!(socket && socket.closed?)
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
socket && socket.close
|
26
|
+
rescue IOError
|
27
|
+
end
|
28
|
+
|
29
|
+
def wait
|
30
|
+
raise RC::Error.new("Not yet started for: #{self}") unless mutex
|
31
|
+
mutex.synchronize{ condv.wait(mutex) until closed? } unless closed?
|
32
|
+
end
|
33
|
+
|
34
|
+
def onopen sock=nil, &cb
|
35
|
+
if block_given?
|
36
|
+
@onopen = cb
|
37
|
+
else
|
38
|
+
@onopen.call(sock) if @onopen
|
39
|
+
onmessage_for(sock)
|
40
|
+
end
|
41
|
+
rescue Exception => e
|
42
|
+
begin # close the socket since we're going to stop anyway
|
43
|
+
sock.close # if we don't close it, client might wait forever
|
44
|
+
rescue IOError
|
45
|
+
end
|
46
|
+
# let the client has a chance to handle this, and make signal
|
47
|
+
onerror(e, sock)
|
48
|
+
end
|
49
|
+
|
50
|
+
def onmessage event=nil, sock=nil, &cb
|
51
|
+
if block_given?
|
52
|
+
@onmessage = cb
|
53
|
+
elsif @onmessage
|
54
|
+
@onmessage.call(event, sock)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# would also be called upon closing, would always be called at least once
|
59
|
+
def onerror error=nil, sock=nil, &cb
|
60
|
+
if block_given?
|
61
|
+
@onerror = cb
|
62
|
+
else
|
63
|
+
begin
|
64
|
+
@onerror.call(error, sock) if @onerror
|
65
|
+
ensure
|
66
|
+
condv.signal # should never deadlock someone
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
attr_accessor :mutex, :condv
|
73
|
+
|
74
|
+
private
|
75
|
+
# called in requesting thread after the request is done
|
76
|
+
def onmessage_for sock
|
77
|
+
self.socket = sock # for you to track the socket
|
78
|
+
until sock.eof?
|
79
|
+
event = sock.readline("\n\n").split("\n").inject({}) do |r, i|
|
80
|
+
k, v = i.split(': ', 2)
|
81
|
+
r[k] = v
|
82
|
+
r
|
83
|
+
end
|
84
|
+
onmessage(event, sock)
|
85
|
+
end
|
86
|
+
sock.close
|
87
|
+
onerror(EOFError.new, sock)
|
88
|
+
rescue IOError => e
|
89
|
+
onerror(e, sock)
|
90
|
+
end
|
91
|
+
end
|
data/lib/rest-core/middleware.rb
CHANGED
@@ -1,16 +1,10 @@
|
|
1
1
|
|
2
|
-
require 'rest-core'
|
3
|
-
|
4
2
|
require 'uri'
|
3
|
+
require 'rest-core'
|
5
4
|
|
6
5
|
module RestCore::Middleware
|
7
6
|
include RestCore
|
8
7
|
|
9
|
-
# identity function
|
10
|
-
def self.id
|
11
|
-
@id ||= lambda{ |a| a }
|
12
|
-
end
|
13
|
-
|
14
8
|
def self.included mod
|
15
9
|
mod.send(:include, RestCore)
|
16
10
|
mod.send(:attr_reader, :app)
|
@@ -39,10 +33,22 @@ module RestCore::Middleware
|
|
39
33
|
mod.send(:include, accessor)
|
40
34
|
end
|
41
35
|
|
42
|
-
def call env,
|
43
|
-
def
|
44
|
-
def
|
45
|
-
|
36
|
+
def call env, &k; app.call(env, &(k || id)); end
|
37
|
+
def id ; RC.id ; end
|
38
|
+
def fail env, obj
|
39
|
+
if obj
|
40
|
+
env.merge(FAIL => (env[FAIL] || []) + [obj])
|
41
|
+
else
|
42
|
+
env
|
43
|
+
end
|
44
|
+
end
|
45
|
+
def log env, obj
|
46
|
+
if obj
|
47
|
+
env.merge(LOG => (env[LOG] || []) + [obj])
|
48
|
+
else
|
49
|
+
env
|
50
|
+
end
|
51
|
+
end
|
46
52
|
def run app=app
|
47
53
|
if app.respond_to?(:app) && app.app
|
48
54
|
run(app.app)
|
@@ -8,12 +8,7 @@ class RestCore::ErrorDetector
|
|
8
8
|
def call env
|
9
9
|
app.call(env){ |response|
|
10
10
|
detector = error_detector(env)
|
11
|
-
yield(
|
12
|
-
if error = (detector && detector.call(response))
|
13
|
-
fail(response, error)
|
14
|
-
else
|
15
|
-
response
|
16
|
-
end)
|
11
|
+
yield(fail(response, detector && detector.call(response)))
|
17
12
|
}
|
18
13
|
end
|
19
14
|
end
|
@@ -1,21 +1,33 @@
|
|
1
1
|
|
2
2
|
require 'rest-core/middleware'
|
3
3
|
|
4
|
+
# http://tools.ietf.org/html/rfc6749
|
4
5
|
class RestCore::Oauth2Header
|
5
6
|
def self.members; [:access_token_type, :access_token]; end
|
6
7
|
include RestCore::Middleware
|
7
8
|
|
8
9
|
def call env, &k
|
9
10
|
start_time = Time.now
|
10
|
-
headers
|
11
|
-
|
12
|
-
|
11
|
+
headers = build_headers(env)
|
12
|
+
auth = headers['Authorization']
|
13
|
+
event = Event::WithHeader.new(Time.now - start_time,
|
14
|
+
"Authorization: #{auth}") if auth
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
+
app.call(log(env.merge(REQUEST_HEADERS => headers), event), &k)
|
17
|
+
end
|
18
|
+
|
19
|
+
def build_headers env
|
20
|
+
auth = case token = access_token(env)
|
21
|
+
when String
|
22
|
+
token
|
23
|
+
when Hash
|
24
|
+
token.map{ |(k, v)| "#{k}=\"#{v}\"" }.join(', ')
|
25
|
+
end
|
16
26
|
|
17
|
-
|
18
|
-
|
19
|
-
|
27
|
+
if auth
|
28
|
+
{'Authorization' => "#{access_token_type(env)} #{auth}"}
|
29
|
+
else
|
30
|
+
{}
|
31
|
+
end.merge(env[REQUEST_HEADERS])
|
20
32
|
end
|
21
33
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
|
2
2
|
require 'rest-core/middleware'
|
3
|
-
|
4
|
-
require 'timeout'
|
3
|
+
require 'rest-core/timer'
|
5
4
|
|
6
5
|
class RestCore::Timeout
|
7
6
|
def self.members; [:timeout]; end
|
@@ -22,27 +21,14 @@ class RestCore::Timeout
|
|
22
21
|
end
|
23
22
|
|
24
23
|
def monitor env
|
25
|
-
|
26
|
-
when /Auto/
|
27
|
-
run.http_client.class.to_s
|
28
|
-
else
|
29
|
-
name
|
30
|
-
end
|
31
|
-
|
32
|
-
timer = case class_name
|
33
|
-
when /EmHttpRequest/
|
34
|
-
TimerEm
|
35
|
-
else
|
36
|
-
TimerThread
|
37
|
-
end.new(timeout(env), timeout_error)
|
38
|
-
|
24
|
+
timer = Timer.new(timeout(env), timeout_error)
|
39
25
|
yield(env.merge(TIMER => timer))
|
26
|
+
rescue Exception
|
27
|
+
timer.cancel
|
28
|
+
raise
|
40
29
|
end
|
41
30
|
|
42
31
|
def timeout_error
|
43
32
|
::Timeout::Error.new('execution expired')
|
44
33
|
end
|
45
|
-
|
46
|
-
autoload :TimerEm , 'rest-core/middleware/timeout/timer_em'
|
47
|
-
autoload :TimerThread, 'rest-core/middleware/timeout/timer_thread'
|
48
34
|
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
|
2
|
+
require 'thread'
|
3
|
+
require 'rest-core'
|
4
|
+
|
5
|
+
class RestCore::Promise
|
6
|
+
include RestCore
|
7
|
+
|
8
|
+
class Future < BasicObject
|
9
|
+
def initialize promise, target
|
10
|
+
@promise, @target = promise, target
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing msg, *args, &block
|
14
|
+
@promise.yield[@target].__send__(msg, *args, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize env, k=RC.id, immediate=false, &job
|
19
|
+
self.env = env
|
20
|
+
self.k = k
|
21
|
+
self.immediate = immediate
|
22
|
+
|
23
|
+
self.body, self.status, self.headers,
|
24
|
+
self.socket, self.response, self.error, = nil
|
25
|
+
|
26
|
+
self.condv = ConditionVariable.new
|
27
|
+
self.mutex = Mutex.new
|
28
|
+
|
29
|
+
defer(&job) if job
|
30
|
+
end
|
31
|
+
|
32
|
+
def inspect
|
33
|
+
"<#{self.class.name} for #{env[REQUEST_PATH]}>"
|
34
|
+
end
|
35
|
+
|
36
|
+
def future_body ; Future.new(self, RESPONSE_BODY ); end
|
37
|
+
def future_status ; Future.new(self, RESPONSE_STATUS ); end
|
38
|
+
def future_headers ; Future.new(self, RESPONSE_HEADERS); end
|
39
|
+
def future_socket ; Future.new(self, RESPONSE_SOCKET ); end
|
40
|
+
def future_failures; Future.new(self, FAIL) ; end
|
41
|
+
|
42
|
+
# called in client thread
|
43
|
+
def defer &job
|
44
|
+
if pool_size < 0 # negative number for blocking call
|
45
|
+
job.call
|
46
|
+
elsif pool_size > 0
|
47
|
+
self.task = client_class.thread_pool.defer do
|
48
|
+
synchronized_yield{ job.call }
|
49
|
+
end
|
50
|
+
else
|
51
|
+
Thread.new{ synchronized_yield{ job.call } }
|
52
|
+
end
|
53
|
+
env[TIMER].on_timeout{ reject(env[TIMER].error) } if env[TIMER]
|
54
|
+
end
|
55
|
+
|
56
|
+
# called in client thread (client.wait)
|
57
|
+
def wait
|
58
|
+
# it might be awaken by some other futures!
|
59
|
+
mutex.synchronize{ condv.wait(mutex) until !!status } unless !!status
|
60
|
+
end
|
61
|
+
|
62
|
+
# called in client thread (from the future (e.g. body))
|
63
|
+
def yield
|
64
|
+
wait
|
65
|
+
callback
|
66
|
+
end
|
67
|
+
|
68
|
+
# called in requesting thread after the request is done
|
69
|
+
def fulfill body, status, headers, socket=nil
|
70
|
+
env[TIMER].cancel if env[TIMER]
|
71
|
+
self.body, self.status, self.headers, self.socket =
|
72
|
+
body, status, headers, socket
|
73
|
+
# under ASYNC callback, should call immediately
|
74
|
+
callback_in_async if immediate
|
75
|
+
condv.broadcast # client or response might be waiting
|
76
|
+
end
|
77
|
+
|
78
|
+
# called in requesting thread if something goes wrong or timed out
|
79
|
+
def reject error
|
80
|
+
task.cancel if task
|
81
|
+
|
82
|
+
self.error = if error.kind_of?(Exception)
|
83
|
+
error
|
84
|
+
else
|
85
|
+
Error.new(error || 'unknown')
|
86
|
+
end
|
87
|
+
fulfill('', 0, {})
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
attr_accessor :env, :k, :immediate,
|
92
|
+
:response, :body, :status, :headers, :socket, :error,
|
93
|
+
:condv, :mutex, :task
|
94
|
+
|
95
|
+
private
|
96
|
+
# called in a new thread if pool_size == 0, otherwise from the pool
|
97
|
+
# i.e. requesting thread
|
98
|
+
def synchronized_yield
|
99
|
+
mutex.synchronize{ yield }
|
100
|
+
rescue Exception => e
|
101
|
+
# nothing we can do here for an asynchronous exception,
|
102
|
+
# so we just log the error
|
103
|
+
# TODO: add error_log_method
|
104
|
+
warn "RestCore: ERROR: #{e}\n from #{e.backtrace.inspect}"
|
105
|
+
reject(e) # should never deadlock someone
|
106
|
+
end
|
107
|
+
|
108
|
+
# called in client thread, when yield is called
|
109
|
+
def callback
|
110
|
+
self.response ||= k.call(
|
111
|
+
env.merge(RESPONSE_BODY => body ,
|
112
|
+
RESPONSE_STATUS => status,
|
113
|
+
RESPONSE_HEADERS => headers,
|
114
|
+
RESPONSE_SOCKET => socket,
|
115
|
+
FAIL => ((env[FAIL]||[]) + [error]).compact,
|
116
|
+
LOG => env[LOG] ||[]))
|
117
|
+
end
|
118
|
+
|
119
|
+
# called in requesting thread, whenever the request is done
|
120
|
+
def callback_in_async
|
121
|
+
callback
|
122
|
+
rescue Exception => e
|
123
|
+
# nothing we can do here for an asynchronous exception,
|
124
|
+
# so we just log the error
|
125
|
+
# TODO: add error_log_method
|
126
|
+
warn "RestCore: ERROR: #{e}\n from #{e.backtrace.inspect}"
|
127
|
+
end
|
128
|
+
|
129
|
+
def client_class; env[CLIENT].class; end
|
130
|
+
def pool_size
|
131
|
+
@pool_size ||= if client_class.respond_to?(:pool_size)
|
132
|
+
client_class.pool_size
|
133
|
+
else
|
134
|
+
0
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|