uber-s3 0.1.2 → 0.1.3

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