shrine 2.19.4 → 3.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of shrine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +299 -11
- data/README.md +9 -3
- data/doc/advantages.md +1 -1
- data/doc/carrierwave.md +4 -4
- data/doc/creating_persistence_plugins.md +172 -0
- data/doc/creating_plugins.md +1 -1
- data/doc/creating_storages.md +3 -1
- data/doc/design.md +2 -2
- data/doc/direct_s3.md +0 -22
- data/doc/paperclip.md +3 -3
- data/doc/plugins/activerecord.md +211 -42
- data/doc/plugins/atomic_helpers.md +153 -0
- data/doc/plugins/column.md +90 -0
- data/doc/plugins/derivation_endpoint.md +54 -62
- data/doc/plugins/derivatives.md +752 -0
- data/doc/plugins/entity.md +204 -0
- data/doc/plugins/infer_extension.md +8 -8
- data/doc/plugins/instrumentation.md +33 -13
- data/doc/plugins/keep_files.md +5 -15
- data/doc/plugins/model.md +157 -0
- data/doc/plugins/presign_endpoint.md +2 -1
- data/doc/plugins/refresh_metadata.md +44 -7
- data/doc/plugins/sequel.md +190 -33
- data/doc/plugins/{default_url_options.md → url_options.md} +5 -5
- data/doc/processing.md +1 -1
- data/doc/release_notes/1.1.0.md +2 -2
- data/doc/release_notes/2.15.0.md +1 -1
- data/doc/storage/s3.md +2 -2
- data/doc/testing.md +1 -1
- data/lib/shrine.rb +72 -138
- data/lib/shrine/attacher.rb +272 -176
- data/lib/shrine/attachment.rb +2 -42
- data/lib/shrine/plugins/activerecord.rb +103 -26
- data/lib/shrine/plugins/add_metadata.rb +9 -10
- data/lib/shrine/plugins/atomic_helpers.rb +111 -0
- data/lib/shrine/plugins/attacher_options.rb +55 -0
- data/lib/shrine/plugins/backgrounding.rb +147 -115
- data/lib/shrine/plugins/cached_attachment_data.rb +6 -9
- data/lib/shrine/plugins/column.rb +104 -0
- data/lib/shrine/plugins/data_uri.rb +35 -38
- data/lib/shrine/plugins/default_storage.rb +18 -12
- data/lib/shrine/plugins/default_url.rb +11 -21
- data/lib/shrine/plugins/default_url_options.rb +3 -30
- data/lib/shrine/plugins/delete_raw.rb +9 -13
- data/lib/shrine/plugins/derivation_endpoint.rb +75 -114
- data/lib/shrine/plugins/derivatives.rb +576 -0
- data/lib/shrine/plugins/determine_mime_type.rb +3 -15
- data/lib/shrine/plugins/download_endpoint.rb +83 -131
- data/lib/shrine/plugins/dynamic_storage.rb +4 -8
- data/lib/shrine/plugins/entity.rb +128 -0
- data/lib/shrine/plugins/form_assign.rb +107 -0
- data/lib/shrine/plugins/included.rb +4 -3
- data/lib/shrine/plugins/infer_extension.rb +10 -17
- data/lib/shrine/plugins/instrumentation.rb +45 -25
- data/lib/shrine/plugins/keep_files.rb +2 -12
- data/lib/shrine/plugins/metadata_attributes.rb +15 -14
- data/lib/shrine/plugins/model.rb +137 -0
- data/lib/shrine/plugins/module_include.rb +2 -0
- data/lib/shrine/plugins/presign_endpoint.rb +1 -15
- data/lib/shrine/plugins/pretty_location.rb +5 -5
- data/lib/shrine/plugins/processing.rb +21 -6
- data/lib/shrine/plugins/rack_file.rb +1 -39
- data/lib/shrine/plugins/rack_response.rb +14 -7
- data/lib/shrine/plugins/recache.rb +5 -2
- data/lib/shrine/plugins/refresh_metadata.rb +12 -8
- data/lib/shrine/plugins/remote_url.rb +44 -53
- data/lib/shrine/plugins/remove_attachment.rb +7 -2
- data/lib/shrine/plugins/remove_invalid.rb +8 -4
- data/lib/shrine/plugins/restore_cached_data.rb +12 -4
- data/lib/shrine/plugins/sequel.rb +115 -27
- data/lib/shrine/plugins/signature.rb +2 -7
- data/lib/shrine/plugins/store_dimensions.rb +13 -27
- data/lib/shrine/plugins/upload_endpoint.rb +14 -15
- data/lib/shrine/plugins/upload_options.rb +9 -8
- data/lib/shrine/plugins/url_options.rb +33 -0
- data/lib/shrine/plugins/validation.rb +87 -0
- data/lib/shrine/plugins/validation_helpers.rb +33 -54
- data/lib/shrine/plugins/versions.rb +106 -84
- data/lib/shrine/storage/file_system.rb +32 -57
- data/lib/shrine/storage/linter.rb +9 -1
- data/lib/shrine/storage/memory.rb +42 -0
- data/lib/shrine/storage/s3.rb +38 -146
- data/lib/shrine/uploaded_file.rb +22 -29
- data/lib/shrine/version.rb +4 -4
- data/shrine.gemspec +2 -3
- metadata +27 -54
- data/doc/plugins/backup.md +0 -31
- data/doc/plugins/copy.md +0 -24
- data/doc/plugins/delete_promoted.md +0 -12
- data/doc/plugins/direct_upload.md +0 -172
- data/doc/plugins/hooks.md +0 -58
- data/doc/plugins/logging.md +0 -42
- data/doc/plugins/migration_helpers.md +0 -60
- data/doc/plugins/moving.md +0 -19
- data/doc/plugins/multi_delete.md +0 -20
- data/doc/plugins/parallelize.md +0 -16
- data/doc/plugins/parsed_json.md +0 -23
- data/lib/shrine/plugins/background_helpers.rb +0 -5
- data/lib/shrine/plugins/backup.rb +0 -90
- data/lib/shrine/plugins/copy.rb +0 -50
- data/lib/shrine/plugins/delete_promoted.rb +0 -20
- data/lib/shrine/plugins/direct_upload.rb +0 -217
- data/lib/shrine/plugins/hooks.rb +0 -90
- data/lib/shrine/plugins/logging.rb +0 -142
- data/lib/shrine/plugins/migration_helpers.rb +0 -70
- data/lib/shrine/plugins/moving.rb +0 -57
- data/lib/shrine/plugins/multi_delete.rb +0 -32
- data/lib/shrine/plugins/parallelize.rb +0 -78
- data/lib/shrine/plugins/parsed_json.rb +0 -29
data/lib/shrine/plugins/hooks.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Shrine
|
4
|
-
module Plugins
|
5
|
-
# Documentation lives in [doc/plugins/hooks.md] on GitHub.
|
6
|
-
#
|
7
|
-
# [doc/plugins/hooks.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/hooks.md
|
8
|
-
module Hooks
|
9
|
-
module InstanceMethods
|
10
|
-
def upload(io, context = {})
|
11
|
-
result = nil
|
12
|
-
before_upload(io, context)
|
13
|
-
around_upload(io, context) { result = super }
|
14
|
-
after_upload(io, context)
|
15
|
-
result
|
16
|
-
end
|
17
|
-
|
18
|
-
def around_upload(*args)
|
19
|
-
yield
|
20
|
-
end
|
21
|
-
|
22
|
-
def before_upload(*)
|
23
|
-
end
|
24
|
-
|
25
|
-
def after_upload(*)
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
def processed(io, context)
|
30
|
-
result = nil
|
31
|
-
before_process(io, context)
|
32
|
-
around_process(io, context) { result = super }
|
33
|
-
after_process(io, context)
|
34
|
-
result
|
35
|
-
end
|
36
|
-
private :processed
|
37
|
-
|
38
|
-
def around_process(*args)
|
39
|
-
yield
|
40
|
-
end
|
41
|
-
|
42
|
-
def before_process(*)
|
43
|
-
end
|
44
|
-
|
45
|
-
def after_process(*)
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
def store(io, context = {})
|
50
|
-
result = nil
|
51
|
-
before_store(io, context)
|
52
|
-
around_store(io, context) { result = super }
|
53
|
-
after_store(io, context)
|
54
|
-
result
|
55
|
-
end
|
56
|
-
|
57
|
-
def around_store(*args)
|
58
|
-
yield
|
59
|
-
end
|
60
|
-
|
61
|
-
def before_store(*)
|
62
|
-
end
|
63
|
-
|
64
|
-
def after_store(*)
|
65
|
-
end
|
66
|
-
|
67
|
-
|
68
|
-
def delete(io, context = {})
|
69
|
-
result = nil
|
70
|
-
before_delete(io, context)
|
71
|
-
around_delete(io, context) { result = super }
|
72
|
-
after_delete(io, context)
|
73
|
-
result
|
74
|
-
end
|
75
|
-
|
76
|
-
def around_delete(*args)
|
77
|
-
yield
|
78
|
-
end
|
79
|
-
|
80
|
-
def before_delete(*)
|
81
|
-
end
|
82
|
-
|
83
|
-
def after_delete(*)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
register_plugin(:hooks, Hooks)
|
89
|
-
end
|
90
|
-
end
|
@@ -1,142 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
Shrine.deprecation("The logging plugin has been deprecated in favor of instrumentation plugin. The logging plugin will be removed in Shrine 3.")
|
4
|
-
|
5
|
-
require "logger"
|
6
|
-
require "json"
|
7
|
-
require "time"
|
8
|
-
|
9
|
-
class Shrine
|
10
|
-
module Plugins
|
11
|
-
# Documentation lives in [doc/plugins/logging.md] on GitHub.
|
12
|
-
#
|
13
|
-
# [doc/plugins/logging.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/logging.md
|
14
|
-
module Logging
|
15
|
-
def self.load_dependencies(uploader, *)
|
16
|
-
uploader.plugin :hooks
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.configure(uploader, opts = {})
|
20
|
-
uploader.opts[:logging_stream] = opts.fetch(:stream, uploader.opts.fetch(:logging_stream, $stdout))
|
21
|
-
uploader.opts[:logging_logger] = opts.fetch(:logger, uploader.opts.fetch(:logging_logger, uploader.create_logger))
|
22
|
-
uploader.opts[:logging_format] = opts.fetch(:format, uploader.opts.fetch(:logging_format, :human))
|
23
|
-
|
24
|
-
Shrine.deprecation("The :heroku logging format has been renamed to :logfmt. Using :heroku name will stop being supported in Shrine 3.") if uploader.opts[:logging_format] == :heroku
|
25
|
-
end
|
26
|
-
|
27
|
-
module ClassMethods
|
28
|
-
def logger=(logger)
|
29
|
-
@logger = logger
|
30
|
-
end
|
31
|
-
|
32
|
-
def logger
|
33
|
-
@logger ||= opts[:logging_logger]
|
34
|
-
end
|
35
|
-
|
36
|
-
def create_logger
|
37
|
-
logger = Logger.new(opts[:logging_stream])
|
38
|
-
logger.level = Logger::INFO
|
39
|
-
logger.level = Logger::WARN if ENV["RACK_ENV"] == "test"
|
40
|
-
logger.formatter = pretty_formatter
|
41
|
-
logger
|
42
|
-
end
|
43
|
-
|
44
|
-
# It makes logging preamble simpler than the default logger. Also, it
|
45
|
-
# doesn't output timestamps if on Heroku.
|
46
|
-
def pretty_formatter
|
47
|
-
proc do |severity, time, program_name, message|
|
48
|
-
output = "#{Process.pid}: #{message}\n".dup
|
49
|
-
output.prepend "#{time.utc.iso8601(3)} " unless ENV["DYNO"]
|
50
|
-
output
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
module InstanceMethods
|
56
|
-
def store(io, context = {})
|
57
|
-
log("store", io, context) { super }
|
58
|
-
end
|
59
|
-
|
60
|
-
def delete(io, context = {})
|
61
|
-
log("delete", io, context) { super }
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def processed(io, context = {})
|
67
|
-
log("process", io, context) { super }
|
68
|
-
end
|
69
|
-
|
70
|
-
# Collects the data and sends it for logging.
|
71
|
-
def log(action, input, context)
|
72
|
-
result, duration = benchmark { yield }
|
73
|
-
|
74
|
-
_log(
|
75
|
-
action: action,
|
76
|
-
phase: context[:action],
|
77
|
-
uploader: self.class.to_s,
|
78
|
-
attachment: context[:name],
|
79
|
-
record_class: (context[:record].class.to_s if context[:record]),
|
80
|
-
record_id: (context[:record].id if context[:record].respond_to?(:id)),
|
81
|
-
files: (action == "process" ? [count(input), count(result)] : count(result)),
|
82
|
-
duration: ("%.2f" % duration).to_f,
|
83
|
-
) unless result.nil?
|
84
|
-
|
85
|
-
result
|
86
|
-
end
|
87
|
-
|
88
|
-
# Determines format of logging and calls appropriate method.
|
89
|
-
def _log(data)
|
90
|
-
message = send("_log_message_#{opts[:logging_format]}", data)
|
91
|
-
self.class.logger.info(message)
|
92
|
-
end
|
93
|
-
|
94
|
-
def _log_message_human(data)
|
95
|
-
components = []
|
96
|
-
components << "#{data[:action].upcase}"
|
97
|
-
components[-1] += "[#{data[:phase]}]" if data[:phase]
|
98
|
-
components << "#{data[:uploader]}"
|
99
|
-
components[-1] += "[:#{data[:attachment]}]" if data[:attachment]
|
100
|
-
components << "#{data[:record_class]}" if data[:record_class]
|
101
|
-
components[-1] += "[#{data[:record_id]}]" if data[:record_id]
|
102
|
-
components << "#{Array(data[:files]).join("-")} #{"file#{"s" if Array(data[:files]).any?{|n| n > 1}}"}"
|
103
|
-
components << "(#{data[:duration]}s)"
|
104
|
-
components.join(" ")
|
105
|
-
end
|
106
|
-
|
107
|
-
def _log_message_json(data)
|
108
|
-
data[:files] = Array(data[:files]).join("-")
|
109
|
-
JSON.generate(data)
|
110
|
-
end
|
111
|
-
|
112
|
-
def _log_message_logfmt(data)
|
113
|
-
data[:files] = Array(data[:files]).join("-")
|
114
|
-
data.map { |key, value| "#{key}=#{value}" }.join(" ")
|
115
|
-
end
|
116
|
-
alias _log_message_heroku _log_message_logfmt # deprecated alias
|
117
|
-
|
118
|
-
# We may have one file, a hash of versions, or an array of files or
|
119
|
-
# hashes.
|
120
|
-
def count(object)
|
121
|
-
case object
|
122
|
-
when Hash
|
123
|
-
object.count
|
124
|
-
when Array
|
125
|
-
object.inject(0) { |sum, o| sum += count(o) }
|
126
|
-
else
|
127
|
-
1
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def benchmark
|
132
|
-
start = Time.now
|
133
|
-
result = yield
|
134
|
-
finish = Time.now
|
135
|
-
[result, finish - start]
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
register_plugin(:logging, Logging)
|
141
|
-
end
|
142
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
Shrine.deprecation("The migration_helpers plugin is deprecated and will be removed in Shrine 3. Attacher#cached? and Attacher#stored? have been moved to base.")
|
4
|
-
|
5
|
-
class Shrine
|
6
|
-
module Plugins
|
7
|
-
# Documentation lives in [doc/plugins/migration_helpers.md] on GitHub.
|
8
|
-
#
|
9
|
-
# [doc/plugins/migration_helpers.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/migration_helpers.md
|
10
|
-
module MigrationHelpers
|
11
|
-
def self.configure(uploader, delegate: false)
|
12
|
-
uploader.opts[:migration_helpers_delegate] = delegate
|
13
|
-
end
|
14
|
-
|
15
|
-
module AttachmentMethods
|
16
|
-
def initialize(name)
|
17
|
-
super
|
18
|
-
|
19
|
-
return if shrine_class.opts[:migration_helpers_delegate] == false
|
20
|
-
|
21
|
-
name = attachment_name
|
22
|
-
|
23
|
-
define_method :"update_#{name}" do |&block|
|
24
|
-
send(:"#{name}_attacher").update_stored(&block)
|
25
|
-
end
|
26
|
-
|
27
|
-
define_method :"#{name}_cache" do
|
28
|
-
send(:"#{name}_attacher").cache
|
29
|
-
end
|
30
|
-
|
31
|
-
define_method :"#{name}_store" do
|
32
|
-
send(:"#{name}_attacher").store
|
33
|
-
end
|
34
|
-
|
35
|
-
define_method :"#{name}_cached?" do
|
36
|
-
send(:"#{name}_attacher").cached?
|
37
|
-
end
|
38
|
-
|
39
|
-
define_method :"#{name}_stored?" do
|
40
|
-
send(:"#{name}_attacher").stored?
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
module AttacherMethods
|
46
|
-
# Updates the attachment with the result of the block. It will get
|
47
|
-
# called only if the attachment exists and is stored.
|
48
|
-
def update_stored(&block)
|
49
|
-
return if get.nil? || cache.uploaded?(get)
|
50
|
-
new_attachment = block.call(get)
|
51
|
-
swap(new_attachment)
|
52
|
-
end
|
53
|
-
|
54
|
-
# Returns true if the attachment is present and is uploaded by the
|
55
|
-
# temporary storage.
|
56
|
-
def cached?
|
57
|
-
get && cache.uploaded?(get)
|
58
|
-
end
|
59
|
-
|
60
|
-
# Returns true if the attachment is present and is uploaded by the
|
61
|
-
# permanent storage.
|
62
|
-
def stored?
|
63
|
-
get && store.uploaded?(get)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
register_plugin(:migration_helpers, MigrationHelpers)
|
69
|
-
end
|
70
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
Shrine.deprecation("The moving plugin has been deprecated in favor of the :move upload option for FileSystem storage. It will no longer be available in Shrine 3.")
|
4
|
-
|
5
|
-
class Shrine
|
6
|
-
module Plugins
|
7
|
-
# Documentation lives in [doc/plugins/moving.md] on GitHub.
|
8
|
-
#
|
9
|
-
# [doc/plugins/moving.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/moving.md
|
10
|
-
module Moving
|
11
|
-
def self.configure(uploader, opts = {})
|
12
|
-
uploader.opts[:moving_storages] = opts.fetch(:storages, uploader.opts[:moving_storages])
|
13
|
-
end
|
14
|
-
|
15
|
-
module InstanceMethods
|
16
|
-
private
|
17
|
-
|
18
|
-
# Moves the file if storage supports it, otherwise defaults to copying.
|
19
|
-
def copy(io, context)
|
20
|
-
if move?(io, context)
|
21
|
-
move(io, context)
|
22
|
-
else
|
23
|
-
super
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# Generates upload options and calls `#move` on the storage.
|
28
|
-
def move(io, context)
|
29
|
-
location = context[:location]
|
30
|
-
metadata = context[:metadata]
|
31
|
-
upload_options = context[:upload_options] || {}
|
32
|
-
|
33
|
-
storage.move(io, location, shrine_metadata: metadata, **upload_options)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Returns true if file should be moved and is movable.
|
37
|
-
def move?(io, context)
|
38
|
-
return false if context[:move] == false
|
39
|
-
moving_storage? && movable?(io, context)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Returns true if storage can move this file.
|
43
|
-
def movable?(io, context)
|
44
|
-
storage.respond_to?(:move) && storage.movable?(io, context[:location])
|
45
|
-
end
|
46
|
-
|
47
|
-
# Returns true if file should be moved.
|
48
|
-
def moving_storage?
|
49
|
-
opts[:moving_storages].nil? ||
|
50
|
-
opts[:moving_storages].include?(storage_key)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
register_plugin(:moving, Moving)
|
56
|
-
end
|
57
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
Shrine.deprecation("The multi_delete plugin is deprecated and will be removed in Shrine 3.")
|
4
|
-
|
5
|
-
class Shrine
|
6
|
-
module Plugins
|
7
|
-
# Documentation lives in [doc/plugins/multi_delete.md] on GitHub.
|
8
|
-
#
|
9
|
-
# [doc/plugins/multi_delete.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/multi_delete.md
|
10
|
-
module MultiDelete
|
11
|
-
module InstanceMethods
|
12
|
-
private
|
13
|
-
|
14
|
-
# Adds the ability to upload multiple files, leveraging the underlying
|
15
|
-
# storage's potential multi delete capability.
|
16
|
-
def _delete(uploaded_file, context)
|
17
|
-
if uploaded_file.is_a?(Array)
|
18
|
-
if storage.respond_to?(:multi_delete)
|
19
|
-
storage.multi_delete(uploaded_file.map(&:id))
|
20
|
-
else
|
21
|
-
uploaded_file.each { |file| _delete(file, context) }
|
22
|
-
end
|
23
|
-
else
|
24
|
-
super
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
register_plugin(:multi_delete, MultiDelete)
|
31
|
-
end
|
32
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "thread"
|
4
|
-
|
5
|
-
class Shrine
|
6
|
-
module Plugins
|
7
|
-
# Documentation lives in [doc/plugins/parallelize.md] on GitHub.
|
8
|
-
#
|
9
|
-
# [doc/plugins/parallelize.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/parallelize.md
|
10
|
-
module Parallelize
|
11
|
-
def self.configure(uploader, opts = {})
|
12
|
-
uploader.opts[:parallelize_threads] = opts.fetch(:threads, uploader.opts.fetch(:parallelize_threads, 3))
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.load_dependencies(uploader, opts = {})
|
16
|
-
uploader.plugin :hooks
|
17
|
-
end
|
18
|
-
|
19
|
-
module InstanceMethods
|
20
|
-
def around_store(io, context)
|
21
|
-
with_pool { |pool| super(io, context.update(thread_pool: pool)) }
|
22
|
-
end
|
23
|
-
|
24
|
-
def around_delete(uploaded_file, context)
|
25
|
-
with_pool { |pool| super(uploaded_file, context.update(thread_pool: pool)) }
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def put(io, context)
|
31
|
-
context[:thread_pool].enqueue { super }
|
32
|
-
end
|
33
|
-
|
34
|
-
def remove(uploaded_file, context)
|
35
|
-
context[:thread_pool].enqueue { super }
|
36
|
-
end
|
37
|
-
|
38
|
-
# We initialize a thread pool with configured number of threads.
|
39
|
-
def with_pool(&block)
|
40
|
-
pool = ThreadPool.new(opts[:parallelize_threads])
|
41
|
-
result = yield pool
|
42
|
-
pool.perform
|
43
|
-
result
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class ThreadPool
|
48
|
-
def initialize(size)
|
49
|
-
@size = size
|
50
|
-
@tasks = Queue.new
|
51
|
-
end
|
52
|
-
|
53
|
-
def enqueue(&task)
|
54
|
-
@tasks.enq(task)
|
55
|
-
end
|
56
|
-
|
57
|
-
def perform
|
58
|
-
@tasks.close
|
59
|
-
threads = @size.times.map { spawn_thread }
|
60
|
-
threads.each(&:join)
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def spawn_thread
|
66
|
-
Thread.new do
|
67
|
-
loop do
|
68
|
-
task = @tasks.deq or break
|
69
|
-
task.call
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
register_plugin(:parallelize, Parallelize)
|
77
|
-
end
|
78
|
-
end
|