diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2017-07-24 08:48:42 -0500 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2017-07-24 08:48:42 -0500 |
commit | 69922fc7154fb0b99031b3215f42bb0124715608 (patch) | |
tree | dfa246ca0ef21c2abfe16b485db6881339dc4d15 /lib/active_storage/service/disk_service.rb | |
parent | b2032888194ded868d22993c720ea1b03c4f754b (diff) | |
download | rails-69922fc7154fb0b99031b3215f42bb0124715608.tar.gz rails-69922fc7154fb0b99031b3215f42bb0124715608.tar.bz2 rails-69922fc7154fb0b99031b3215f42bb0124715608.zip |
Everything under app/ is eager loaded, don't want that for service
Since it references all the specific cloud services that are intended only to be loaded on demand.
Diffstat (limited to 'lib/active_storage/service/disk_service.rb')
-rw-r--r-- | lib/active_storage/service/disk_service.rb | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/lib/active_storage/service/disk_service.rb b/lib/active_storage/service/disk_service.rb new file mode 100644 index 0000000000..3cde203a31 --- /dev/null +++ b/lib/active_storage/service/disk_service.rb @@ -0,0 +1,91 @@ +require "fileutils" +require "pathname" +require "digest/md5" +require "active_support/core_ext/numeric/bytes" + +class ActiveStorage::Service::DiskService < ActiveStorage::Service + attr_reader :root + + def initialize(root:) + @root = root + end + + def upload(key, io, checksum: nil) + instrument :upload, key, checksum: checksum do + IO.copy_stream(io, make_path_for(key)) + ensure_integrity_of(key, checksum) if checksum + end + end + + def download(key) + if block_given? + instrument :streaming_download, key do + File.open(path_for(key), "rb") do |file| + while data = file.read(64.kilobytes) + yield data + end + end + end + else + instrument :download, key do + File.binread path_for(key) + end + end + end + + def delete(key) + instrument :delete, key do + begin + File.delete path_for(key) + rescue Errno::ENOENT + # Ignore files already deleted + end + end + end + + def exist?(key) + instrument :exist, key do |payload| + answer = File.exist? path_for(key) + payload[:exist] = answer + answer + end + end + + def url(key, expires_in:, disposition:, filename:, content_type:) + instrument :url, key do |payload| + verified_key_with_expiration = ActiveStorage.verifier.generate(key, expires_in: expires_in, purpose: :blob_key) + + generated_url = + if defined?(Rails) && defined?(Rails.application) + Rails.application.routes.url_helpers.rails_disk_blob_path \ + verified_key_with_expiration, + disposition: disposition, filename: filename, content_type: content_type + else + "/rails/active_storage/disk/#{verified_key_with_expiration}/#{filename}?disposition=#{disposition}&content_type=#{content_type}" + end + + payload[:url] = generated_url + + generated_url + end + end + + private + def path_for(key) + File.join root, folder_for(key), key + end + + def folder_for(key) + [ key[0..1], key[2..3] ].join("/") + end + + def make_path_for(key) + path_for(key).tap { |path| FileUtils.mkdir_p File.dirname(path) } + end + + def ensure_integrity_of(key, checksum) + unless Digest::MD5.file(path_for(key)).base64digest == checksum + raise ActiveStorage::IntegrityError + end + end +end |