uber-s3 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,5 @@
1
1
  class UberS3
2
2
  class Bucket
3
-
4
3
  attr_accessor :client, :name
5
4
 
6
5
  def initialize(client, name)
@@ -24,11 +23,11 @@ class UberS3
24
23
  def object(key)
25
24
  Object.new(self, key)
26
25
  end
26
+ alias_method :[], :object
27
27
 
28
28
  def get(key)
29
29
  object(key).fetch
30
30
  end
31
- alias_method :[], :get
32
31
 
33
32
  def exists?(key)
34
33
  object(key).exists?
@@ -40,6 +39,8 @@ class UberS3
40
39
 
41
40
 
42
41
  class ObjectList
42
+ include Enumerable
43
+
43
44
  attr_accessor :bucket, :key, :options, :objects
44
45
 
45
46
  def initialize(bucket, key, options={})
@@ -52,14 +53,10 @@ class UberS3
52
53
  def fetch(marker=nil)
53
54
  @objects = []
54
55
 
55
- response = bucket.connection.get("/?prefix=#{CGI.escape(key)}&marker=#{marker}")
56
- # response = bucket.connection.get("/?prefix=#{CGI.escape(key)}&marker=#{marker}&max-keys=2")
57
-
58
- if response[:status] != 200
59
- raise UberS3Error, response.inspect
60
- else
61
- @objects = parse_contents(response[:body])
62
- end
56
+ default_max_keys = 500
57
+ response = bucket.connection.get("/?prefix=#{CGI.escape(key)}&marker=#{marker}&max-keys=#{default_max_keys}")
58
+
59
+ @objects = parse_contents(response.body)
63
60
  end
64
61
 
65
62
  def parse_contents(xml)
@@ -5,9 +5,8 @@ module UberS3::Connection
5
5
  class EmHttp < Adapter
6
6
 
7
7
  # NOTE: this will be very difficult to support
8
- # with our interface.. will need lots of work
9
- # perhaps will limit async capabilities to
10
- # fibered mode
8
+ # with our interface.. will need lots of work.
9
+ # We may only want to support async with fibers.
11
10
 
12
11
  end
13
12
  end
@@ -14,12 +14,12 @@ module UberS3::Connection
14
14
 
15
15
  r = EM::HttpRequest.new(url).send(verb, params)
16
16
 
17
- {
17
+ UberS3::Response.new({
18
18
  :status => r.response_header.status,
19
19
  :header => r.response_header,
20
20
  :body => r.response,
21
21
  :raw => r
22
- }
22
+ })
23
23
  end
24
24
 
25
25
  end
@@ -25,12 +25,12 @@ module UberS3::Connection
25
25
  response_body = r.body
26
26
  end
27
27
 
28
- {
28
+ UberS3::Response.new({
29
29
  :status => r.code.to_i,
30
30
  :header => r.header.to_hash,
31
31
  :body => response_body,
32
32
  :raw => r
33
- }
33
+ })
34
34
  end
35
35
 
36
36
  end
@@ -0,0 +1,89 @@
1
+ class UberS3
2
+
3
+ module Error
4
+
5
+ class Standard < StandardError
6
+ def initialize(key, message)
7
+ super("#{key}: #{message}")
8
+ end
9
+ end
10
+
11
+ class Unknown < StandardError; end
12
+
13
+ class AccessDenied < Standard; end
14
+ class AccountProblem < Standard; end
15
+ class AmbiguousGrantByEmailAddress < Standard; end
16
+ class BadDigest < Standard; end
17
+ class BucketAlreadyExists < Standard; end
18
+ class BucketAlreadyOwnedByYou < Standard; end
19
+ class BucketNotEmpty < Standard; end
20
+ class CredentialsNotSupported < Standard; end
21
+ class CrossLocationLoggingProhibited < Standard; end
22
+ class EntityTooSmall < Standard; end
23
+ class EntityTooLarge < Standard; end
24
+ class ExpiredToken < Standard; end
25
+ class IllegalVersioningConfigurationException < Standard; end
26
+ class IncompleteBody < Standard; end
27
+ class IncorrectNumberOfFilesInPostRequest < Standard; end
28
+ class InlineDataTooLarge < Standard; end
29
+ class InternalError < Standard; end
30
+ class InvalidAccessKeyId < Standard; end
31
+ class InvalidAddressingHeader < Standard; end
32
+ class InvalidArgument < Standard; end
33
+ class InvalidBucketName < Standard; end
34
+ class InvalidDigest < Standard; end
35
+ class InvalidLocationConstraint < Standard; end
36
+ class InvalidPart < Standard; end
37
+ class InvalidPartOrder < Standard; end
38
+ class InvalidPayer < Standard; end
39
+ class InvalidPolicyDocument < Standard; end
40
+ class InvalidRange < Standard; end
41
+ class InvalidRequest < Standard; end
42
+ class InvalidSecurity < Standard; end
43
+ class InvalidSOAPRequest < Standard; end
44
+ class InvalidStorageClass < Standard; end
45
+ class InvalidTargetBucketForLogging < Standard; end
46
+ class InvalidToken < Standard; end
47
+ class InvalidURI < Standard; end
48
+ class KeyTooLong < Standard; end
49
+ class MalformedACLError < Standard; end
50
+ class MalformedPOSTRequest < Standard; end
51
+ class MalformedXML < Standard; end
52
+ class MaxMessageLengthExceeded < Standard; end
53
+ class MaxPostPreDataLengthExceededError < Standard; end
54
+ class MetadataTooLarge < Standard; end
55
+ class MethodNotAllowed < Standard; end
56
+ class MissingAttachment < Standard; end
57
+ class MissingContentLength < Standard; end
58
+ class MissingRequestBodyError < Standard; end
59
+ class MissingSecurityElement < Standard; end
60
+ class MissingSecurityHeader < Standard; end
61
+ class NoLoggingStatusForKey < Standard; end
62
+ class NoSuchBucket < Standard; end
63
+ class NoSuchKey < Standard; end
64
+ class NoSuchUpload < Standard; end
65
+ class NoSuchVersion < Standard; end
66
+ class NotImplemented < Standard; end
67
+ class NotSignedUp < Standard; end
68
+ class NotSuchBucketPolicy < Standard; end
69
+ class OperationAborted < Standard; end
70
+ class PermanentRedirect < Standard; end
71
+ class PreconditionFailed < Standard; end
72
+ class Redirect < Standard; end
73
+ class RequestIsNotMultiPartContent < Standard; end
74
+ class RequestTimeout < Standard; end
75
+ class RequestTimeTooSkewed < Standard; end
76
+ class RequestTorrentOfBucketError < Standard; end
77
+ class SignatureDoesNotMatch < Standard; end
78
+ class ServiceUnavailable < Standard; end
79
+ class SlowDown < Standard; end
80
+ class TemporaryRedirect < Standard; end
81
+ class TokenRefreshRequired < Standard; end
82
+ class TooManyBuckets < Standard; end
83
+ class UnexpectedContent < Standard; end
84
+ class UnresolvableGrantByEmailAddress < Standard; end
85
+ class UserKeyMustBeSpecified < Standard; end
86
+
87
+ end
88
+
89
+ end
@@ -1,25 +1,23 @@
1
1
  class UberS3
2
2
  class Object
3
- include Operation::Object::All
3
+ include Operation::Object::AccessPolicy
4
+ include Operation::Object::CacheControl
5
+ include Operation::Object::ContentDisposition
6
+ include Operation::Object::ContentEncoding
7
+ include Operation::Object::ContentMd5
8
+ include Operation::Object::ContentType
9
+ include Operation::Object::Expires
10
+ include Operation::Object::Meta
11
+ include Operation::Object::StorageClass
4
12
 
5
- attr_accessor :bucket, :key, :value, :size, :errors
6
-
7
- # attr_accessor :access,
8
- # :cache_control,
9
- # :content_disposition,
10
- # :content_encoding,
11
- # :size,
12
- # :content_md5,
13
- # :content_type,
14
- # :expires,
15
- # :storage_class
13
+ attr_accessor :bucket, :key, :value, :size, :error
16
14
 
17
15
  def initialize(bucket, key, value=nil, options={})
18
16
  self.bucket = bucket
19
17
  self.key = key
20
18
  self.value = value
21
19
 
22
- # Init state of object
20
+ # Init current state
23
21
  infer_content_type!
24
22
 
25
23
  # Call operation methods based on options passed
@@ -31,11 +29,11 @@ class UberS3
31
29
  end
32
30
 
33
31
  def exists?
34
- bucket.connection.head(key)[:status] == 200
32
+ bucket.connection.head(key).status == 200
35
33
  end
36
34
 
37
35
  def fetch
38
- self.value = bucket.connection.get(key)[:body]
36
+ self.value = bucket.connection.get(key).body
39
37
  self
40
38
  end
41
39
 
@@ -57,7 +55,9 @@ class UberS3
57
55
 
58
56
  # Content MD5 integrity check
59
57
  if !content_md5.nil?
60
- # Our object expects a md5 hex digest
58
+ self.content_md5 = Digest::MD5.hexdigest(value) if content_md5 == true
59
+
60
+ # We expect a md5 hex digest here
61
61
  md5_digest = content_md5.unpack('a2'*16).collect {|i| i.hex.chr }.join
62
62
  headers['Content-MD5'] = Base64.encode64(md5_digest).strip
63
63
  end
@@ -75,18 +75,15 @@ class UberS3
75
75
  # Let's do it
76
76
  response = bucket.connection.put(key, headers, value)
77
77
 
78
- if response[:status] != 200
79
- # TODO: .. we should raise stuff here!!!!!!!! exception handling....................
80
- self.errors = response[:body]
81
- else
82
- self.errors = nil
83
- end
78
+ # Update error state
79
+ self.error = response.error
84
80
 
85
- response[:status] == 200
81
+ # Test for success....
82
+ response.status == 200
86
83
  end
87
84
 
88
85
  def delete
89
- bucket.connection.delete(key)[:status] == 204
86
+ bucket.connection.delete(key).status == 204
90
87
  end
91
88
 
92
89
  def value
@@ -14,6 +14,7 @@ module UberS3::Operation::Object
14
14
  end
15
15
 
16
16
  module InstanceMethods
17
+ # TODO.. move stuff from object.rb to here... need callback / chaining stuff...
17
18
  end
18
19
 
19
20
  end
@@ -1,35 +1,7 @@
1
1
  class UberS3
2
2
  module Operation
3
-
4
- module Bucket
5
- module All
6
- def self.included(base)
7
- Operation.include_modules(base, 'bucket')
8
- end
9
- end
10
- end
11
-
12
- module Object
13
- module All
14
- def self.included(base)
15
- Operation.include_modules(base, 'object')
16
- end
17
- end
18
- end
19
-
20
- def include_modules(base, path)
21
- # Auto include modules of a particular path
22
- Dir[File.dirname(__FILE__)+"/operation/#{path}/*.rb"].each do |op|
23
- group_module_name = self.to_s + '::' + path.split('_').map {|x| x.capitalize}.join("")
24
- op_klass_name = File.basename(op).gsub(/.rb$/i, '').split('_').map {|x| x.capitalize}.join("")
25
-
26
- require op
27
- op_klass = instance_eval(group_module_name+'::'+op_klass_name)
28
-
29
- base.send :include, op_klass
30
- end
31
- end
32
- module_function :include_modules
33
-
34
3
  end
35
4
  end
5
+
6
+ # Load object operation modules
7
+ Dir[File.dirname(__FILE__) + '/operation/object/*.rb'].each {|f| require f }
@@ -0,0 +1,49 @@
1
+ class UberS3
2
+ class Response
3
+
4
+ attr_accessor :status, :header, :body, :raw, :error_key, :error_message
5
+
6
+ def initialize(options={})
7
+ if !([:status, :header, :body, :raw] - options.keys).empty?
8
+ raise "Expecting keys :status, :header, :body and :raw"
9
+ end
10
+
11
+ self.status = options[:status]
12
+ self.header = options[:header]
13
+ self.body = options[:body]
14
+ self.raw = options[:raw]
15
+
16
+ check_for_errors!
17
+ end
18
+
19
+ # TODO: can/should we normalize the keys..? downcase.. etc.?
20
+ # def header=(header)
21
+ # end
22
+
23
+ def check_for_errors!
24
+ return if status < 400 || body.to_s.empty?
25
+
26
+ # Errors are XML
27
+ doc = Util::XmlDocument.new(body)
28
+
29
+ self.error_key = doc.xpath('//Error/Code').first.text
30
+ self.error_message = doc.xpath('//Error/Message').first.text
31
+
32
+ error_klass = instance_eval("Error::#{error_key}") rescue nil
33
+
34
+ if error_klass.nil?
35
+ raise Error::Unknown, "HTTP Response: #{status}, Body: #{body}"
36
+ else
37
+ raise error_klass.new(error_key, error_message)
38
+ end
39
+ end
40
+
41
+ def error
42
+ if !error_key.nil?
43
+ "#{error_key}: #{error_message}"
44
+ end
45
+ end
46
+
47
+
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  class UberS3
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.4'
3
3
  end
data/lib/uber-s3.rb CHANGED
@@ -29,7 +29,8 @@ class UberS3
29
29
  end
30
30
 
31
31
  require 'uber-s3/version'
32
- require 'uber-s3/exceptions'
32
+ require 'uber-s3/error'
33
+ require 'uber-s3/response'
33
34
  require 'uber-s3/connection'
34
35
  require 'uber-s3/authorization'
35
36
  require 'uber-s3/operation'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uber-s3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-17 00:00:00.000000000Z
12
+ date: 2011-10-21 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mime-types
16
- requirement: &70300780746280 !ruby/object:Gem::Requirement
16
+ requirement: &70197560327260 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '1.16'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70300780746280
24
+ version_requirements: *70197560327260
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70300780745880 !ruby/object:Gem::Requirement
27
+ requirement: &70197560326480 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70300780745880
35
+ version_requirements: *70197560326480
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70300780745320 !ruby/object:Gem::Requirement
38
+ requirement: &70197560325160 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,8 +43,8 @@ dependencies:
43
43
  version: 2.7.0
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70300780745320
47
- description: A simple & very fast S3 client supporting sync and async communication
46
+ version_requirements: *70197560325160
47
+ description: A simple & very fast S3 client supporting sync / async HTTP adapters
48
48
  email:
49
49
  - peter@nulayer.com
50
50
  executables: []
@@ -58,7 +58,7 @@ files:
58
58
  - lib/uber-s3/connection/em_http_fibered.rb
59
59
  - lib/uber-s3/connection/net_http.rb
60
60
  - lib/uber-s3/connection.rb
61
- - lib/uber-s3/exceptions.rb
61
+ - lib/uber-s3/error.rb
62
62
  - lib/uber-s3/object.rb
63
63
  - lib/uber-s3/operation/object/access_policy.rb
64
64
  - lib/uber-s3/operation/object/cache_control.rb
@@ -70,6 +70,7 @@ files:
70
70
  - lib/uber-s3/operation/object/meta.rb
71
71
  - lib/uber-s3/operation/object/storage_class.rb
72
72
  - lib/uber-s3/operation.rb
73
+ - lib/uber-s3/response.rb
73
74
  - lib/uber-s3/util/xml_document.rb
74
75
  - lib/uber-s3/version.rb
75
76
  - lib/uber-s3.rb
@@ -96,6 +97,6 @@ rubyforge_project:
96
97
  rubygems_version: 1.8.11
97
98
  signing_key:
98
99
  specification_version: 3
99
- summary: A simple & very fast S3 client supporting sync and async communication
100
+ summary: A simple & very fast S3 client supporting sync / async HTTP adapters
100
101
  test_files: []
101
102
  has_rdoc:
@@ -1,7 +0,0 @@
1
- class UberS3
2
-
3
- class UberS3Error < StandardError; end
4
-
5
-
6
-
7
- end