Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.4.1"
".": "0.5.0"
}
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
configured_endpoints: 18
openapi_spec_hash: 153617b7252b1b12f21043b2a1246f8b
openapi_spec_hash: 539798fac79a1eeebf9ac4faa0492455
config_hash: 6dcf08c4324405f152d1da9fc11ab04a
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## 0.5.0 (2025-11-21)

Full Changelog: [v0.4.1...v0.5.0](https://github.com/openlayer-ai/openlayer-ruby/compare/v0.4.1...v0.5.0)

### Features

* **api:** api update ([e686c41](https://github.com/openlayer-ai/openlayer-ruby/commit/e686c41ce85b71f1d36e6e98c57fd1e15b0dba50))
* **api:** api update ([062f345](https://github.com/openlayer-ai/openlayer-ruby/commit/062f34578e996d2f947d6175656e29657bd6d325))
* handle thread interrupts in the core HTTP client ([ec67b44](https://github.com/openlayer-ai/openlayer-ruby/commit/ec67b44714f9f117f129ace368b40e47e9ec3f3c))


### Bug Fixes

* absolutely qualified uris should always override the default ([e245d11](https://github.com/openlayer-ai/openlayer-ruby/commit/e245d1191c6f5e73a5f4431a8bfff1989d828648))
* better thread safety via early initializing SSL store during HTTP client creation ([0855118](https://github.com/openlayer-ai/openlayer-ruby/commit/0855118d3873821c235675a70cce45283342cf8b))


### Chores

* bump dependency version and update sorbet types ([005fef1](https://github.com/openlayer-ai/openlayer-ruby/commit/005fef135da52869fae96c862fde529d2b1a7f03))
* explicitly require "base64" gem ([a83cb81](https://github.com/openlayer-ai/openlayer-ruby/commit/a83cb819307c7f60dc50613302e7b88238c35fae))

## 0.4.1 (2025-10-15)

Full Changelog: [v0.4.0...v0.4.1](https://github.com/openlayer-ai/openlayer-ruby/compare/v0.4.0...v0.4.1)
Expand Down
3 changes: 1 addition & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ group :development do
gem "sorbet"
gem "steep"
gem "syntax_tree"
# TODO: using a fork for now, the prettier below has a bug
gem "syntax_tree-rbs", github: "stainless-api/syntax_tree-rbs", branch: "main"
gem "syntax_tree-rbs", github: "ruby-syntax-tree/syntax_tree-rbs", branch: "main"
gem "tapioca"
end

Expand Down
84 changes: 42 additions & 42 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
GIT
remote: https://github.com/stainless-api/syntax_tree-rbs.git
revision: c30b50219918be7cfe3ef803a00b59d1e77fcada
remote: https://github.com/ruby-syntax-tree/syntax_tree-rbs.git
revision: f94bc3060682ffbd126e4d5086ffedc89073d626
branch: main
specs:
syntax_tree-rbs (1.0.0)
Expand All @@ -11,20 +11,20 @@ GIT
PATH
remote: .
specs:
openlayer (0.4.1)
openlayer (0.5.0)
connection_pool

GEM
remote: https://rubygems.org/
specs:
activesupport (8.0.2.1)
activesupport (8.1.1)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
json
logger (>= 1.4.2)
minitest (>= 5.1)
securerandom (>= 0.3)
Expand All @@ -33,22 +33,22 @@ GEM
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.3)
async (2.27.3)
async (2.34.0)
console (~> 1.29)
fiber-annotation
io-event (~> 1.11)
metrics (~> 0.12)
traces (~> 0.15)
traces (~> 0.18)
base64 (0.3.0)
benchmark (0.4.1)
bigdecimal (3.2.2)
benchmark (0.5.0)
bigdecimal (3.3.1)
concurrent-ruby (1.3.5)
connection_pool (2.5.3)
console (1.33.0)
connection_pool (2.5.4)
console (1.34.2)
fiber-annotation
fiber-local (~> 1.1)
json
crack (1.0.0)
crack (1.0.1)
bigdecimal
rexml
csv (3.3.5)
Expand All @@ -64,20 +64,20 @@ GEM
fiber-local (1.1.0)
fiber-storage
fiber-storage (1.0.1)
fileutils (1.7.3)
hashdiff (1.2.0)
fileutils (1.8.0)
hashdiff (1.2.1)
i18n (1.14.7)
concurrent-ruby (~> 1.0)
io-event (1.11.2)
json (2.13.2)
json (2.15.2)
language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.7.0)
metrics (0.13.0)
minitest (5.25.5)
metrics (0.15.0)
minitest (5.26.0)
minitest-focus (1.4.0)
minitest (>= 4, < 6)
minitest-hooks (1.5.2)
Expand All @@ -89,51 +89,51 @@ GEM
mutex_m (0.3.0)
netrc (0.11.0)
parallel (1.27.0)
parser (3.3.9.0)
parser (3.3.10.0)
ast (~> 2.4.1)
racc
prettier_print (1.2.1)
prism (1.4.0)
prism (1.6.0)
public_suffix (6.0.2)
racc (1.8.1)
rainbow (3.1.1)
rake (13.3.0)
rake (13.3.1)
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
rbi (0.3.6)
rbi (0.3.7)
prism (~> 1.0)
rbs (>= 3.4.4)
rbs (3.9.4)
rbs (3.9.5)
logger
redcarpet (3.6.1)
regexp_parser (2.11.2)
rexml (3.4.1)
rubocop (1.79.2)
regexp_parser (2.11.3)
rexml (3.4.4)
rubocop (1.81.7)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.46.0, < 2.0)
rubocop-ast (>= 1.47.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.46.0)
rubocop-ast (1.47.1)
parser (>= 3.3.7.2)
prism (~> 1.4)
ruby-progressbar (1.13.0)
securerandom (0.4.1)
sorbet (0.5.12424)
sorbet-static (= 0.5.12424)
sorbet-runtime (0.5.12424)
sorbet-static (0.5.12424-aarch64-linux)
sorbet-static (0.5.12424-universal-darwin)
sorbet-static (0.5.12424-x86_64-linux)
sorbet-static-and-runtime (0.5.12424)
sorbet (= 0.5.12424)
sorbet-runtime (= 0.5.12424)
sorbet (0.6.12690)
sorbet-static (= 0.6.12690)
sorbet-runtime (0.6.12690)
sorbet-static (0.6.12690-aarch64-linux)
sorbet-static (0.6.12690-universal-darwin)
sorbet-static (0.6.12690-x86_64-linux)
sorbet-static-and-runtime (0.6.12690)
sorbet (= 0.6.12690)
sorbet-runtime (= 0.6.12690)
spoom (1.6.3)
erubi (>= 1.10.0)
prism (>= 0.28.0)
Expand Down Expand Up @@ -174,14 +174,14 @@ GEM
terminal-table (4.0.0)
unicode-display_width (>= 1.1.1, < 4)
thor (1.4.0)
traces (0.17.0)
traces (0.18.2)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (3.1.5)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.3)
webmock (3.25.1)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.1.0)
uri (1.1.0)
webmock (3.26.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application
<!-- x-release-please-start-version -->

```ruby
gem "openlayer", "~> 0.4.1"
gem "openlayer", "~> 0.5.0"
```

<!-- x-release-please-end -->
Expand Down
2 changes: 2 additions & 0 deletions lib/openlayer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
# Standard libraries.
# rubocop:disable Lint/RedundantRequireStatement
require "English"
require "base64"
require "cgi"
require "date"
require "erb"
require "etc"
require "json"
require "net/http"
require "openssl"
require "pathname"
require "rbconfig"
require "securerandom"
Expand Down
8 changes: 7 additions & 1 deletion lib/openlayer/internal/transport/base_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ def initialize(
self.class::PLATFORM_HEADERS,
{
"accept" => "application/json",
"content-type" => "application/json"
"content-type" => "application/json",
"user-agent" => user_agent
},
headers
)
Expand All @@ -219,6 +220,11 @@ def initialize(
# @return [Hash{String=>String}]
private def auth_headers = {}

# @api private
#
# @return [String]
private def user_agent = "#{self.class.name}/Ruby #{Openlayer::VERSION}"

# @api private
#
# @return [String]
Expand Down
62 changes: 36 additions & 26 deletions lib/openlayer/internal/transport/pooled_net_requester.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ class PooledNetRequester
class << self
# @api private
#
# @param cert_store [OpenSSL::X509::Store]
# @param url [URI::Generic]
#
# @return [Net::HTTP]
def connect(url)
def connect(cert_store:, url:)
port =
case [url.port, url.scheme]
in [Integer, _]
Expand All @@ -33,6 +34,8 @@ def connect(url)
Net::HTTP.new(url.host, port).tap do
_1.use_ssl = %w[https wss].include?(url.scheme)
_1.max_retries = 0

(_1.cert_store = cert_store) if _1.use_ssl?
end
end

Expand Down Expand Up @@ -102,7 +105,7 @@ def build_request(request, &blk)
pool =
@mutex.synchronize do
@pools[origin] ||= ConnectionPool.new(size: @size) do
self.class.connect(url)
self.class.connect(cert_store: @cert_store, url: url)
end
end

Expand All @@ -128,40 +131,48 @@ def execute(request)
url, deadline = request.fetch_values(:url, :deadline)

req = nil
eof = false
finished = false
closing = nil

# rubocop:disable Metrics/BlockLength
enum = Enumerator.new do |y|
next if finished

with_pool(url, deadline: deadline) do |conn|
req, closing = self.class.build_request(request) do
self.class.calibrate_socket_timeout(conn, deadline)
end

self.class.calibrate_socket_timeout(conn, deadline)
unless conn.started?
conn.keep_alive_timeout = self.class::KEEP_ALIVE_TIMEOUT
conn.start
end
eof = false
closing = nil
::Thread.handle_interrupt(Object => :never) do
::Thread.handle_interrupt(Object => :immediate) do
req, closing = self.class.build_request(request) do
self.class.calibrate_socket_timeout(conn, deadline)
end

self.class.calibrate_socket_timeout(conn, deadline)
conn.request(req) do |rsp|
y << [req, rsp]
break if finished

rsp.read_body do |bytes|
y << bytes.force_encoding(Encoding::BINARY)
break if finished
self.class.calibrate_socket_timeout(conn, deadline)
unless conn.started?
conn.keep_alive_timeout = self.class::KEEP_ALIVE_TIMEOUT
conn.start
end

self.class.calibrate_socket_timeout(conn, deadline)
conn.request(req) do |rsp|
y << [req, rsp]
break if finished

rsp.read_body do |bytes|
y << bytes.force_encoding(Encoding::BINARY)
break if finished

self.class.calibrate_socket_timeout(conn, deadline)
end
eof = true
end
end
ensure
begin
conn.finish if !eof && conn&.started?
ensure
closing&.call
end
eof = true
end
ensure
conn.finish if !eof && conn&.started?
end
rescue Timeout::Error
raise Openlayer::Errors::APITimeoutError.new(url: url, request: req)
Expand All @@ -174,8 +185,6 @@ def execute(request)
body = Openlayer::Internal::Util.fused_enum(enum, external: true) do
finished = true
loop { enum.next }
ensure
closing&.call
end
[Integer(response.code), response, body]
end
Expand All @@ -186,6 +195,7 @@ def execute(request)
def initialize(size: self.class::DEFAULT_MAX_CONNECTIONS)
@mutex = Mutex.new
@size = size
@cert_store = OpenSSL::X509::Store.new.tap(&:set_default_paths)
@pools = {}
end

Expand Down
Loading