From b2a29d9eb795dc50c02ee361bb908aa04c3b5514 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Tue, 14 Jul 2009 01:43:40 -0700 Subject: [PATCH] started extracting the http layer --- lib/couchrest.rb | 15 +-- lib/couchrest/core/adapters/restclient.rb | 35 +++++++ lib/couchrest/core/database.rb | 15 ++- lib/couchrest/core/document.rb | 4 - lib/couchrest/core/http_abstraction.rb | 48 +++++++++ lib/couchrest/mixins/views.rb | 2 +- lib/couchrest/monkeypatches.rb | 118 +++++++++++----------- spec/couchrest/core/couchrest_spec.rb | 2 +- 8 files changed, 158 insertions(+), 81 deletions(-) create mode 100644 lib/couchrest/core/adapters/restclient.rb create mode 100644 lib/couchrest/core/http_abstraction.rb diff --git a/lib/couchrest.rb b/lib/couchrest.rb index 1bad3ad..e824563 100644 --- a/lib/couchrest.rb +++ b/lib/couchrest.rb @@ -45,6 +45,7 @@ module CouchRest autoload :ExtendedDocument, 'couchrest/more/extended_document' autoload :CastedModel, 'couchrest/more/casted_model' + require File.join(File.dirname(__FILE__), 'couchrest', 'core', 'http_abstraction') require File.join(File.dirname(__FILE__), 'couchrest', 'mixins') # The CouchRest module methods handle the basic JSON serialization @@ -118,9 +119,9 @@ module CouchRest } end - # set proxy for RestClient to use + # set proxy to use def proxy url - RestClient.proxy = url + HttpAbstraction.proxy = url end # ensure that a database exists @@ -141,7 +142,7 @@ module CouchRest def put(uri, doc = nil) payload = doc.to_json if doc begin - JSON.parse(RestClient.put(uri, payload)) + JSON.parse(HttpAbstraction.put(uri, payload)) rescue Exception => e if $DEBUG raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}" @@ -153,7 +154,7 @@ module CouchRest def get(uri) begin - JSON.parse(RestClient.get(uri), :max_nesting => false) + JSON.parse(HttpAbstraction.get(uri), :max_nesting => false) rescue => e if $DEBUG raise "Error while sending a GET request #{uri}\n: #{e}" @@ -166,7 +167,7 @@ module CouchRest def post uri, doc = nil payload = doc.to_json if doc begin - JSON.parse(RestClient.post(uri, payload)) + JSON.parse(HttpAbstraction.post(uri, payload)) rescue Exception => e if $DEBUG raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}" @@ -177,11 +178,11 @@ module CouchRest end def delete uri - JSON.parse(RestClient.delete(uri)) + JSON.parse(HttpAbstraction.delete(uri)) end def copy uri, destination - JSON.parse(RestClient.copy(uri, {'Destination' => destination})) + JSON.parse(HttpAbstraction.copy(uri, {'Destination' => destination})) end def paramify_url url, params = {} diff --git a/lib/couchrest/core/adapters/restclient.rb b/lib/couchrest/core/adapters/restclient.rb new file mode 100644 index 0000000..ed02228 --- /dev/null +++ b/lib/couchrest/core/adapters/restclient.rb @@ -0,0 +1,35 @@ +module RestClientAdapter + + module API + def proxy=(url) + RestClient.proxy = url + end + + def proxy + RestClient.proxy + end + + def get(uri, headers={}) + RestClient.get(uri, headers) + end + + def post(uri, payload, headers={}) + RestClient.post(uri, payload, headers) + end + + def put(uri, payload, headers={}) + RestClient.put(uri, payload, headers) + end + + def delete(uri, headers={}) + RestClient.delete(uri, headers) + end + + def copy(uri, headers) + RestClient::Request.execute( :method => :copy, + :url => uri, + :headers => headers) + end + end + +end \ No newline at end of file diff --git a/lib/couchrest/core/database.rb b/lib/couchrest/core/database.rb index 6627117..08eb4cb 100644 --- a/lib/couchrest/core/database.rb +++ b/lib/couchrest/core/database.rb @@ -58,7 +58,7 @@ module CouchRest keys = params.delete(:keys) funcs = funcs.merge({:keys => keys}) if keys url = CouchRest.paramify_url "#{@root}/_temp_view", params - JSON.parse(RestClient.post(url, funcs.to_json, {"Content-Type" => 'application/json'})) + JSON.parse(HttpAbstraction.post(url, funcs.to_json, {"Content-Type" => 'application/json'})) end # backwards compatibility is a plus @@ -100,11 +100,8 @@ module CouchRest # GET an attachment directly from CouchDB def fetch_attachment(doc, name) - # slug = escape_docid(docid) - # name = CGI.escape(name) uri = url_for_attachment(doc, name) - RestClient.get uri - # "#{@uri}/#{slug}/#{name}" + HttpAbstraction.get uri end # PUT an attachment directly to CouchDB @@ -112,14 +109,14 @@ module CouchRest docid = escape_docid(doc['_id']) name = CGI.escape(name) uri = url_for_attachment(doc, name) - JSON.parse(RestClient.put(uri, file, options)) + JSON.parse(HttpAbstraction.put(uri, file, options)) end # DELETE an attachment directly from CouchDB def delete_attachment doc, name uri = url_for_attachment(doc, name) # this needs a rev - JSON.parse(RestClient.delete(uri)) + JSON.parse(HttpAbstraction.delete(uri)) end # Save a document to CouchDB. This will use the _id field from @@ -146,7 +143,7 @@ module CouchRest slug = escape_docid(doc['_id']) begin CouchRest.put "#{@root}/#{slug}", doc - rescue RestClient::ResourceNotFound + rescue HttpAbstraction::ResourceNotFound p "resource not found when saving even tho an id was passed" slug = doc['_id'] = @server.next_uuid CouchRest.put "#{@root}/#{slug}", doc @@ -252,7 +249,7 @@ module CouchRest def recreate! delete! create! - rescue RestClient::ResourceNotFound + rescue HttpAbstraction::ResourceNotFound ensure create! end diff --git a/lib/couchrest/core/document.rb b/lib/couchrest/core/document.rb index 941ed80..44c4f5a 100644 --- a/lib/couchrest/core/document.rb +++ b/lib/couchrest/core/document.rb @@ -3,10 +3,6 @@ require 'delegate' module CouchRest class Document < Response include CouchRest::Mixins::Attachments - - # def self.inherited(subklass) - # subklass.send(:extlib_inheritable_accessor, :database) - # end extlib_inheritable_accessor :database attr_accessor :database diff --git a/lib/couchrest/core/http_abstraction.rb b/lib/couchrest/core/http_abstraction.rb new file mode 100644 index 0000000..529866d --- /dev/null +++ b/lib/couchrest/core/http_abstraction.rb @@ -0,0 +1,48 @@ +require 'couchrest/core/adapters/restclient' + +# Abstraction layet for HTTP communications. +# +# By defining a basic API that CouchRest is relying on, +# it allows for easy experimentations and implementations of various libraries. +# +# Most of the API is based on the RestClient API that was used in the early version of CouchRest. +# +module HttpAbstraction + + # here is the list of exception expected by CouchRest + # please convert the underlying errors in this set of known + # exceptions. + class ResourceNotFound < StandardError; end + class RequestFailed < StandardError; end + class RequestTimeout < StandardError; end + class ServerBrokeConnection < StandardError; end + class Conflict < StandardError; end + + + # # Here is the API you need to implement if you want to write a new adapter + # # See adapters/restclient.rb for more information. + # + # def self.proxy=(url) + # end + # + # def self.proxy + # end + # + # def self.get(uri, headers=nil) + # end + # + # def self.post(uri, payload, headers=nil) + # end + # + # def self.put(uri, payload, headers=nil) + # end + # + # def self.delete(uri, headers=nil) + # end + # + # def self.copy(uri, headers) + # end + +end + +HttpAbstraction.extend(RestClientAdapter::API) \ No newline at end of file diff --git a/lib/couchrest/mixins/views.rb b/lib/couchrest/mixins/views.rb index 420b87a..d6abeb0 100644 --- a/lib/couchrest/mixins/views.rb +++ b/lib/couchrest/mixins/views.rb @@ -162,7 +162,7 @@ module CouchRest begin design_doc.view_on(db, view_name, opts, &block) # the design doc may not have been saved yet on this database - rescue RestClient::ResourceNotFound => e + rescue HttpAbstraction::ResourceNotFound => e if retryable save_design_doc_on(db) retryable = false diff --git a/lib/couchrest/monkeypatches.rb b/lib/couchrest/monkeypatches.rb index bebd49a..95c52c3 100644 --- a/lib/couchrest/monkeypatches.rb +++ b/lib/couchrest/monkeypatches.rb @@ -51,63 +51,63 @@ if RUBY_VERSION.to_f < 1.9 end end -module RestClient - def self.copy(url, headers={}) - Request.execute(:method => :copy, - :url => url, - :headers => headers) - end - -# class Request -# -# def establish_connection(uri) -# Thread.current[:connection].finish if (Thread.current[:connection] && Thread.current[:connection].started?) -# p net_http_class -# net = net_http_class.new(uri.host, uri.port) -# net.use_ssl = uri.is_a?(URI::HTTPS) -# net.verify_mode = OpenSSL::SSL::VERIFY_NONE -# Thread.current[:connection] = net -# Thread.current[:connection].start -# Thread.current[:connection] -# end -# -# def transmit(uri, req, payload) -# setup_credentials(req) -# -# Thread.current[:host] ||= uri.host -# Thread.current[:port] ||= uri.port -# -# if (Thread.current[:connection].nil? || (Thread.current[:host] != uri.host)) -# p "establishing a connection" -# establish_connection(uri) -# end +# module RestClient +# # def self.copy(url, headers={}) +# # Request.execute(:method => :copy, +# # :url => url, +# # :headers => headers) +# # end # -# display_log request_log -# http = Thread.current[:connection] -# http.read_timeout = @timeout if @timeout -# -# begin -# res = http.request(req, payload) -# rescue -# p "Net::HTTP connection failed, reconnecting" -# establish_connection(uri) -# http = Thread.current[:connection] -# require 'ruby-debug' -# req.body_stream = nil -# -# res = http.request(req, payload) -# display_log response_log(res) -# result res -# else -# display_log response_log(res) -# process_result res -# end -# -# rescue EOFError -# raise RestClient::ServerBrokeConnection -# rescue Timeout::Error -# raise RestClient::RequestTimeout -# end -# end - -end +# # class Request +# # +# # def establish_connection(uri) +# # Thread.current[:connection].finish if (Thread.current[:connection] && Thread.current[:connection].started?) +# # p net_http_class +# # net = net_http_class.new(uri.host, uri.port) +# # net.use_ssl = uri.is_a?(URI::HTTPS) +# # net.verify_mode = OpenSSL::SSL::VERIFY_NONE +# # Thread.current[:connection] = net +# # Thread.current[:connection].start +# # Thread.current[:connection] +# # end +# # +# # def transmit(uri, req, payload) +# # setup_credentials(req) +# # +# # Thread.current[:host] ||= uri.host +# # Thread.current[:port] ||= uri.port +# # +# # if (Thread.current[:connection].nil? || (Thread.current[:host] != uri.host)) +# # p "establishing a connection" +# # establish_connection(uri) +# # end +# # +# # display_log request_log +# # http = Thread.current[:connection] +# # http.read_timeout = @timeout if @timeout +# # +# # begin +# # res = http.request(req, payload) +# # rescue +# # p "Net::HTTP connection failed, reconnecting" +# # establish_connection(uri) +# # http = Thread.current[:connection] +# # require 'ruby-debug' +# # req.body_stream = nil +# # +# # res = http.request(req, payload) +# # display_log response_log(res) +# # result res +# # else +# # display_log response_log(res) +# # process_result res +# # end +# # +# # rescue EOFError +# # raise RestClient::ServerBrokeConnection +# # rescue Timeout::Error +# # raise RestClient::RequestTimeout +# # end +# # end +# +# end diff --git a/spec/couchrest/core/couchrest_spec.rb b/spec/couchrest/core/couchrest_spec.rb index 2ed8bb9..35e48e6 100644 --- a/spec/couchrest/core/couchrest_spec.rb +++ b/spec/couchrest/core/couchrest_spec.rb @@ -191,7 +191,7 @@ describe CouchRest do describe "using a proxy for RestClient connections" do it "should set proxy url for RestClient" do CouchRest.proxy 'http://localhost:8888/' - proxy_uri = URI.parse(RestClient.proxy) + proxy_uri = URI.parse(HttpAbstraction.proxy) proxy_uri.host.should eql( 'localhost' ) proxy_uri.port.should eql( 8888 ) CouchRest.proxy nil