aboutsummaryrefslogtreecommitdiffstats
path: root/lib/active_storage/service/s3_service.rb
blob: ad55db0dc0cbb97ecf0d421eb2f918c30b16ec28 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
require "aws-sdk"
require "active_support/core_ext/numeric/bytes"

class ActiveStorage::Service::S3Service < ActiveStorage::Service
  attr_reader :client, :bucket

  def initialize(bucket:, client: nil, **client_options)
    @bucket = bucket
    @client = client || Aws::S3::Client.new(client_options)
  end

  def upload(key, io, checksum: nil)
    instrument :upload, key, checksum: checksum do
      begin
        client.put_object bucket: bucket, key: key, body: io, content_md5: checksum
      rescue Aws::S3::Errors::BadDigest
        raise ActiveStorage::IntegrityError
      end
    end
  end

  def download(key, &block)
    if block_given?
      instrument :streaming_download, key do
        client.get_object bucket: bucket, key: key, &block
      end
    else
      instrument :download, key do
        "".b.tap do |data|
          client.get_object bucket: bucket, key: key, response_target: data
        end
      end
    end
  end

  def delete(key)
    instrument :delete, key do
      client.delete_object bucket: bucket, key: key
    end
  end

  def exist?(key)
    instrument :exist, key do |payload|
      payload[:exist] =
        begin
          client.head_object bucket: bucket, key: key
        rescue Aws::S3::Errors::NoSuckKey
          false
        else
          true
        end
    end
  end

  def url(key, expires_in:, disposition:, filename:)
    instrument :url, key do |payload|
      payload[:url] = presigner.presigned_url :get_object,
        bucket: bucket, key: key, expires_in: expires_in,
        response_content_disposition: "#{disposition}; filename=\"#{filename}\""
    end
  end

  def url_for_direct_upload(key, expires_in:, content_type:, content_length:)
    instrument :url, key do |payload|
      payload[:url] = presigner.presigned_url :put_object,
        bucket: bucket, key: key, expires_in: expires_in,
        content_type: content_type, content_length: content_length
    end
  end

  private
    def presigner
      @presigner ||= Aws::S3::Presigner.new client: client
    end
end