uber-s3 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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