diff options
Diffstat (limited to 'lib/net')
| -rw-r--r-- | lib/net/hippie.rb | 1 | ||||
| -rw-r--r-- | lib/net/hippie/connection.rb | 39 | ||||
| -rw-r--r-- | lib/net/hippie/rust_backend.rb | 72 | ||||
| -rw-r--r-- | lib/net/hippie/rust_connection.rb | 73 |
4 files changed, 185 insertions, 0 deletions
diff --git a/lib/net/hippie.rb b/lib/net/hippie.rb index d71fe68..b19ab63 100644 --- a/lib/net/hippie.rb +++ b/lib/net/hippie.rb @@ -10,6 +10,7 @@ require 'net/hippie/version' require 'net/hippie/client' require 'net/hippie/connection' require 'net/hippie/content_type_mapper' +require 'net/hippie/rust_backend' module Net # net/http for hippies. diff --git a/lib/net/hippie/connection.rb b/lib/net/hippie/connection.rb index 599d754..35a478a 100644 --- a/lib/net/hippie/connection.rb +++ b/lib/net/hippie/connection.rb @@ -1,10 +1,49 @@ # frozen_string_literal: true +require_relative 'rust_backend' + module Net module Hippie # A connection to a specific host class Connection def initialize(scheme, host, port, options = {}) + @scheme = scheme + @host = host + @port = port + @options = options + + if RustBackend.enabled? + require_relative 'rust_connection' + @backend = RustConnection.new(scheme, host, port, options) + else + @backend = create_ruby_backend(scheme, host, port, options) + end + end + + def run(request) + @backend.run(request) + end + + def build_url_for(path) + @backend.build_url_for(path) + end + + private + + def create_ruby_backend(scheme, host, port, options) + # This is the original Ruby implementation wrapped in an object + # that matches the same interface as RustConnection + RubyConnection.new(scheme, host, port, options) + end + end + + # Wrapper for the original Ruby implementation + class RubyConnection + def initialize(scheme, host, port, options = {}) + @scheme = scheme + @host = host + @port = port + http = Net::HTTP.new(host, port) http.read_timeout = options.fetch(:read_timeout, 10) http.open_timeout = options.fetch(:open_timeout, 10) diff --git a/lib/net/hippie/rust_backend.rb b/lib/net/hippie/rust_backend.rb new file mode 100644 index 0000000..7d1637e --- /dev/null +++ b/lib/net/hippie/rust_backend.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +module Net + module Hippie + # Rust backend integration + module RustBackend + @rust_available = nil + + def self.available? + return @rust_available unless @rust_available.nil? + + @rust_available = begin + require 'net_hippie_ext' + true + rescue LoadError + false + end + end + + def self.enabled? + ENV['NET_HIPPIE_RUST'] == 'true' && available? + end + + # Adapter to make RustResponse behave like Net::HTTPResponse + class ResponseAdapter + def initialize(rust_response) + @rust_response = rust_response + @code = rust_response.code + @body = rust_response.body + end + + def code + @code + end + + def body + @body + end + + def [](header_name) + @rust_response[header_name.to_s] + end + + def class + case @code.to_i + when 200 + Net::HTTPOK + when 201 + Net::HTTPCreated + when 300..399 + Net::HTTPRedirection + when 400..499 + Net::HTTPClientError + when 500..599 + Net::HTTPServerError + else + Net::HTTPResponse + end + end + + # Make it behave like the expected response class + def is_a?(klass) + self.class == klass || super + end + + def kind_of?(klass) + is_a?(klass) + end + end + end + end +end
\ No newline at end of file diff --git a/lib/net/hippie/rust_connection.rb b/lib/net/hippie/rust_connection.rb new file mode 100644 index 0000000..7c37350 --- /dev/null +++ b/lib/net/hippie/rust_connection.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require_relative 'rust_backend' + +module Net + module Hippie + # Rust-powered connection that mimics the Ruby Connection interface + class RustConnection + def initialize(scheme, host, port, options = {}) + @scheme = scheme + @host = host + @port = port + @options = options + + # Create the Rust client (simplified version for now) + @rust_client = Net::Hippie::RustClient.new + end + + def run(request) + url = build_url_for(request.path) + headers = {} # Simplified for now + body = request.body || '' + method = extract_method(request) + + begin + rust_response = @rust_client.public_send(method.downcase, url, headers, body) + RustBackend::ResponseAdapter.new(rust_response) + rescue => e + # Map Rust errors to Ruby equivalents + raise map_rust_error(e) + end + end + + def build_url_for(path) + return path if path.start_with?('http') + + port_suffix = (@port == 80 && @scheme == 'http') || (@port == 443 && @scheme == 'https') ? '' : ":#{@port}" + "#{@scheme}://#{@host}#{port_suffix}#{path}" + end + + private + + def extract_headers(request) + headers = {} + request.each_header do |key, value| + headers[key] = value + end + headers + end + + def extract_method(request) + request.class.name.split('::').last.sub('HTTP', '').downcase + end + + def map_rust_error(error) + case error.message + when /Net::ReadTimeout/ + Net::ReadTimeout.new + when /Net::OpenTimeout/ + Net::OpenTimeout.new + when /Errno::ECONNREFUSED/ + Errno::ECONNREFUSED.new + when /Errno::ECONNRESET/ + Errno::ECONNRESET.new + when /timeout/i + Net::ReadTimeout.new + else + error + end + end + end + end +end
\ No newline at end of file |
