async-http 0.49.1 → 0.50.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/.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
|