Class: Raca::Container
- Inherits:
-
Object
- Object
- Raca::Container
- Defined in:
- lib/raca/container.rb
Overview
Represents a single cloud files container. Contains methods for uploading, downloading, collecting stats, listing files, etc.
You probably don’t want to instantiate this directly, see Raca::Account#containers
Constant Summary collapse
- MAX_ITEMS_PER_LIST =
10_000
- LARGE_FILE_THRESHOLD =
5 Gb
5_368_709_120
- LARGE_FILE_SEGMENT_SIZE =
100 Mb
104_857_600
Instance Attribute Summary collapse
-
#container_name ⇒ Object
readonly
Returns the value of attribute container_name.
Instance Method Summary collapse
-
#cdn_enable(ttl = 259200) ⇒ Object
use this with caution, it will make EVERY object in the container publicly available via the CDN.
-
#cdn_metadata ⇒ Object
Return the key details for CDN access to this container.
-
#delete(key) ⇒ Object
Delete
key
from the container. -
#download(key, filepath) ⇒ Object
Download the object at key into a local file at filepath.
-
#expiring_url(object_key, temp_url_key, expires_at = Time.now.to_i + 60) ⇒ Object
Generate a expiring URL for a file that is otherwise private.
-
#initialize(account, region, container_name, opts = {}) ⇒ Container
constructor
A new instance of Container.
-
#list(options = {}) ⇒ Object
Return an array of files in the container.
-
#metadata ⇒ Object
Return some basic stats on the current container.
-
#object_metadata(key) ⇒ Object
Returns some metadata about a single object in this container.
-
#purge_from_akamai(key, email_address) ⇒ Object
Remove
key
from the CDN edge nodes on which it is currently cached. -
#search(prefix) ⇒ Object
Returns an array of object keys that start with prefix.
-
#upload(key, data_or_path, headers = {}) ⇒ Object
Upload data_or_path (which may be a filename or an IO) to the container, as key.
Constructor Details
#initialize(account, region, container_name, opts = {}) ⇒ Container
Returns a new instance of Container.
20 21 22 23 24 25 26 27 |
# File 'lib/raca/container.rb', line 20 def initialize(account, region, container_name, opts = {}) raise ArgumentError, "The container name must not contain '/'." if container_name['/'] @account, @region, @container_name = account, region, container_name @storage_url = @account.public_endpoint("cloudFiles", region) @cdn_url = @account.public_endpoint("cloudFilesCDN", region) @logger = opts[:logger] @logger ||= Rails.logger if defined?(Rails) end |
Instance Attribute Details
#container_name ⇒ Object (readonly)
Returns the value of attribute container_name.
18 19 20 |
# File 'lib/raca/container.rb', line 18 def container_name @container_name end |
Instance Method Details
#cdn_enable(ttl = 259200) ⇒ Object
use this with caution, it will make EVERY object in the container publicly available via the CDN. CDN enabling can be done via the web UI but only with a TTL of 72 hours. Using the API it’s possible to set a TTL of 50 years.
TTL is defined in seconds, default is 72 hours.
182 183 184 185 186 187 |
# File 'lib/raca/container.rb', line 182 def cdn_enable(ttl = 259200) log "enabling CDN access to #{container_path} with a cache expiry of #{ttl / 60} minutes" response = cdn_client.put(container_path, "X-TTL" => ttl.to_i.to_s) (200..299).cover?(response.code.to_i) end |
#cdn_metadata ⇒ Object
Return the key details for CDN access to this container. Can be called on non CDN enabled containers, but the details won’t make much sense.
163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/raca/container.rb', line 163 def log "retrieving container CDN metadata from #{container_path}" response = cdn_client.head(container_path) { :cdn_enabled => response["X-CDN-Enabled"] == "True", :host => response["X-CDN-URI"], :ssl_host => response["X-CDN-SSL-URI"], :streaming_host => response["X-CDN-STREAMING-URI"], :ttl => response["X-TTL"].to_i, :log_retention => response["X-Log-Retention"] == "True" } end |
#delete(key) ⇒ Object
Delete key
from the container. If the container is on the CDN, the object will still be served from the CDN until the TTL expires.
50 51 52 53 54 55 |
# File 'lib/raca/container.rb', line 50 def delete(key) log "deleting #{key} from #{container_path}" object_path = File.join(container_path, Raca::Util.url_encode(key)) response = storage_client.delete(object_path) (200..299).cover?(response.code.to_i) end |
#download(key, filepath) ⇒ Object
Download the object at key into a local file at filepath.
Returns the number of downloaded bytes.
90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/raca/container.rb', line 90 def download(key, filepath) log "downloading #{key} from #{container_path}" object_path = File.join(container_path, Raca::Util.url_encode(key)) response = storage_client.get(object_path) do |response| File.open(filepath, 'wb') do |io| response.read_body do |chunk| io.write(chunk) end end end response["Content-Length"].to_i end |
#expiring_url(object_key, temp_url_key, expires_at = Time.now.to_i + 60) ⇒ Object
Generate a expiring URL for a file that is otherwise private. useful for providing temporary access to files.
192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/raca/container.rb', line 192 def expiring_url(object_key, temp_url_key, expires_at = Time.now.to_i + 60) digest = OpenSSL::Digest::Digest.new('sha1') method = 'GET' expires = expires_at.to_i path = File.join(container_path, object_key) encoded_path = File.join(container_path, Raca::Util.url_encode(object_key)) data = "#{method}\n#{expires}\n#{path}" hmac = OpenSSL::HMAC.new(temp_url_key, digest) hmac << data "https://#{storage_host}#{encoded_path}?temp_url_sig=#{hmac.hexdigest}&temp_url_expires=#{expires}" end |
#list(options = {}) ⇒ Object
Return an array of files in the container.
Supported options
max - the maximum number of items to return marker - return items alphabetically after this key. Useful for pagination prefix - only return items that start with this string details - return extra details for each file - size, md5, etc
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 |
# File 'lib/raca/container.rb', line 112 def list( = {}) max = .fetch(:max, 100_000_000) marker = .fetch(:marker, nil) prefix = .fetch(:prefix, nil) details = .fetch(:details, nil) limit = [max, MAX_ITEMS_PER_LIST].min log "retrieving up to #{max} items from #{container_path}" request_path = list_request_path(marker, prefix, details, limit) result = storage_client.get(request_path).body || "" if details result = JSON.parse(result) else result = result.split("\n") end result.tap {|items| if max <= limit log "Got #{items.length} items; we don't need any more." elsif items.length < limit log "Got #{items.length} items; there can't be any more." else log "Got #{items.length} items; requesting #{limit} more." details ? marker = items.last["name"] : marker = items.last items.concat list(max: max-items.length, marker: marker, prefix: prefix, details: details) end } end |
#metadata ⇒ Object
Return some basic stats on the current container.
151 152 153 154 155 156 157 158 |
# File 'lib/raca/container.rb', line 151 def log "retrieving container metadata from #{container_path}" response = storage_client.head(container_path) { :objects => response["X-Container-Object-Count"].to_i, :bytes => response["X-Container-Bytes-Used"].to_i } end |
#object_metadata(key) ⇒ Object
Returns some metadata about a single object in this container.
75 76 77 78 79 80 81 82 83 84 |
# File 'lib/raca/container.rb', line 75 def (key) object_path = File.join(container_path, Raca::Util.url_encode(key)) log "Requesting metadata from #{object_path}" response = storage_client.head(object_path) { :content_type => response["Content-Type"], :bytes => response["Content-Length"].to_i } end |
#purge_from_akamai(key, email_address) ⇒ Object
Remove key
from the CDN edge nodes on which it is currently cached. The object is not deleted from the container: as the URL is re-requested, the edge cache will be re-filled with the object currently in the container.
This shouldn’t be used except when it’s really required (e.g. when a piece has to be taken down) because it’s expensive: it lodges a support ticket at Akamai. (!)
64 65 66 67 68 69 70 71 |
# File 'lib/raca/container.rb', line 64 def purge_from_akamai(key, email_address) log "Requesting #{File.join(container_path, key)} to be purged from the CDN" response = cdn_client.delete( File.join(container_path, Raca::Util.url_encode(key)), 'X-Purge-Email' => email_address ) (200..299).cover?(response.code.to_i) end |
#search(prefix) ⇒ Object
Returns an array of object keys that start with prefix. This is a convenience method that is equivilant to:
container.list(prefix: "foo/bar/")
144 145 146 147 |
# File 'lib/raca/container.rb', line 144 def search(prefix) log "retrieving container listing from #{container_path} items starting with #{prefix}" list(prefix: prefix) end |
#upload(key, data_or_path, headers = {}) ⇒ Object
Upload data_or_path (which may be a filename or an IO) to the container, as key.
If headers are provided they will be added to to upload request. Use this to manually specify content type, content disposition, CORS headers, etc.
34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/raca/container.rb', line 34 def upload(key, data_or_path, headers = {}) case data_or_path when StringIO, File upload_io(key, data_or_path, data_or_path.size, headers) when String File.open(data_or_path, "rb") do |io| upload_io(key, io, io.stat.size, headers) end else raise ArgumentError, "data_or_path must be an IO with data or filename string" end end |