Class: Hypertube::Core::Http2Client::Http2Client
- Inherits:
-
Object
- Object
- Hypertube::Core::Http2Client::Http2Client
show all
- Defined in:
- lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb
Defined Under Namespace
Classes: Http2TransportError
Constant Summary
collapse
- MAX_ATTEMPTS =
2
- DEFAULT_CONNECT_TIMEOUT_SECONDS =
120
- DEFAULT_RESPONSE_TIMEOUT_SECONDS =
180
%w[
connection
keep-alive
proxy-connection
transfer-encoding
upgrade
host
].freeze
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(connection_data) ⇒ Http2Client
Returns a new instance of Http2Client.
132
133
134
135
136
137
138
139
140
141
142
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 132
def initialize(connection_data)
@connection_data = connection_data
@send_receive_lock = Mutex.new
@url = connection_data.respond_to?(:hostname) ? connection_data.hostname : connection_data.to_s
@uri = URI.parse(@url)
unless %w[http https].include?(@uri.scheme.to_s.downcase)
raise "Http2Client requires 'http' (h2c) or 'https' (h2 over TLS) scheme. Provided URL: #{@url}"
end
@response_timeout = connection_data.respond_to?(:response_timeout) ? connection_data.response_timeout : DEFAULT_RESPONSE_TIMEOUT_SECONDS
@http_client = build_http_client
end
|
Class Method Details
.close(connection_data) ⇒ Object
71
72
73
74
75
76
77
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 71
def close(connection_data)
client = nil
@clients_lock.synchronize do
client = @clients.delete(connection_key(connection_data))
end
client&.close
end
|
.get_state(connection_data) ⇒ Object
79
80
81
82
83
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 79
def get_state(connection_data)
@clients_lock.synchronize do
@clients.key?(connection_key(connection_data)) ? :OPEN : nil
end
end
|
.send_message(connection_data, message) ⇒ Object
29
30
31
32
33
34
35
36
37
38
39
40
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 29
def send_message(connection_data, message)
raise ArgumentError, 'connection_data cannot be nil' if connection_data.nil?
raise ArgumentError, 'message cannot be nil' if message.nil?
begin
send_message_body(connection_data, message)
rescue StandardError
close(connection_data)
raise
end
end
|
.send_message_body(connection_data, message) ⇒ Object
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 42
def send_message_body(connection_data, message)
client = create_or_get_client(connection_data, expected_current: nil)
last_ex = nil
MAX_ATTEMPTS.times do |attempt|
begin
client.with_send_receive_lock do
return client.send_bytes(message)
end
rescue StandardError => ex
last_ex = ex
break if attempt == MAX_ATTEMPTS - 1
break unless transient_http2_error?(ex)
client = create_or_get_client(connection_data, expected_current: client)
end
end
if last_ex
e = RuntimeError.new("HTTP/2 send to #{connection_key(connection_data)} failed after #{MAX_ATTEMPTS} attempts. Last error: #{last_ex.message}")
e.set_backtrace(last_ex.backtrace)
raise e
end
raise RuntimeError, "HTTP/2 send to #{connection_key(connection_data)} failed after #{MAX_ATTEMPTS} attempts."
end
|
Instance Method Details
#close ⇒ Object
198
199
200
201
202
203
204
205
206
207
208
209
210
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 198
def close
return unless @http_client
if @http_client.respond_to?(:close)
@http_client.close
elsif @http_client.respond_to?(:shutdown)
@http_client.shutdown
end
rescue StandardError
ensure
@http_client = nil
end
|
#send_bytes(message) ⇒ Object
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 148
def send_bytes(message)
payload = normalize_payload(message)
response = nil
ensure_server_reachable!
Timeout.timeout(operation_timeout_seconds) do
response = @http_client.post(@url, headers: , body: payload)
if defined?(HTTPX::ErrorResponse) && response.is_a?(HTTPX::ErrorResponse)
response_error = response.respond_to?(:error) ? response.error : nil
details = response_error ? response_error.message : response.to_s
raise Http2TransportError, "HTTP/2 request to #{@url} failed: #{details}"
end
status_code = response.status.to_i
http_version = response.version.to_s
if !http_version.empty? && !http_version.start_with?('2')
raise RuntimeError, "HTTP/2 request to #{@url} failed: the endpoint did not negotiate HTTP/2."
end
reason = (response)
if status_code < 200 || status_code >= 300
raise RuntimeError, "HTTP/2 request to #{@url} failed with status #{status_code} #{reason}. "
end
return response.body.to_s.bytes
end
rescue Timeout::Error
timeout_text =
if @response_timeout && @response_timeout >= 0
"timed out after #{@response_timeout} seconds"
else
"timed out"
end
raise Http2TransportError, "HTTP/2 request to #{@url} #{timeout_text}. The server may not be responding."
rescue StandardError => e
if timeout_error?(e)
timeout_text =
if @response_timeout && @response_timeout >= 0
"timed out after #{@response_timeout} seconds"
else
"timed out"
end
raise Http2TransportError, "HTTP/2 request to #{@url} #{timeout_text}. The server may not be responding."
end
if defined?(HTTPX::Error) && e.is_a?(HTTPX::Error)
raise Http2TransportError, "HTTP/2 request to #{@url} failed: #{e.message}. The server may be unavailable or not responding."
end
raise
end
|
#with_send_receive_lock ⇒ Object
144
145
146
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 144
def with_send_receive_lock
@send_receive_lock.synchronize { yield }
end
|