summaryrefslogtreecommitdiff
path: root/lib/net
diff options
context:
space:
mode:
Diffstat (limited to 'lib/net')
-rw-r--r--lib/net/hippie.rb1
-rw-r--r--lib/net/hippie/connection.rb39
-rw-r--r--lib/net/hippie/rust_backend.rb72
-rw-r--r--lib/net/hippie/rust_connection.rb73
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