simple_connect-client 0.4.1 → 0.4.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae7e0f3cdc244fc7c1712733d2133880ba990266836efc5c17cea62446c8404a
4
- data.tar.gz: 707d4208287010cc457b55952a2fd2ad52ec571ec03f55aafde77877f3b1e933
3
+ metadata.gz: f2aad5a1e606ce7a4e0f6865b23dc9b47a4e51ca16798d54680274f1869a0be4
4
+ data.tar.gz: 2d795adb31a236e0fff6867d369e3d5613f417ddce877a3cd627822d6bacbced
5
5
  SHA512:
6
- metadata.gz: 763c65eb40890daa5a3cf62591d83ae899cd54c1782da943b430d77190051f809bee18e5c0ac1f532920e8cc2d9832c567d6c2d8d3ae8739a71953027e16390f
7
- data.tar.gz: e8c9b418b9761f6e714ccc50524d32beac29f16d396d1439ff20c742b8d9389b54987f121a33171eb0a9288680ed7b73aaa17cb763967a9b5fedde4e1448eb55
6
+ metadata.gz: 5dedfab83ea079979e6c896b39dc4b7cd54f7fc02ca494906ccec03cfc8cefd6b0dcc728b4146b4d62980dbab465f8178fdc39ff8c317d9b94c2d1e7027ed9e9
7
+ data.tar.gz: 721910c69f6eda24a7e7fc9fa4a57e777d1c776f7967383b15f8978fca0f25981f5574b4fe4f13a5786c180e68dff80b79f43130b5d442af7a688b6bd57af746
@@ -31,17 +31,15 @@ module SimpleConnect
31
31
  # @param debug [Boolean] when true, log the complete outgoing request
32
32
  # (method, URL, headers, body) and the full response (status, headers,
33
33
  # body) for each message API call. Defaults to false.
34
+ # @param ip_version [Symbol, nil] pin the connection to a single IP
35
+ # family — `:ipv4` or `:ipv6` (see Request::IPV4 / Request::IPV6).
36
+ # Defaults to nil, which leaves resolution to the OS (dual-stack).
34
37
  def initialize(base_url:, api_key:,
35
38
  timeout: DEFAULT_TIMEOUT, logger: nil,
36
39
  max_attempts: nil, retryable: nil, user_agent: nil,
37
- debug: true)
38
- raise ConfigurationError, "base_url is required" if base_url.to_s.strip.empty?
39
- raise ConfigurationError, "api_key is required" if api_key.to_s.strip.empty?
40
-
41
- if max_attempts && retryable
42
- raise ConfigurationError,
43
- "pass either `max_attempts:` or `retryable:`, not both"
44
- end
40
+ debug: true, ip_version: nil)
41
+ validate_config!(base_url: base_url, api_key: api_key, max_attempts: max_attempts,
42
+ retryable: retryable, ip_version: ip_version)
45
43
 
46
44
  base_uri = URI.parse(base_url)
47
45
  request = Request.new(
@@ -49,9 +47,27 @@ module SimpleConnect
49
47
  timeout: timeout,
50
48
  logger: logger,
51
49
  retryable: retryable || Retryable.new(max_attempts: max_attempts || Retryable::DEFAULT_MAX_ATTEMPTS),
52
- debug: debug
50
+ debug: debug,
51
+ ip_version: ip_version
53
52
  )
54
53
  @messages = Api::Messages.new(request: request, base_uri: base_uri)
55
54
  end
55
+
56
+ private
57
+
58
+ def validate_config!(base_url:, api_key:, max_attempts:, retryable:, ip_version:)
59
+ raise ConfigurationError, "base_url is required" if base_url.to_s.strip.empty?
60
+ raise ConfigurationError, "api_key is required" if api_key.to_s.strip.empty?
61
+
62
+ if max_attempts && retryable
63
+ raise ConfigurationError,
64
+ "pass either `max_attempts:` or `retryable:`, not both"
65
+ end
66
+
67
+ return unless ip_version && !Request::IP_FAMILIES.key?(ip_version)
68
+
69
+ raise ConfigurationError,
70
+ "ip_version: must be #{Request::IPV4.inspect} or #{Request::IPV6.inspect}"
71
+ end
56
72
  end
57
73
  end
@@ -6,12 +6,19 @@ module SimpleConnect
6
6
  # delegated to the injected Retryable; per-retry sleep / delay policy lives
7
7
  # there (see SimpleConnect::Retryable).
8
8
  class Request
9
- def initialize(headers:, timeout:, retryable:, logger: nil, debug: false)
10
- @headers = headers
11
- @timeout = timeout
12
- @logger = logger
13
- @retryable = retryable
14
- @debug = debug
9
+ # Force the connection onto a single IP family instead of the OS default
10
+ # dual-stack resolution. nil leaves resolution to the OS.
11
+ IPV4 = :ipv4
12
+ IPV6 = :ipv6
13
+ IP_FAMILIES = { IPV4 => Socket::AF_INET, IPV6 => Socket::AF_INET6 }.freeze
14
+
15
+ def initialize(headers:, timeout:, retryable:, logger: nil, debug: false, ip_version: nil)
16
+ @headers = headers
17
+ @timeout = timeout
18
+ @logger = logger
19
+ @retryable = retryable
20
+ @debug = debug
21
+ @ip_version = ip_version
15
22
  end
16
23
 
17
24
  def get(uri, body: "")
@@ -66,9 +73,17 @@ module SimpleConnect
66
73
  http.use_ssl = uri.scheme == "https"
67
74
  http.read_timeout = @timeout
68
75
  http.open_timeout = @timeout
76
+ http.ipaddr = resolve_ip(uri.host) if @ip_version
69
77
  http
70
78
  end
71
79
 
80
+ # Pin the socket to the requested IP family while keeping the original
81
+ # host for the Host header and TLS SNI (Net::HTTP#ipaddr= preserves them).
82
+ def resolve_ip(host)
83
+ family = IP_FAMILIES.fetch(@ip_version)
84
+ Addrinfo.getaddrinfo(host, nil, family, :STREAM).first&.ip_address
85
+ end
86
+
72
87
  def build_net_http_request(http_method, uri, headers, body)
73
88
  case http_method
74
89
  when :get
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleConnect
4
- VERSION = "0.4.1"
4
+ VERSION = "0.4.2"
5
5
  end
@@ -4,6 +4,7 @@ require "json"
4
4
  require "net/http"
5
5
  require "openssl"
6
6
  require "securerandom"
7
+ require "socket"
7
8
  require "time"
8
9
  require "uri"
9
10
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_connect-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ramkrishan Patidar