uber-s3 0.1.2 → 0.1.3

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.
@@ -4,18 +4,31 @@ module UberS3::Connection
4
4
  class NetHttp < Adapter
5
5
 
6
6
  def request(verb, url, headers={}, body=nil)
7
+ if verb == :get
8
+ # Support fetching compressed data
9
+ headers['Accept-Encoding'] = 'gzip, deflate'
10
+ end
11
+
7
12
  uri = URI.parse(url)
8
13
  http = Net::HTTP.new(uri.host, uri.port)
9
14
 
10
15
  req_klass = instance_eval("Net::HTTP::"+verb.to_s.capitalize)
11
16
  req = req_klass.new(uri.to_s, headers)
12
-
17
+
13
18
  r = http.request(req, body)
14
19
 
20
+ # Auto-decode any gzipped objects
21
+ if verb == :get && r.header['content-encoding'] == 'gzip'
22
+ gz = Zlib::GzipReader.new(StringIO.new(r.body))
23
+ response_body = gz.read
24
+ else
25
+ response_body = r.body
26
+ end
27
+
15
28
  {
16
29
  :status => r.code.to_i,
17
30
  :header => r.header.to_hash,
18
- :body => r.body,
31
+ :body => response_body,
19
32
  :raw => r
20
33
  }
21
34
  end
@@ -39,10 +39,6 @@ class UberS3
39
39
  # headers['Connection'] = (persistent ? 'keep-alive' : 'close')
40
40
 
41
41
  if body
42
- mime_type = MIME::Types.type_for(path).first
43
-
44
- headers['Content-Type'] ||= mime_type.content_type if mime_type
45
- headers['Content-Type'] ||= 'binary/octet-stream'
46
42
  headers['Content-Length'] ||= body.bytesize.to_s
47
43
  end
48
44
 
@@ -1,24 +1,28 @@
1
1
  class UberS3
2
2
  class Object
3
+ include Operation::Object::All
3
4
 
4
- attr_accessor :bucket, :key, :value, :errors
5
- # attr_accessor :etag, :last_modified
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
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
16
16
 
17
17
  def initialize(bucket, key, value=nil, options={})
18
- self.bucket = bucket
19
- self.key = key
20
- self.value = value
18
+ self.bucket = bucket
19
+ self.key = key
20
+ self.value = value
21
+
22
+ # Init state of object
23
+ infer_content_type!
21
24
 
25
+ # Call operation methods based on options passed
22
26
  bucket.connection.defaults.merge(options).each {|k,v| self.send((k.to_s+'=').to_sym, v) }
23
27
  end
24
28
 
@@ -38,6 +42,9 @@ class UberS3
38
42
  def save
39
43
  headers = {}
40
44
 
45
+ # Encode data if necessary
46
+ gzip_content!
47
+
41
48
  # Standard pass through values
42
49
  headers['Cache-Control'] = cache_control
43
50
  headers['Content-Disposition'] = content_disposition
@@ -69,6 +76,7 @@ class UberS3
69
76
  response = bucket.connection.put(key, headers, value)
70
77
 
71
78
  if response[:status] != 200
79
+ # TODO: .. we should raise stuff here!!!!!!!! exception handling....................
72
80
  self.errors = response[:body]
73
81
  else
74
82
  self.errors = nil
@@ -98,32 +106,13 @@ class UberS3
98
106
  @key = key.gsub(/^\//,'')
99
107
  end
100
108
 
101
- ##########################
102
-
103
109
  def value=(value)
104
110
  self.size = value.to_s.bytesize
105
111
  @value = value
106
112
  end
107
113
 
108
- def access=(access)
109
- valid_values = [:private, :public_read, :public_read_write, :authenticated_read]
110
-
111
- if valid_values.include?(access)
112
- @access = access
113
- else
114
- raise "Invalid access value"
115
- end
116
- end
117
-
118
- def storage_class=(storage_class)
119
- valid_values = [:standard, :reduced_redundancy]
120
-
121
- if valid_values.include?(storage_class)
122
- @storage_class = storage_class
123
- else
124
- raise "Invalid storage_class value"
125
- end
126
- end
114
+ # TODO..
115
+ # Add callback support so Operations can hook into that ... cleaner. ie. on_save { ... }
127
116
 
128
117
  end
129
118
  end
@@ -14,6 +14,15 @@ module UberS3::Operation::Object
14
14
  end
15
15
 
16
16
  module InstanceMethods
17
+ def access=(access)
18
+ valid_values = [:private, :public_read, :public_read_write, :authenticated_read]
19
+
20
+ if valid_values.include?(access)
21
+ @access = access
22
+ else
23
+ raise "Invalid access value"
24
+ end
25
+ end
17
26
  end
18
27
 
19
28
  end
@@ -6,6 +6,7 @@ module UberS3::Operation::Object
6
6
  base.send :include, InstanceMethods
7
7
 
8
8
  base.instance_eval do
9
+ attr_accessor :cache_control
9
10
  end
10
11
  end
11
12
 
@@ -6,6 +6,7 @@ module UberS3::Operation::Object
6
6
  base.send :include, InstanceMethods
7
7
 
8
8
  base.instance_eval do
9
+ attr_accessor :content_disposition
9
10
  end
10
11
  end
11
12
 
@@ -6,6 +6,7 @@ module UberS3::Operation::Object
6
6
  base.send :include, InstanceMethods
7
7
 
8
8
  base.instance_eval do
9
+ attr_accessor :gzip, :content_encoding
9
10
  end
10
11
  end
11
12
 
@@ -13,6 +14,50 @@ module UberS3::Operation::Object
13
14
  end
14
15
 
15
16
  module InstanceMethods
17
+
18
+ # Default mime-types to be auto-gzipped if gzip == :web
19
+ WEB_GZIP_TYPES = ['text/html', 'text/plain', 'text/css',
20
+ 'application/javascript', 'application/x-javascript',
21
+ 'text/xml', 'application/xml', 'application/xml+rss']
22
+
23
+ private
24
+
25
+ def gzip_content!
26
+ return if gzip.nil?
27
+
28
+ if gzip == true
29
+ encode = true
30
+ elsif gzip == :web && WEB_GZIP_TYPES.include?(content_type)
31
+ encode = true
32
+ elsif gzip.is_a?(String) && gzip == content_type
33
+ encode = true
34
+ elsif gzip.is_a?(Array) && gzip.include?(content_type)
35
+ encode = true
36
+ else
37
+ encode = false
38
+ end
39
+
40
+ if encode
41
+ self.value = gzip_encoder(value)
42
+ self.content_encoding = 'gzip'
43
+ end
44
+ end
45
+
46
+ def gzip_encoder(data)
47
+ begin
48
+ gz_stream = StringIO.new
49
+ gz = Zlib::GzipWriter.new(gz_stream)
50
+ gz.write(value)
51
+ gz.close
52
+
53
+ gz_stream.string
54
+ rescue => ex
55
+ # TODO ...
56
+ $stderr.puts "Gzip failed: #{ex.message}"
57
+ raise ex
58
+ end
59
+ end
60
+
16
61
  end
17
62
 
18
63
  end
@@ -6,6 +6,7 @@ module UberS3::Operation::Object
6
6
  base.send :include, InstanceMethods
7
7
 
8
8
  base.instance_eval do
9
+ attr_accessor :content_md5
9
10
  end
10
11
  end
11
12
 
@@ -6,6 +6,7 @@ module UberS3::Operation::Object
6
6
  base.send :include, InstanceMethods
7
7
 
8
8
  base.instance_eval do
9
+ attr_accessor :content_type
9
10
  end
10
11
  end
11
12
 
@@ -13,6 +14,14 @@ module UberS3::Operation::Object
13
14
  end
14
15
 
15
16
  module InstanceMethods
17
+
18
+ def infer_content_type!
19
+ mime_type = MIME::Types.type_for(key).first
20
+
21
+ self.content_type ||= mime_type.content_type if mime_type
22
+ self.content_type ||= 'binary/octet-stream'
23
+ end
24
+
16
25
  end
17
26
 
18
27
  end
@@ -6,6 +6,7 @@ module UberS3::Operation::Object
6
6
  base.send :include, InstanceMethods
7
7
 
8
8
  base.instance_eval do
9
+ attr_accessor :expires
9
10
  end
10
11
  end
11
12
 
@@ -6,6 +6,7 @@ module UberS3::Operation::Object
6
6
  base.send :include, InstanceMethods
7
7
 
8
8
  base.instance_eval do
9
+ attr_accessor :storage_class
9
10
  end
10
11
  end
11
12
 
@@ -13,6 +14,15 @@ module UberS3::Operation::Object
13
14
  end
14
15
 
15
16
  module InstanceMethods
17
+ def storage_class=(storage_class)
18
+ valid_values = [:standard, :reduced_redundancy]
19
+
20
+ if valid_values.include?(storage_class)
21
+ @storage_class = storage_class
22
+ else
23
+ raise "Invalid storage_class value"
24
+ end
25
+ end
16
26
  end
17
27
 
18
28
  end
@@ -1,22 +1,35 @@
1
1
  class UberS3
2
2
  module Operation
3
3
 
4
- # Load and include all operations
5
- Dir[File.dirname(__FILE__)+'/operation/*'].each do |group|
6
- Dir[group+'/*.rb'].each do |op|
7
-
8
- group_klass_name = File.basename(group).split('_').map {|x| x.capitalize}.join("")
9
- op_klass_name = File.basename(op).gsub(/.rb$/i, '').split('_').map {|x| x.capitalize}.join("")
10
-
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
+
11
26
  require op
12
- op_klass = instance_eval(group_klass_name+'::'+op_klass_name)
13
- group_klass = instance_eval(group_klass_name)
14
-
15
- group_klass.send :include, op_klass
27
+ op_klass = instance_eval(group_module_name+'::'+op_klass_name)
28
+
29
+ base.send :include, op_klass
16
30
  end
17
31
  end
32
+ module_function :include_modules
18
33
 
19
34
  end
20
35
  end
21
-
22
-
@@ -1,3 +1,3 @@
1
1
  class UberS3
2
- VERSION = '0.1.2'
2
+ VERSION = '0.1.3'
3
3
  end
data/lib/uber-s3.rb CHANGED
@@ -4,6 +4,8 @@ require 'openssl'
4
4
  require 'forwardable'
5
5
  require 'base64'
6
6
  require 'digest/md5'
7
+ require 'zlib'
8
+ require 'stringio'
7
9
  require 'mime/types'
8
10
 
9
11
  class UberS3
@@ -30,6 +32,7 @@ require 'uber-s3/version'
30
32
  require 'uber-s3/exceptions'
31
33
  require 'uber-s3/connection'
32
34
  require 'uber-s3/authorization'
35
+ require 'uber-s3/operation'
33
36
  require 'uber-s3/bucket'
34
37
  require 'uber-s3/object'
35
38
 
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.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2011-10-17 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mime-types
16
- requirement: &70154944646920 !ruby/object:Gem::Requirement
16
+ requirement: &70300780746280 !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: *70154944646920
24
+ version_requirements: *70300780746280
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70154944646480 !ruby/object:Gem::Requirement
27
+ requirement: &70300780745880 !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: *70154944646480
35
+ version_requirements: *70300780745880
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70154944645900 !ruby/object:Gem::Requirement
38
+ requirement: &70300780745320 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 2.7.0
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70154944645900
46
+ version_requirements: *70300780745320
47
47
  description: A simple & very fast S3 client supporting sync and async communication
48
48
  email:
49
49
  - peter@nulayer.com