added the ability to load plugins in the client, allowing to extend request/response/headers transparently

This commit is contained in:
HoneyryderChuck 2017-12-07 01:05:01 +00:00
parent 3df3eba0fc
commit 9c40845d94
7 changed files with 73 additions and 16 deletions

View File

@ -15,5 +15,29 @@ require "httpx/response"
require "httpx/client"
module HTTPX
# All plugins should be stored under this module/namespace. Can register and load
# plugins.
#
module Plugins
@plugins = {}
# Loads a plugin based on a name. If the plugin hasn't been loaded, tries to load
# it from the load path under "httpx/plugins/" directory.
#
def self.load_plugin(name)
h = @plugins
unless (plugin = h[name])
require "httpx/plugins/#{name}"
raise "Plugin #{name} hasn't been registered" unless (plugin = h[name])
end
plugin
end
# Registers a plugin (+mod+) in the central store indexed by +name+.
#
def self.register_plugin(name, mod)
@plugins[name] = mod
end
end
end

View File

@ -30,7 +30,7 @@ module HTTPX
def initialize(io, options, &on_response)
@io = io
@options = HTTPX::Options.new(options)
@options = Options.new(options)
@read_buffer = +""
@write_buffer = +""
@pending = []

View File

@ -61,7 +61,8 @@ module HTTPX
def on_headers_complete(h)
log { "headers received" }
response = Response.new(@selector, @parser.status_code, h)
headers = @options.headers_class.new(h)
response = @options.response_class.new(@selector, @parser.status_code, headers)
@responses << response
request = @requests[@responses.size - 1]
emit(:response, request, response)

View File

@ -45,9 +45,10 @@ module HTTPX
end
# stream.on(:half_close)
# stream.on(:altsvc)
stream.on(:headers) do |headers|
_, status = headers.shift
response = Response.new(@selector, status, headers)
stream.on(:headers) do |h|
_, status = h.shift
headers = @options.headers_class.new(h)
response = @options.response_class.new(@selector, status, headers)
@streams[stream.id] = response
emit(:response, request, response)
end

View File

@ -3,7 +3,7 @@
module HTTPX
class Client
def initialize(**options)
@default_options = Options.new(options)
@default_options = self.class.default_options.merge(options)
@connection = Connection.new(@default_options)
end
@ -12,7 +12,7 @@ module HTTPX
end
def request(verb, uri, **options)
Request.new(verb, uri, **@default_options.merge(options))
@default_options.request_class.new(verb, uri, **@default_options.merge(options))
end
def send(*requests)
@ -30,5 +30,32 @@ module HTTPX
end
requests.size == 1 ? responses.first : responses
end
@default_options = Options.new
class << self
attr_reader :default_options
def inherited(klass)
super
klass.instance_variable_set(:@default_options, @default_options.dup)
end
def plugin(pl, *args, &block)
# raise Error, "Cannot add a plugin to a frozen config" if frozen?
pl = Plugins.load_plugin(pl) if pl.is_a?(Symbol)
pl.load_dependencies(self, *args, &block) if pl.respond_to?(:load_dependencies)
include(pl::InstanceMethods) if defined?(pl::InstanceMethods)
extend(pl::ClassMethods) if defined?(pl::ClassMethods)
default_options.request_class.send(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
default_options.request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
default_options.response_class.send(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
default_options.response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
default_options.headers_class.send(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
default_options.headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
pl.configure(self, *args, &block) if pl.respond_to?(:configure)
nil
end
end
end
end

View File

@ -32,13 +32,16 @@ module HTTPX
def initialize(options = {})
defaults = {
:proxy => {},
:ssl => {},
:timeout => Timeout.by(:null),
:headers => {},
:cookies => {},
:max_concurrent_requests => MAX_CONCURRENT_REQUESTS,
:max_retries => MAX_RETRIES,
:proxy => {},
:ssl => {},
:timeout => Timeout.by(:null),
:headers => {},
:cookies => {},
:max_concurrent_requests => MAX_CONCURRENT_REQUESTS,
:max_retries => MAX_RETRIES,
:request_class => Class.new(Request),
:response_class => Class.new(Response),
:headers_class => Class.new(Headers),
}
defaults.merge!(options)
@ -70,6 +73,7 @@ module HTTPX
%w[
params form json body
proxy follow ssl max_retries
request_class response_class headers_class
].each do |method_name|
def_option(method_name)
end

View File

@ -36,7 +36,7 @@ module HTTPX
raise(Error, "unknown method: #{verb}") unless METHODS.include?(@verb)
@headers = Headers.new(@options.headers)
@headers = @options.headers_class.new(@options.headers)
@headers["user-agent"] ||= USER_AGENT
@headers["accept"] ||= "*/*"
@ -55,7 +55,7 @@ module HTTPX
end
def <<(data)
(@body ||= +"") << data
@body << data
end
def authority