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.
120
121
122
123
124
125
126
127
128
129
130
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 120
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
59
60
61
62
63
64
65
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 59
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
67
68
69
70
71
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 67
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
# 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?
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
186
187
188
189
190
191
192
193
194
195
196
197
198
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 186
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
136
137
138
139
140
141
142
143
144
145
146
147
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
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 136
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
132
133
134
|
# File 'lib/hypertube-ruby-sdk/core/http2_client/http2_client.rb', line 132
def with_send_receive_lock
@send_receive_lock.synchronize { yield }
end
|