/
mirroring.rb
142 lines (116 loc) · 3.97 KB
/
mirroring.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# frozen_string_literal: true
class Shrine
module Plugins
# Documentation can be found on https://shrinerb.com/docs/plugins/mirroring
module Mirroring
def self.configure(uploader, **opts)
uploader.opts[:mirroring] ||= { upload: true, delete: true }
uploader.opts[:mirroring].merge!(opts)
fail Error, ":mirror option is required for mirroring plugin" unless uploader.opts[:mirroring][:mirror]
end
module ClassMethods
def mirrors(storage_key = nil)
if storage_key
mirrors = opts[:mirroring][:mirror][storage_key]
fail Error, "no mirrors registered for storage #{storage_key.inspect}" unless mirrors
Array(mirrors)
else
opts[:mirroring][:mirror]
end
end
def mirror_upload_block(&block)
if block
opts[:mirroring][:upload_block] = block
else
opts[:mirroring][:upload_block]
end
end
def mirror_delete_block(&block)
if block
opts[:mirroring][:delete_block] = block
else
opts[:mirroring][:delete_block]
end
end
def mirror_upload?
opts[:mirroring][:upload]
end
def mirror_delete?
opts[:mirroring][:delete]
end
end
module InstanceMethods
# Mirrors upload to other mirror storages.
def upload(io, mirror: true, **options)
file = super(io, **options)
file.trigger_mirror_upload(**options) if mirror
file
end
end
module FileMethods
# Mirrors upload if mirrors are defined. Calls mirror block if
# registered, otherwise mirrors synchronously.
def trigger_mirror_upload(**options)
return unless shrine_class.mirrors[storage_key] && shrine_class.mirror_upload?
if shrine_class.mirror_upload_block
mirror_upload_background(**options)
else
mirror_upload(**options)
end
end
# Calls mirror upload block.
def mirror_upload_background(**options)
fail Error, "mirror upload block is not registered" unless shrine_class.mirror_upload_block
shrine_class.mirror_upload_block.call(self, **options)
end
# Uploads the file to each mirror storage.
def mirror_upload(**options)
previously_opened = opened?
each_mirror do |mirror|
rewind if opened?
shrine_class.upload(self, mirror, **options, location: id, close: false, action: :mirror)
end
ensure
if opened? && !previously_opened
close
@io = nil
end
end
# Mirrors delete to other mirror storages.
def delete(mirror: true)
result = super()
trigger_mirror_delete if mirror
result
end
# Mirrors delete if mirrors are defined. Calls mirror block if
# registered, otherwise mirrors synchronously.
def trigger_mirror_delete
return unless shrine_class.mirrors[storage_key] && shrine_class.mirror_delete?
if shrine_class.mirror_delete_block
mirror_delete_background
else
mirror_delete
end
end
# Calls mirror delete block.
def mirror_delete_background
fail Error, "mirror delete block is not registered" unless shrine_class.mirror_delete_block
shrine_class.mirror_delete_block.call(self)
end
# Deletes the file from each mirror storage.
def mirror_delete
each_mirror do |mirror|
self.class.new(id: id, storage: mirror).delete
end
end
private
# Iterates over mirror storages.
def each_mirror(&block)
mirrors = shrine_class.mirrors(storage_key)
mirrors.map(&block)
end
end
end
register_plugin(:mirroring, Mirroring)
end
end