Module: OnyxCord::Internal::HTTP
- Defined in:
- lib/onyxcord/internal/http.rb
Overview
Modern HTTP adapter wrapping HTTPX with persistent connections, automatic retries on 502, and a response interface compatible with the rest of OnyxCord.
Defined Under Namespace
Classes: Response
Constant Summary collapse
- POOL_OPTIONS =
{ max_connections: 50, max_connections_per_origin: 20, pool_timeout: 10 }.freeze
Class Method Summary collapse
- .delete(url, **headers) ⇒ Object
-
.get(url, **headers) ⇒ Object
Convenience wrappers.
- .multipart?(body) ⇒ Boolean
- .multipart_body(body, boundary) ⇒ Object
- .multipart_content_type(filename) ⇒ Object
- .multipart_parts(body) ⇒ Object
- .patch(url, body = nil, **headers) ⇒ Object
- .post(url, body = nil, **headers) ⇒ Object
- .post_multipart(url, body, headers) ⇒ Object
- .put(url, body = nil, **headers) ⇒ Object
-
.request(type, url, body = nil, **headers) ⇒ Response
Perform a raw HTTP request and return a Response.
-
.reset! ⇒ Object
Reset the HTTP session (useful for tests).
-
.session ⇒ Object
The shared HTTPX session with persistent, pooled connections.
- .session_mutex ⇒ Object
Class Method Details
.delete(url, **headers) ⇒ Object
217 218 219 |
# File 'lib/onyxcord/internal/http.rb', line 217 def delete(url, **headers) request(:delete, url, nil, **headers) end |
.get(url, **headers) ⇒ Object
Convenience wrappers
201 202 203 |
# File 'lib/onyxcord/internal/http.rb', line 201 def get(url, **headers) request(:get, url, nil, **headers) end |
.multipart?(body) ⇒ Boolean
181 182 183 184 185 |
# File 'lib/onyxcord/internal/http.rb', line 181 def multipart?(body) return true if body.is_a?(Array) && body.all? { |part| part.is_a?(Hash) && part[:name] && part.key?(:value) } body.is_a?(Hash) && body.any? { |_, value| value.respond_to?(:read) || value.respond_to?(:path) } end |
.multipart_body(body, boundary) ⇒ Object
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/onyxcord/internal/http.rb', line 137 def multipart_body(body, boundary) output = String.new(encoding: Encoding::BINARY) multipart_parts(body).each do |part| key = part[:name] value = part[:value] output << "--#{boundary}\r\n" if part[:filename] value.rewind if value.respond_to?(:rewind) filename = part[:filename] output << "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{filename}\"\r\n" output << "Content-Type: #{part[:content_type] || multipart_content_type(filename)}\r\n\r\n" output << value.read.to_s else output << "Content-Disposition: form-data; name=\"#{key}\"\r\n" output << "\r\n" output << value.to_s end output << "\r\n" end output << "--#{boundary}--\r\n" end |
.multipart_content_type(filename) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/onyxcord/internal/http.rb', line 161 def multipart_content_type(filename) ext = File.extname(filename).downcase case ext when '.txt' then 'text/plain' when '.json' then 'application/json' when '.xml' then 'application/xml' when '.png' then 'image/png' when '.jpg', '.jpeg' then 'image/jpeg' when '.gif' then 'image/gif' when '.webp' then 'image/webp' when '.mp3' then 'audio/mpeg' when '.mp4' then 'video/mp4' when '.ogg' then 'audio/ogg' when '.wav' then 'audio/wav' when '.pdf' then 'application/pdf' when '.zip' then 'application/zip' else 'application/octet-stream' end end |
.multipart_parts(body) ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/onyxcord/internal/http.rb', line 187 def multipart_parts(body) return body if body.is_a?(Array) body.map do |key, value| if value.respond_to?(:read) || value.respond_to?(:path) upload = Upload.wrap(value) { name: key, value: upload, filename: upload.filename, content_type: upload.content_type } else { name: key, value: value } end end end |
.patch(url, body = nil, **headers) ⇒ Object
213 214 215 |
# File 'lib/onyxcord/internal/http.rb', line 213 def patch(url, body = nil, **headers) request(:patch, url, body, **headers) end |
.post(url, body = nil, **headers) ⇒ Object
205 206 207 |
# File 'lib/onyxcord/internal/http.rb', line 205 def post(url, body = nil, **headers) request(:post, url, body, **headers) end |
.post_multipart(url, body, headers) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/onyxcord/internal/http.rb', line 124 def post_multipart(url, body, headers) uri = URI(url) boundary = "----OnyxCord#{SecureRandom.hex(12)}" request = Net::HTTP::Post.new(uri) headers.each { |key, value| request[key.to_s] = value } request['Content-Type'] = "multipart/form-data; boundary=#{boundary}" request.body = multipart_body(body, boundary) Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http| http.request(request) end end |
.put(url, body = nil, **headers) ⇒ Object
209 210 211 |
# File 'lib/onyxcord/internal/http.rb', line 209 def put(url, body = nil, **headers) request(:put, url, body, **headers) end |
.request(type, url, body = nil, **headers) ⇒ Response
Perform a raw HTTP request and return a Response.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/onyxcord/internal/http.rb', line 95 def request(type, url, body = nil, **headers) http = session.with(headers: headers) raw = case type when :get http.get(url) when :post if multipart?(body) # Multipart upload post_multipart(url, body, headers) else http.post(url, body: body) end when :put http.put(url, body: body) when :patch http.patch(url, body: body) when :delete http.delete(url) else raise ArgumentError, "Unknown HTTP method: #{type}" end # HTTPX returns an error response object on network failures raise raw.error if raw.is_a?(HTTPX::ErrorResponse) Response.new(raw) end |
.reset! ⇒ Object
Reset the HTTP session (useful for tests).
77 78 79 80 81 82 83 |
# File 'lib/onyxcord/internal/http.rb', line 77 def reset! session_mutex.synchronize do @session&.close if @session.respond_to?(:close) ensure @session = nil end end |
.session ⇒ Object
The shared HTTPX session with persistent, pooled connections.
64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/onyxcord/internal/http.rb', line 64 def session session_mutex.synchronize do @session ||= HTTPX.plugin(:persistent) .plugin(:follow_redirects) .with( fallback_protocol: 'http/1.1', ssl: { alpn_protocols: ['http/1.1'] }, pool_options: POOL_OPTIONS ) end end |
.session_mutex ⇒ Object
85 86 87 |
# File 'lib/onyxcord/internal/http.rb', line 85 def session_mutex @session_mutex ||= Mutex.new end |