Class: Tori::Backend::S3

Inherits:
Object
  • Object
show all
Defined in:
lib/tori/backend/s3.rb

Constant Summary collapse

DEFAULT_CONTENT_TYPE =
'text/plain'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bucket:, client: nil) ⇒ S3

Must be set bucket name.

And it use aws-sdk-core >= 2.0
ENV takes precedence over credentials file and instance profile

example:

Tori.config.backend = Tori::Backend::S3.new(bucket: 'tori_bucket')
# or
Tori.config.backend = Tori::Backend::S3.new(
  bucket: 'tori_bucket',
  client: Aws::S3::Client.new(
    access_key_id: 'your_access_key',
    secret_access_key: 'your_secret_access_key',
    region: 'your-region-1'
  )
)


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/tori/backend/s3.rb', line 32

def initialize(bucket:, client: nil)
  @bucket = bucket
  if client
    unless client.kind_of?(Aws::S3::Client)
      raise TypeError, "client should be instance of Aws::S3::Client or nil"
    end
    @client = client
  else
    region = ENV['TORI_AWS_REGION'] || ENV['AWS_REGION'] || Aws.config[:region]
    @client = if ENV['TORI_AWS_ACCESS_KEY_ID'] && ENV['TORI_AWS_SECRET_ACCESS_KEY']
                Aws::S3::Client.new(
                  access_key_id:     ENV['TORI_AWS_ACCESS_KEY_ID'],
                  secret_access_key: ENV['TORI_AWS_SECRET_ACCESS_KEY'],
                  region:            region,
                )
              else
                # Use instance profile or credentials file (~/.aws/credentials)
                Aws::S3::Client.new(region: region)
              end
  end
end

Instance Attribute Details

#bucketObject

Returns the value of attribute bucket.



8
9
10
# File 'lib/tori/backend/s3.rb', line 8

def bucket
  @bucket
end

#clientObject (readonly)

Returns the value of attribute client.



9
10
11
# File 'lib/tori/backend/s3.rb', line 9

def client
  @client
end

Class Method Details

.type_for(path) ⇒ Object



12
13
14
# File 'lib/tori/backend/s3.rb', line 12

def type_for(path)
  (MIME::Types.type_for(path).first || DEFAULT_CONTENT_TYPE).to_s
end

Instance Method Details

#body(filename, **opts) ⇒ Object



108
109
110
# File 'lib/tori/backend/s3.rb', line 108

def body(filename, **opts)
  get(filename, **opts)[:body]
end

#copy_object(opts = {}) ⇒ Object



186
187
188
# File 'lib/tori/backend/s3.rb', line 186

def copy_object(opts = {})
  client.copy_object bucket: @bucket, **opts
end

#copy_to(filename, tori_file, **opts) ⇒ Object



128
129
130
131
132
133
134
135
# File 'lib/tori/backend/s3.rb', line 128

def copy_to(filename, tori_file, **opts)
  copy_object(
    copy_source: "#{bucket}/#{filename}",
    bucket:      bucket,
    key:         tori_file.name,
    **opts,
  )
end

#delete(filename) ⇒ Object



91
92
93
# File 'lib/tori/backend/s3.rb', line 91

def delete(filename)
  delete_object key: filename
end

#delete_object(opts = {}) ⇒ Object



182
183
184
# File 'lib/tori/backend/s3.rb', line 182

def delete_object(opts={})
  client.delete_object bucket: @bucket, **opts
end

#exist?(filename = nil) ⇒ Boolean Also known as: exists?

Returns:

  • (Boolean)


95
96
97
98
99
100
101
# File 'lib/tori/backend/s3.rb', line 95

def exist?(filename = nil)
  head filename
rescue Aws::S3::Errors::NoSuchKey, Aws::S3::Errors::NotFound
  false
else
  true
end

#get(filename, **opts) ⇒ Object



112
113
114
# File 'lib/tori/backend/s3.rb', line 112

def get(filename, **opts)
  get_object(key: filename, **opts)
end

#get_object(opts = {}) ⇒ Object



166
167
168
# File 'lib/tori/backend/s3.rb', line 166

def get_object(opts={})
  client.get_object bucket: @bucket, **opts
end

#head(filename = nil, **opts) ⇒ Object



120
121
122
123
124
125
126
# File 'lib/tori/backend/s3.rb', line 120

def head(filename = nil, **opts)
  if filename
    head_object key: filename, **opts
  else
    head_bucket
  end
end

#head_bucket(opts = {}) ⇒ Object



174
175
176
# File 'lib/tori/backend/s3.rb', line 174

def head_bucket(opts={})
  client.head_bucket bucket: @bucket, **opts
end

#head_object(opts = {}) ⇒ Object



170
171
172
# File 'lib/tori/backend/s3.rb', line 170

def head_object(opts={})
  client.head_object bucket: @bucket, **opts
end

#open(filename, opts = {}) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/tori/backend/s3.rb', line 146

def open(filename, opts = {})
  names = [::File.basename(filename), ::File.extname(filename)]
  tmpdir = opts.delete(:tmpdir)

  if block_given?
    Tempfile.create(names, tmpdir, **opts) do |f|
      get_object(key: filename, response_target: f.path)
      yield f
    end
  else
    f = Tempfile.open(names, tmpdir, **opts)
    get_object(key: filename, response_target: f.path)
    f
  end
end

#otherwise(backend) ⇒ Object



162
163
164
# File 'lib/tori/backend/s3.rb', line 162

def otherwise(backend)
  Chain.new(self, backend)
end

#public_url(filename) ⇒ Object



137
138
139
# File 'lib/tori/backend/s3.rb', line 137

def public_url(filename)
  "#{client.config.endpoint}/#{@bucket}/#{filename}"
end

#put(filename, body, **opts) ⇒ Object



116
117
118
# File 'lib/tori/backend/s3.rb', line 116

def put(filename, body, **opts)
  put_object key: filename, body: body, **opts
end

#put_object(opts = {}) ⇒ Object



178
179
180
# File 'lib/tori/backend/s3.rb', line 178

def put_object(opts = {})
  client.put_object bucket: @bucket, **opts
end

#read(filename, **opts) ⇒ Object



104
105
106
# File 'lib/tori/backend/s3.rb', line 104

def read(filename, **opts)
  body(filename, **opts).read
end

#url_for(filename, method) ⇒ Object



141
142
143
144
# File 'lib/tori/backend/s3.rb', line 141

def url_for(filename, method)
  signer = Aws::S3::Presigner.new(client: client)
  signer.presigned_url(method, bucket: @bucket, key: filename)
end

#write(filename, resource, opts = nil) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/tori/backend/s3.rb', line 54

def write(filename, resource, opts = nil)
  opts ||= {}
  if from_path = opts.delete(:from_path)
    opts[:content_type] = self.class.type_for(from_path)
  end

  if resource.nil? && opts[:body]
    resource = opts[:body]
  end

  case resource
  when String
    put_object({
      key: filename,
      body: resource,
      content_type: DEFAULT_CONTENT_TYPE,
    }.merge(opts))
  when File, Pathname
    path = resource.to_path
    content_type = self.class.type_for(path)
    ::File.open(path) { |f|
      put_object({
        key: filename,
        body: f,
        content_type: content_type.to_s,
        content_length: f.size,
      }.merge(opts))
    }
  else
    put_object({
      key: filename,
      body: resource,
      content_type: DEFAULT_CONTENT_TYPE,
    }.merge(opts))
  end
end