Class: Trove::Storage::S3

Inherits:
Object
  • Object
show all
Defined in:
lib/trove/storage/s3.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of S3.



9
10
11
12
# File 'lib/trove/storage/s3.rb', line 9

def initialize(bucket:, prefix: nil)
  @bucket = bucket
  @prefix = prefix
end

Instance Attribute Details

#bucketObject (readonly)

Returns the value of attribute bucket.



7
8
9
# File 'lib/trove/storage/s3.rb', line 7

def bucket
  @bucket
end

#prefixObject (readonly)

Returns the value of attribute prefix.



7
8
9
# File 'lib/trove/storage/s3.rb', line 7

def prefix
  @prefix
end

Instance Method Details

#delete(filename, version: nil) ⇒ Object



66
67
68
69
70
71
72
73
# File 'lib/trove/storage/s3.rb', line 66

def delete(filename, version: nil)
  options = {bucket: bucket, key: key(filename)}
  options[:version_id] = version if version
  client.delete_object(**options)
  true
rescue Aws::S3::Errors::NoSuchKey, Aws::S3::Errors::NotFound
  false
end

#download(filename, dest, version: nil) ⇒ Object



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
# File 'lib/trove/storage/s3.rb', line 14

def download(filename, dest, version: nil)
  current_size = 0
  total_size = nil

  # TODO better path
  tmp = "#{Dir.tmpdir}/trove-#{Time.now.to_f}"
  begin
    File.open(tmp, "wb") do |file|
      options = {bucket: bucket, key: key(filename)}
      options[:version_id] = version if version
      client.get_object(**options) do |chunk, headers|
        file.write(chunk)

        current_size += chunk.bytesize
        total_size ||= headers["content-length"].to_i
        yield current_size, total_size
      end
    end
    FileUtils.mv(tmp, dest)
  ensure
    # delete file if interrupted
    File.unlink(tmp) if File.exist?(tmp)
  end
rescue Aws::S3::Errors::NoSuchKey, Aws::S3::Errors::NotFound
  raise "File not found"
end

#info(filename, version: nil) ⇒ Object

etag isn’t always MD5, but low likelihood of match if not could alternatively add sha256 to metadata



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/trove/storage/s3.rb', line 54

def info(filename, version: nil)
  options = {bucket: bucket, key: key(filename)}
  options[:version_id] = version if version
  resp = client.head_object(**options)
  {
    version: resp.version_id,
    md5: resp.etag.gsub('"', "")
  }
rescue Aws::S3::Errors::NoSuchKey, Aws::S3::Errors::NotFound
  nil
end

#listObject



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/trove/storage/s3.rb', line 75

def list
  files = []
  options = {bucket: bucket}
  options[:prefix] = prefix if prefix
  client.list_objects_v2(**options).each do |response|
    response.contents.each do |object|
      filename = prefix ? object.key[(prefix.size + 1)..-1] : object.key
      files << {
        filename: filename,
        size: object.size,
        updated_at: object.last_modified
      }
    end
  end
  files
end

#upload(src, filename, &block) ⇒ Object



41
42
43
44
45
46
47
48
49
50
# File 'lib/trove/storage/s3.rb', line 41

def upload(src, filename, &block)
  on_chunk_sent = lambda do |_, current_size, total_size|
    block.call(current_size, total_size)
  end
  resp = nil
  File.open(src, "rb") do |file|
    resp = client.put_object(bucket: bucket, key: key(filename), body: file, on_chunk_sent: on_chunk_sent)
  end
  {version: resp.version_id}
end

#versions(filename) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/trove/storage/s3.rb', line 92

def versions(filename)
  versions = []
  object_key = key(filename)
  client.list_object_versions(bucket: bucket, prefix: object_key).each do |response|
    response.versions.each do |version|
      next if version.key != object_key

      versions << {
        version: version.version_id == "null" ? nil : version.version_id,
        size: version.size,
        updated_at: version.last_modified
      }
    end
  end
  versions
end