-
Notifications
You must be signed in to change notification settings - Fork 23
/
storage_adapter.rb
100 lines (86 loc) · 2.62 KB
/
storage_adapter.rb
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# frozen_string_literal: true
module Valkyrie
class StorageAdapter
class_attribute :storage_adapters
self.storage_adapters = {}
class << self
# Add a storage adapter to the registry under the provided short name
# @param storage_adapter [Valkyrie::StorageAdapter]
# @param short_name [Symbol]
# @return [void]
def register(storage_adapter, short_name)
storage_adapters[short_name] = storage_adapter
end
# @param short_name [Symbol]
# @return [void]
def unregister(short_name)
storage_adapters.delete(short_name)
end
# Find the adapter associated with the provided short name
# @param short_name [Symbol]
# @return [Valkyrie::StorageAdapter]
def find(short_name)
storage_adapters[short_name]
end
# Search through all registered storage adapters until it finds one that
# can handle the passed in identifier. The call find_by on that adapter
# with the given identifier.
# @param id [Valkyrie::ID]
# @return [Valkyrie::StorageAdapter::File]
def find_by(id:)
storage_adapters.values.find do |storage_adapter|
storage_adapter.handles?(id: id)
end.find_by(id: id)
end
end
class File < Dry::Struct
attribute :id, Valkyrie::Types::Any
attribute :io, Valkyrie::Types::Any
delegate :size, :read, :rewind, to: :io
def stream
io
end
def disk_path
Pathname.new(io.path)
end
# @param id [Valkyre::ID]
# @param digests [Array<Digest>]
# @return [Array<Digest>]
def checksum(digests:)
io.rewind
while (chunk = io.read(4096))
digests.each { |digest| digest.update(chunk) }
end
digests.map(&:to_s)
end
# @param id [Valkyre::ID]
# @param size [Integer]
# @param digests [Array<Digest>]
# @return [Boolean]
def valid?(size: nil, digests:)
return false if size && io.size.to_i != size.to_i
calc_digests = checksum(digests: digests.keys.map { |alg| Digest(alg.upcase).new })
return false unless digests.values == calc_digests
true
end
end
class StreamFile < File
def disk_path
Pathname.new(tmp_file.path)
end
private
def tmp_file_name
id.to_s.tr(':/', '__')
end
def tmp_file_path
::File.join(Dir.tmpdir, tmp_file_name)
end
def tmp_file
@tmp_file ||= ::File.open(tmp_file_path, 'w+b') do |f|
IO.copy_stream(io, f)
f
end
end
end
end
end