Class: HTTPX::Session
- Inherits:
-
Object
- Object
- HTTPX::Session
- Includes:
- Chainable, Loggable, ForkTracker
- Defined in:
- lib/httpx/session.rb
Overview
Class implementing the APIs being used publicly.
HTTPX.get(..) #=> delegating to an internal HTTPX::Session object.
HTTPX.plugin(..).get(..) #=> creating an intermediate HTTPX::Session with plugin, then sending the GET request
Defined Under Namespace
Modules: ForkTracker
Constant Summary
Constants included from Loggable
Loggable::COLORS, Loggable::USE_DEBUG_LOG
Class Attribute Summary collapse
-
.default_options ⇒ Object
readonly
Returns the value of attribute default_options.
Class Method Summary collapse
- .inherited(klass) ⇒ Object
-
.plugin(pl, options = nil, &block) ⇒ Object
returns a new HTTPX::Session instance, with the plugin pointed by
pl
loaded.
Instance Method Summary collapse
-
#build_request(verb, uri, params = EMPTY_HASH, options = @options) ⇒ Object
returns a HTTP::Request instance built from the HTTP
verb
, the requesturi
, and the optional set of request-specificoptions
. -
#close(selector = Selector.new) ⇒ Object
closes all the active connections from the session.
- #deselect_connection(connection, selector, cloned = false) ⇒ Object
- #deselect_resolver(resolver, selector) ⇒ Object
-
#find_connection(request_uri, selector, options) ⇒ Object
returns the HTTPX::Connection through which the
request
should be sent through. -
#initialize(options = EMPTY_HASH, &blk) ⇒ Session
constructor
initializes the session with a set of
options
, which will be shared by all requests sent from it. - #pin_connection(connection, selector) ⇒ Object
-
#request(*args, **params) ⇒ Object
performs one, or multple requests; it accepts:.
- #select_connection(connection, selector) ⇒ Object (also: #select_resolver)
- #try_clone_connection(connection, selector, family) ⇒ Object
-
#wrap ⇒ Object
Yields itself the block, then closes it after the block is evaluated.
Methods included from Chainable
Methods included from Loggable
#log, #log_exception, #log_redact
Methods included from ForkTracker
Constructor Details
#initialize(options = EMPTY_HASH, &blk) ⇒ Session
initializes the session with a set of options
, which will be shared by all requests sent from it.
When pass a block, it’ll yield itself to it, then closes after the block is evaluated.
16 17 18 19 20 21 22 23 24 |
# File 'lib/httpx/session.rb', line 16 def initialize( = EMPTY_HASH, &blk) @options = self.class..merge() @persistent = @options.persistent @pool = @options.pool_class.new(@options.) @wrapped = false @closing = false INSTANCES[self] = self if @persistent && @options.close_on_fork && INSTANCES wrap(&blk) if blk end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class HTTPX::Chainable
Class Attribute Details
.default_options ⇒ Object (readonly)
Returns the value of attribute default_options.
437 438 439 |
# File 'lib/httpx/session.rb', line 437 def @default_options end |
Class Method Details
.inherited(klass) ⇒ Object
439 440 441 442 443 444 |
# File 'lib/httpx/session.rb', line 439 def inherited(klass) super klass.instance_variable_set(:@default_options, @default_options) klass.instance_variable_set(:@plugins, @plugins.dup) klass.instance_variable_set(:@callbacks, @callbacks.dup) end |
.plugin(pl, options = nil, &block) ⇒ Object
returns a new HTTPX::Session instance, with the plugin pointed by pl
loaded.
session_with_retries = session.plugin(:retries)
session_with_custom = session.plugin(CustomPlugin)
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
# File 'lib/httpx/session.rb', line 451 def plugin(pl, = nil, &block) label = pl # raise Error, "Cannot add a plugin to a frozen config" if frozen? pl = Plugins.load_plugin(pl) if pl.is_a?(Symbol) if !@plugins.include?(pl) @plugins << pl pl.load_dependencies(self, &block) if pl.respond_to?(:load_dependencies) @default_options = @default_options.dup include(pl::InstanceMethods) if defined?(pl::InstanceMethods) extend(pl::ClassMethods) if defined?(pl::ClassMethods) opts = @default_options opts.extend_with_plugin_classes(pl) if defined?(pl::OptionsMethods) (pl::OptionsMethods.instance_methods - Object.instance_methods).each do |meth| opts..method_added(meth) end @default_options = opts..new(opts) end @default_options = pl.(@default_options) if pl.respond_to?(:extra_options) @default_options = @default_options.merge() if if pl.respond_to?(:subplugins) pl.subplugins.transform_keys(&Plugins.method(:load_plugin)).each do |main_pl, sub_pl| # in case the main plugin has already been loaded, then apply subplugin functionality # immediately next unless @plugins.include?(main_pl) plugin(sub_pl, , &block) end end pl.configure(self, &block) if pl.respond_to?(:configure) if label.is_a?(Symbol) # in case an already-loaded plugin complements functionality of # the plugin currently being loaded, loaded it now @plugins.each do |registered_pl| next if registered_pl == pl next unless registered_pl.respond_to?(:subplugins) sub_pl = registered_pl.subplugins[label] next unless sub_pl plugin(sub_pl, , &block) end end @default_options.freeze set_temporary_name("#{superclass}/#{pl}") if respond_to?(:set_temporary_name) # ruby 3.4 only elsif # this can happen when two plugins are loaded, an one of them calls the other under the hood, # albeit changing some default. @default_options = pl.(@default_options) if pl.respond_to?(:extra_options) @default_options = @default_options.merge() if @default_options.freeze end self end |
Instance Method Details
#build_request(verb, uri, params = EMPTY_HASH, options = @options) ⇒ Object
returns a HTTP::Request instance built from the HTTP verb
, the request uri
, and the optional set of request-specific options
. This request must be sent through the same session it was built from.
req = session.build_request("GET", "https://server.com")
resp = session.request(req)
118 119 120 121 122 123 124 |
# File 'lib/httpx/session.rb', line 118 def build_request(verb, uri, params = EMPTY_HASH, = @options) rklass = .request_class request = rklass.new(verb, uri, , params) request.persistent = @persistent set_request_callbacks(request) request end |
#close(selector = Selector.new) ⇒ Object
closes all the active connections from the session.
when called directly without specifying selector
, all available connections will be picked up from the connection pool and closed. Connections in use by other sessions, or same session in a different thread, will not be reaped.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/httpx/session.rb', line 64 def close(selector = Selector.new) # throw resolvers away from the pool @pool.reset_resolvers # preparing to throw away connections while (connection = @pool.pop_connection) next if connection.state == :closed select_connection(connection, selector) end begin @closing = true selector.terminate ensure @closing = false end end |
#deselect_connection(connection, selector, cloned = false) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/httpx/session.rb', line 138 def deselect_connection(connection, selector, cloned = false) selector.deregister(connection) # when connections coalesce return if connection.state == :idle return if cloned return if @closing && connection.state == :closed @pool.checkin_connection(connection) end |
#deselect_resolver(resolver, selector) ⇒ Object
151 152 153 154 155 156 157 |
# File 'lib/httpx/session.rb', line 151 def deselect_resolver(resolver, selector) selector.deregister(resolver) return if @closing && resolver.closed? @pool.checkin_resolver(resolver) end |
#find_connection(request_uri, selector, options) ⇒ Object
returns the HTTPX::Connection through which the request
should be sent through.
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/httpx/session.rb', line 175 def find_connection(request_uri, selector, ) if (connection = selector.find_connection(request_uri, )) connection.idling if connection.state == :closed connection.log(level: 2) { "found connection##{connection.object_id}(#{connection.state}) in selector##{selector.object_id}" } return connection end connection = @pool.checkout_connection(request_uri, ) connection.log(level: 2) { "found connection##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" } case connection.state when :idle do_init_connection(connection, selector) when :open if .io select_connection(connection, selector) else pin_connection(connection, selector) end when :closing, :closed connection.idling select_connection(connection, selector) else pin_connection(connection, selector) end connection end |
#pin_connection(connection, selector) ⇒ Object
131 132 133 134 |
# File 'lib/httpx/session.rb', line 131 def pin_connection(connection, selector) connection.current_session = self connection.current_selector = selector end |
#request(*args, **params) ⇒ Object
performs one, or multple requests; it accepts:
-
one or multiple HTTPX::Request objects;
-
an HTTP verb, then a sequence of URIs or URI/options tuples;
-
one or multiple HTTP verb / uri / (optional) options tuples;
when present, the set of options
kwargs is applied to all of the sent requests.
respectively returns a single HTTPX::Response response, or all of them in an Array, in the same order.
resp1 = session.request(req1)
resp1, resp2 = session.request(req1, req2)
resp1 = session.request("GET", "https://server.org/a")
resp1, resp2 = session.request("GET", ["https://server.org/a", "https://server.org/b"])
resp1, resp2 = session.request(["GET", "https://server.org/a"], ["GET", "https://server.org/b"])
resp1 = session.request("POST", "https://server.org/a", form: { "foo" => "bar" })
resp1, resp2 = session.request(["POST", "https://server.org/a", form: { "foo" => "bar" }], ["GET", "https://server.org/b"])
resp1, resp2 = session.request("GET", ["https://server.org/a", "https://server.org/b"], headers: { "x-api-token" => "TOKEN" })
102 103 104 105 106 107 108 109 110 |
# File 'lib/httpx/session.rb', line 102 def request(*args, **params) raise ArgumentError, "must perform at least one request" if args.empty? requests = args.first.is_a?(Request) ? args : build_requests(*args, params) responses = send_requests(*requests) return responses.first if responses.size == 1 responses end |
#select_connection(connection, selector) ⇒ Object Also known as: select_resolver
126 127 128 129 |
# File 'lib/httpx/session.rb', line 126 def select_connection(connection, selector) pin_connection(connection, selector) selector.register(connection) end |
#try_clone_connection(connection, selector, family) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/httpx/session.rb', line 159 def try_clone_connection(connection, selector, family) connection.family ||= family return connection if connection.family == family new_connection = connection.class.new(connection.origin, connection.) new_connection.family = family connection.sibling = new_connection do_init_connection(new_connection, selector) new_connection end |
#wrap ⇒ Object
Yields itself the block, then closes it after the block is evaluated.
session.wrap do |http|
http.get("https://wikipedia.com")
end # wikipedia connection closes here
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/httpx/session.rb', line 31 def wrap prev_wrapped = @wrapped @wrapped = true was_initialized = false current_selector = get_current_selector do selector = Selector.new set_current_selector(selector) was_initialized = true selector end begin yield self ensure unless prev_wrapped if @persistent deactivate(current_selector) else close(current_selector) end end @wrapped = prev_wrapped set_current_selector(nil) if was_initialized end end |