Async::HTTPSourceAsyncHTTPInternet

class Internet

A high-level HTTP client for making requests to any URL, managing a pool of persistent connections keyed by host.

Nested

Definitions

def self.instance

The global instance of the internet.

Implementation

def self.instance
	::Thread.current.async_http_internet_instance ||= self.new
end

def initialize(**options)

Initialize the internet client.

Signature

parameter options Hash

Options to pass to the underlying class Async::HTTP::Client instances.

Implementation

def initialize(**options)
	@clients = Hash.new
	@options = options
end

attr :clients

A cache of clients.

Signature

attribute Hash(URI, Client)

def client_for(endpoint)

Get or create a client for the given endpoint.

Signature

parameter endpoint Endpoint

The endpoint to connect to.

returns Client

A client suitable for making requests to the endpoint.

Implementation

def client_for(endpoint)
	key = host_key(endpoint)
	
	@clients.fetch(key) do
		@clients[key] = self.make_client(endpoint)
	end
end

def call(verb, url, *arguments, **options, &block)

Make a request to the internet with the given method and url.

If you provide non-frozen headers, they may be mutated.

Signature

parameter method String

The request method, e.g. GET.

parameter url String

The URL to request, e.g. https://www.codeotaku.com.

parameter headers Hash | Protocol::HTTP::Headers

The headers to send with the request.

parameter body String | Protocol::HTTP::Body

The body to send with the request.

Implementation

def call(verb, url, *arguments, **options, &block)
	endpoint = Endpoint[url]
	client = self.client_for(endpoint)
	
	options[:authority] ||= endpoint.authority
	options[:scheme] ||= endpoint.scheme
	
	request = ::Protocol::HTTP::Request[verb, endpoint.path, *arguments, **options]
	
	response = client.call(request)
	
	return response unless block_given?
	
	begin
		yield response
	ensure
		response.close
	end
end

def close

Close all cached clients and release their resources.

Implementation

def close
	# The order of operations here is to avoid a race condition between iterating over clients (#close may yield) and creating new clients.
	clients = @clients.values
	@clients.clear
	
	clients.each(&:close)
end