async-http 0.49.1 → 0.50.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/Gemfile +0 -5
- data/README.md +66 -0
- data/Rakefile +2 -2
- data/async-http.gemspec +2 -0
- data/lib/async/http/client.rb +7 -2
- data/lib/async/http/endpoint.rb +12 -1
- data/lib/async/http/internet.rb +3 -2
- data/lib/async/http/protocol.rb +2 -2
- data/lib/async/http/protocol/http1/connection.rb +2 -2
- data/lib/async/http/protocol/http2/connection.rb +2 -2
- data/lib/async/http/protocol/https.rb +1 -3
- data/lib/async/http/relative_location.rb +4 -1
- data/lib/async/http/server.rb +2 -2
- data/lib/async/http/version.rb +1 -1
- metadata +19 -5
- data/lib/async/http/pool.rb +0 -187
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5db10f65827c5a336ba0d827f659f81411e87a65de7b2cf0ef512ce52bf4950e
|
4
|
+
data.tar.gz: 50461d80e6da099e33f71a4d6a476fa25609d99c69f401374509d6daf5f29116
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d61522536ff249da6c1fbecbc6493d1f401cb005ce280c1a6ce278f107399a1a2fc43bce170123a52be21da4f88940f0e8783b949bda132609dbf41400c10628
|
7
|
+
data.tar.gz: fba11fe6d4b10036f288e120416efb85e6d7704ae556eeb1eb51f1d7eae7b2cb0ea3106677470d9f6024e5b9dfc0278ba54aab691f7982162f1c363bed0d1d24
|
data/.travis.yml
CHANGED
@@ -13,17 +13,17 @@ addons:
|
|
13
13
|
|
14
14
|
matrix:
|
15
15
|
include:
|
16
|
-
- rvm: 2.3
|
17
16
|
- rvm: 2.4
|
18
17
|
- rvm: 2.5
|
19
18
|
- rvm: 2.6
|
19
|
+
- rvm: 2.7
|
20
20
|
- rvm: 2.6
|
21
|
-
env: COVERAGE=
|
21
|
+
env: COVERAGE=PartialSummary,Coveralls
|
22
22
|
- rvm: truffleruby
|
23
23
|
- rvm: jruby-head
|
24
24
|
env: JRUBY_OPTS="--debug -X+O"
|
25
25
|
- rvm: ruby-head
|
26
|
-
- rvm: 2.
|
26
|
+
- rvm: 2.7
|
27
27
|
os: osx
|
28
28
|
allow_failures:
|
29
29
|
- rvm: truffleruby
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -62,6 +62,72 @@ end
|
|
62
62
|
|
63
63
|
Consider using [async-rest](https://github.com/socketry/async-rest) instead.
|
64
64
|
|
65
|
+
### Multiple Requests
|
66
|
+
|
67
|
+
To issue multiple requests concurrently, you should use a barrier, e.g.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
#!/usr/bin/env ruby
|
71
|
+
|
72
|
+
require 'async'
|
73
|
+
require 'async/barrier'
|
74
|
+
require 'async/http/internet'
|
75
|
+
|
76
|
+
TOPICS = ["ruby", "python", "rust"]
|
77
|
+
|
78
|
+
Async do
|
79
|
+
internet = Async::HTTP::Internet.new
|
80
|
+
barrier = Async::Barrier.new
|
81
|
+
|
82
|
+
# Spawn an asynchronous task for each topic:
|
83
|
+
TOPICS.each do |topic|
|
84
|
+
barrier.async do
|
85
|
+
response = internet.get "https://www.google.com/search?q=#{topic}"
|
86
|
+
puts "Found #{topic}: #{response.read.scan(topic).size} times."
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Ensure we wait for all requests to complete before continuing:
|
91
|
+
barrier.wait
|
92
|
+
ensure
|
93
|
+
internet&.close
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
#### Limiting Requests
|
98
|
+
|
99
|
+
If you need to limit the number of simultaneous requests, use a semaphore.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
#!/usr/bin/env ruby
|
103
|
+
|
104
|
+
require 'async'
|
105
|
+
require 'async/barrier'
|
106
|
+
require 'async/semaphore'
|
107
|
+
require 'async/http/internet'
|
108
|
+
|
109
|
+
TOPICS = ["ruby", "python", "rust"]
|
110
|
+
|
111
|
+
Async do
|
112
|
+
internet = Async::HTTP::Internet.new
|
113
|
+
barrier = Async::Barrier.new
|
114
|
+
semaphore = Async::Semaphore.new(2, parent: barrier)
|
115
|
+
|
116
|
+
# Spawn an asynchronous task for each topic:
|
117
|
+
TOPICS.each do |topic|
|
118
|
+
semaphore.async do
|
119
|
+
response = internet.get "https://www.google.com/search?q=#{topic}"
|
120
|
+
puts "Found #{topic}: #{response.read.scan(topic).size} times."
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Ensure we wait for all requests to complete before continuing:
|
125
|
+
barrier.wait
|
126
|
+
ensure
|
127
|
+
internet&.close
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
65
131
|
### Downloading a File
|
66
132
|
|
67
133
|
Here is an example showing how to download a file and save it to a local path:
|
data/Rakefile
CHANGED
data/async-http.gemspec
CHANGED
@@ -4,6 +4,7 @@ require_relative 'lib/async/http/version'
|
|
4
4
|
Gem::Specification.new do |spec|
|
5
5
|
spec.name = "async-http"
|
6
6
|
spec.version = Async::HTTP::VERSION
|
7
|
+
spec.licenses = ["MIT"]
|
7
8
|
spec.authors = ["Samuel Williams"]
|
8
9
|
spec.email = ["samuel.williams@oriontransfer.co.nz"]
|
9
10
|
|
@@ -18,6 +19,7 @@ Gem::Specification.new do |spec|
|
|
18
19
|
|
19
20
|
spec.add_dependency("async", "~> 1.23")
|
20
21
|
spec.add_dependency("async-io", "~> 1.27.0")
|
22
|
+
spec.add_dependency("async-pool", "~> 0.2")
|
21
23
|
|
22
24
|
spec.add_dependency("protocol-http", "~> 0.13.0")
|
23
25
|
spec.add_dependency("protocol-http1", "~> 0.10.0")
|
data/lib/async/http/client.rb
CHANGED
@@ -23,6 +23,8 @@
|
|
23
23
|
require 'async/io/endpoint'
|
24
24
|
require 'async/io/stream'
|
25
25
|
|
26
|
+
require 'async/pool/controller'
|
27
|
+
|
26
28
|
require 'protocol/http/body/streamable'
|
27
29
|
require 'protocol/http/methods'
|
28
30
|
|
@@ -30,6 +32,9 @@ require_relative 'protocol'
|
|
30
32
|
|
31
33
|
module Async
|
32
34
|
module HTTP
|
35
|
+
DEFAULT_RETRIES = 3
|
36
|
+
DEFAULT_CONNECTION_LIMIT = nil
|
37
|
+
|
33
38
|
class Client < ::Protocol::HTTP::Methods
|
34
39
|
# Provides a robust interface to a server.
|
35
40
|
# * If there are no connections, it will create one.
|
@@ -40,7 +45,7 @@ module Async
|
|
40
45
|
# @param protocol [Protocol::HTTP1 | Protocol::HTTP2 | Protocol::HTTPS] the protocol to use.
|
41
46
|
# @param scheme [String] The default scheme to set to requests.
|
42
47
|
# @param authority [String] The default authority to set to requests.
|
43
|
-
def initialize(endpoint, protocol = endpoint.protocol, scheme = endpoint.scheme, authority = endpoint.authority, retries:
|
48
|
+
def initialize(endpoint, protocol = endpoint.protocol, scheme = endpoint.scheme, authority = endpoint.authority, retries: DEFAULT_RETRIES, connection_limit: DEFAULT_CONNECTION_LIMIT)
|
44
49
|
@endpoint = endpoint
|
45
50
|
@protocol = protocol
|
46
51
|
|
@@ -129,7 +134,7 @@ module Async
|
|
129
134
|
protected
|
130
135
|
|
131
136
|
def make_pool(connection_limit)
|
132
|
-
Pool.
|
137
|
+
Async::Pool::Controller.wrap(limit: connection_limit) do
|
133
138
|
Async.logger.debug(self) {"Making connection to #{@endpoint.inspect}"}
|
134
139
|
|
135
140
|
@protocol.client(@endpoint.connect)
|
data/lib/async/http/endpoint.rb
CHANGED
@@ -37,6 +37,17 @@ module Async
|
|
37
37
|
return self.new(url, endpoint, **options)
|
38
38
|
end
|
39
39
|
|
40
|
+
# Construct an endpoint with a specified scheme, hostname, and options.
|
41
|
+
def self.for(scheme, hostname, **options)
|
42
|
+
# TODO: Consider using URI.for once it becomes available:
|
43
|
+
uri_klass = URI.scheme_list[scheme.upcase] || URI::HTTP
|
44
|
+
|
45
|
+
self.new(
|
46
|
+
uri_klass.new(scheme, nil, hostname, nil, nil, nil, nil, nil, nil),
|
47
|
+
**options
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
40
51
|
# @option scheme [String] the scheme to use, overrides the URL scheme.
|
41
52
|
# @option hostname [String] the hostname to connect to (or bind to), overrides the URL hostname (used for SNI).
|
42
53
|
# @option port [Integer] the port to bind to, overrides the URL port.
|
@@ -81,7 +92,7 @@ module Async
|
|
81
92
|
end
|
82
93
|
|
83
94
|
def secure?
|
84
|
-
['https', 'wss'].include?(
|
95
|
+
['https', 'wss'].include?(self.scheme)
|
85
96
|
end
|
86
97
|
|
87
98
|
def protocol
|
data/lib/async/http/internet.rb
CHANGED
@@ -28,8 +28,9 @@ require 'protocol/http/body/buffered'
|
|
28
28
|
module Async
|
29
29
|
module HTTP
|
30
30
|
class Internet
|
31
|
-
def initialize
|
31
|
+
def initialize(**options)
|
32
32
|
@clients = {}
|
33
|
+
@options = options
|
33
34
|
end
|
34
35
|
|
35
36
|
def call(method, url, headers = [], body = nil)
|
@@ -48,7 +49,7 @@ module Async
|
|
48
49
|
end
|
49
50
|
|
50
51
|
def client_for(endpoint)
|
51
|
-
Client.new(endpoint)
|
52
|
+
Client.new(endpoint, **@options)
|
52
53
|
end
|
53
54
|
|
54
55
|
def close
|
data/lib/async/http/protocol.rb
CHANGED
@@ -35,10 +35,10 @@ module Async
|
|
35
35
|
|
36
36
|
# A connection must implement the following interface:
|
37
37
|
# class Connection
|
38
|
-
# def
|
38
|
+
# def concurrency -> can invoke call 1 or more times simultaneously.
|
39
39
|
# def reusable? -> can be used again/persistent connection.
|
40
40
|
|
41
|
-
# def
|
41
|
+
# def viable? -> Boolean
|
42
42
|
|
43
43
|
# def call(request) -> Response
|
44
44
|
# def each -> (yield(request) -> Response)
|
@@ -113,12 +113,12 @@ module Async
|
|
113
113
|
|
114
114
|
attr :count
|
115
115
|
|
116
|
-
def
|
116
|
+
def concurrency
|
117
117
|
self.maximum_concurrent_streams
|
118
118
|
end
|
119
119
|
|
120
120
|
# Can we use this connection to make requests?
|
121
|
-
def
|
121
|
+
def viable?
|
122
122
|
@stream.connected?
|
123
123
|
end
|
124
124
|
|
@@ -25,8 +25,6 @@ require_relative 'http11'
|
|
25
25
|
|
26
26
|
require_relative 'http2'
|
27
27
|
|
28
|
-
require_relative '../pool'
|
29
|
-
|
30
28
|
require 'openssl'
|
31
29
|
|
32
30
|
unless OpenSSL::SSL::SSLContext.instance_methods.include? :alpn_protocols=
|
@@ -66,7 +64,7 @@ module Async
|
|
66
64
|
if protocol = HANDLERS[name]
|
67
65
|
return protocol
|
68
66
|
else
|
69
|
-
|
67
|
+
raise ArgumentError, "Could not determine protocol for connection (#{name.inspect})."
|
70
68
|
end
|
71
69
|
end
|
72
70
|
|
@@ -26,6 +26,9 @@ require 'protocol/http/middleware'
|
|
26
26
|
|
27
27
|
module Async
|
28
28
|
module HTTP
|
29
|
+
class TooManyRedirects < StandardError
|
30
|
+
end
|
31
|
+
|
29
32
|
# A client wrapper which transparently handles both relative and absolute redirects to a given maximum number of hops.
|
30
33
|
class RelativeLocation < ::Protocol::HTTP::Middleware
|
31
34
|
DEFAULT_METHOD = GET
|
@@ -69,7 +72,7 @@ module Async
|
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
|
-
raise
|
75
|
+
raise TooManyRedirects, "Redirected #{hops} times, exceeded maximum!"
|
73
76
|
end
|
74
77
|
end
|
75
78
|
end
|
data/lib/async/http/server.rb
CHANGED
@@ -29,8 +29,8 @@ require 'protocol/http/middleware'
|
|
29
29
|
module Async
|
30
30
|
module HTTP
|
31
31
|
class Server < ::Protocol::HTTP::Middleware
|
32
|
-
def self.for(*
|
33
|
-
self.new(block, *
|
32
|
+
def self.for(*arguments, &block)
|
33
|
+
self.new(block, *arguments)
|
34
34
|
end
|
35
35
|
|
36
36
|
def initialize(app, endpoint, protocol = endpoint.protocol, scheme = endpoint.scheme)
|
data/lib/async/http/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.50.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 1.27.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: async-pool
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.2'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: protocol-http
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -218,7 +232,6 @@ files:
|
|
218
232
|
- lib/async/http/client.rb
|
219
233
|
- lib/async/http/endpoint.rb
|
220
234
|
- lib/async/http/internet.rb
|
221
|
-
- lib/async/http/pool.rb
|
222
235
|
- lib/async/http/protocol.rb
|
223
236
|
- lib/async/http/protocol/http1.rb
|
224
237
|
- lib/async/http/protocol/http1/client.rb
|
@@ -247,7 +260,8 @@ files:
|
|
247
260
|
- tasks/h2spec.rake
|
248
261
|
- tasks/server.rake
|
249
262
|
homepage: https://github.com/socketry/async-http
|
250
|
-
licenses:
|
263
|
+
licenses:
|
264
|
+
- MIT
|
251
265
|
metadata: {}
|
252
266
|
post_install_message:
|
253
267
|
rdoc_options: []
|
@@ -264,7 +278,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
264
278
|
- !ruby/object:Gem::Version
|
265
279
|
version: '0'
|
266
280
|
requirements: []
|
267
|
-
rubygems_version: 3.
|
281
|
+
rubygems_version: 3.1.2
|
268
282
|
signing_key:
|
269
283
|
specification_version: 4
|
270
284
|
summary: A HTTP client and server library.
|
data/lib/async/http/pool.rb
DELETED
@@ -1,187 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
#
|
3
|
-
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
22
|
-
|
23
|
-
require 'async/logger'
|
24
|
-
require 'async/notification'
|
25
|
-
|
26
|
-
module Async
|
27
|
-
module HTTP
|
28
|
-
# Pool behaviours
|
29
|
-
#
|
30
|
-
# - Single request per connection (HTTP/1 without keep-alive)
|
31
|
-
# - Multiple sequential requests per connection (HTTP1 with keep-alive)
|
32
|
-
# - Multiplex requests per connection (HTTP2)
|
33
|
-
#
|
34
|
-
# In general we don't know the policy until connection is established.
|
35
|
-
#
|
36
|
-
# This pool doesn't impose a maximum number of open resources, but it WILL block if there are no available resources and trying to allocate another one fails.
|
37
|
-
#
|
38
|
-
# Resources must respond to
|
39
|
-
# #multiplex -> 1 or more.
|
40
|
-
# #reusable? -> can be used again.
|
41
|
-
#
|
42
|
-
class Pool
|
43
|
-
def initialize(limit = nil, &block)
|
44
|
-
@resources = {} # resource => count
|
45
|
-
@available = Async::Notification.new
|
46
|
-
|
47
|
-
@limit = limit
|
48
|
-
|
49
|
-
@constructor = block
|
50
|
-
@guard = Async::Semaphore.new(1)
|
51
|
-
end
|
52
|
-
|
53
|
-
# The number of allocated resources.
|
54
|
-
def active
|
55
|
-
@resources.count
|
56
|
-
end
|
57
|
-
|
58
|
-
# Whether there are resources which are currently in use.
|
59
|
-
def busy?
|
60
|
-
@resources.collect do |_, usage|
|
61
|
-
return true if usage > 0
|
62
|
-
end
|
63
|
-
|
64
|
-
return false
|
65
|
-
end
|
66
|
-
|
67
|
-
# Wait until a pool resource has been freed.
|
68
|
-
def wait
|
69
|
-
@available.wait
|
70
|
-
end
|
71
|
-
|
72
|
-
# All allocated resources.
|
73
|
-
attr :resources
|
74
|
-
|
75
|
-
def empty?
|
76
|
-
@resources.empty?
|
77
|
-
end
|
78
|
-
|
79
|
-
def acquire
|
80
|
-
resource = wait_for_resource
|
81
|
-
|
82
|
-
return resource unless block_given?
|
83
|
-
|
84
|
-
begin
|
85
|
-
yield resource
|
86
|
-
ensure
|
87
|
-
release(resource)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# Make the resource resources and let waiting tasks know that there is something resources.
|
92
|
-
def release(resource)
|
93
|
-
# A resource that is not good should also not be reusable.
|
94
|
-
if resource.reusable?
|
95
|
-
reuse(resource)
|
96
|
-
else
|
97
|
-
retire(resource)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def close
|
102
|
-
@resources.each_key(&:close)
|
103
|
-
@resources.clear
|
104
|
-
end
|
105
|
-
|
106
|
-
def to_s
|
107
|
-
"\#<#{self.class} resources=#{availability_string} limit=#{@limit.inspect}>"
|
108
|
-
end
|
109
|
-
|
110
|
-
protected
|
111
|
-
|
112
|
-
def availability_string
|
113
|
-
@resources.collect do |resource,usage|
|
114
|
-
"#{usage}/#{resource.multiplex}#{resource.connected? ? '' : '*'}/#{resource.count}"
|
115
|
-
end.join(";")
|
116
|
-
end
|
117
|
-
|
118
|
-
def reuse(resource)
|
119
|
-
Async.logger.debug(self) {"Reuse #{resource}"}
|
120
|
-
|
121
|
-
@resources[resource] -= 1
|
122
|
-
|
123
|
-
@available.signal
|
124
|
-
end
|
125
|
-
|
126
|
-
def retire(resource)
|
127
|
-
Async.logger.debug(self) {"Retire #{resource}"}
|
128
|
-
|
129
|
-
@resources.delete(resource)
|
130
|
-
|
131
|
-
resource.close
|
132
|
-
|
133
|
-
@available.signal
|
134
|
-
end
|
135
|
-
|
136
|
-
def wait_for_resource
|
137
|
-
# If we fail to create a resource (below), we will end up waiting for one to become resources.
|
138
|
-
until resource = available_resource
|
139
|
-
@available.wait
|
140
|
-
end
|
141
|
-
|
142
|
-
Async.logger.debug(self) {"Wait for resource #{resource}"}
|
143
|
-
|
144
|
-
if resource.multiplex
|
145
|
-
@available.signal
|
146
|
-
end
|
147
|
-
|
148
|
-
return resource
|
149
|
-
end
|
150
|
-
|
151
|
-
def create
|
152
|
-
# This might return nil, which means creating the resource failed.
|
153
|
-
if resource = @constructor.call
|
154
|
-
@resources[resource] = 1
|
155
|
-
end
|
156
|
-
|
157
|
-
return resource
|
158
|
-
end
|
159
|
-
|
160
|
-
def available_resource
|
161
|
-
# TODO This is a linear search... not ideal, but simple for now.
|
162
|
-
@resources.each do |resource, count|
|
163
|
-
if count < resource.multiplex
|
164
|
-
# We want to use this resource... but is it connected?
|
165
|
-
if resource.connected?
|
166
|
-
@resources[resource] += 1
|
167
|
-
|
168
|
-
return resource
|
169
|
-
else
|
170
|
-
retire(resource)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
@guard.acquire do
|
176
|
-
if @limit.nil? or self.active < @limit
|
177
|
-
Async.logger.debug(self) {"No resources resources, allocating new one..."}
|
178
|
-
|
179
|
-
return create
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
return nil
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|