Skip to content

Instantly share code, notes, and snippets.

@spencerldixon
Created September 25, 2020 11:40
Show Gist options
  • Save spencerldixon/0ac2b3ce10b5c843904de02120acb77c to your computer and use it in GitHub Desktop.
Save spencerldixon/0ac2b3ce10b5c843904de02120acb77c to your computer and use it in GitHub Desktop.
Azure Downloads and Zip Streaming
# Service object azure_api.rb for interfacing with azure blob storage. Handles getting a list of files as well as
# getting files by top_level_directory/prefix and multiple prefixes. Also caches requests to ensure a fast response.
require 'azure/storage/blob'
CACHE_LENGTH = 3.hours
PREFIX_DELIMITER = ','
class AzureApi
def self.get_files_for(directory, prefix=nil)
return self.list_blobs(directory) if prefix.nil?
prefixes = prefix.split(PREFIX_DELIMITER)
prefixes.flat_map do |prefix|
self.list_blobs(File.join(directory, prefix, '/'))
end
end
def self.list_blobs(prefix)
Rails.cache.fetch("get_files_for_#{AZURE_CONTAINER}_#{prefix}", expires_in: CACHE_LENGTH) do
AZURE_CLIENT.list_blobs(AZURE_CONTAINER, prefix: prefix)
end
end
def self.download(path)
Rails.cache.fetch("download_#{AZURE_CONTAINER}_#{path}", expires_in: CACHE_LENGTH) do
AZURE_CLIENT.get_blob(AZURE_CONTAINER, path)
end
end
end
########################## STREAMING ACTION FOR CONTROLLER ##################
def download_all_as_zip
# Generates a zip of all files given a Azure directory and a prefix
blobs = AzureApi.get_files_for(DIRECTORY, PREFIX)
send_file_headers!(
type: "application/zip",
disposition: "attachment",
filename: "download_#{Time.now.to_i}.zip"
)
response.headers["Last-Modified"] = Time.now.httpdate.to_s
response.headers["X-Accel-Buffering"] = "no"
writer = ZipTricks::BlockWrite.new do |chunk|
response.stream.write(chunk)
end
ZipTricks::Streamer.open(writer) do |zip|
blobs.each do |blob|
# Download each individual blob, takes the full path of the blob
_blob, content = AzureApi.download(blob.name)
zip.write_deflated_file(blob.name) do |file_writer|
# Add blob content to file writer to stream back to browser
file_writer << content
end
end
end
ensure
response.stream.close
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment