Class: CloudFiles::StorageObject
- Inherits:
-
Object
- Object
- CloudFiles::StorageObject
- Defined in:
- lib/cloudfiles/storage_object.rb
Instance Attribute Summary collapse
-
#container ⇒ Object
readonly
The parent CloudFiles::Container object.
-
#name ⇒ Object
readonly
Name of the object corresponding to the instantiated object.
Instance Method Summary collapse
-
#bytes ⇒ Object
Size of the object (in bytes).
-
#content_type ⇒ Object
Content type of the object data.
- #content_type=(type) ⇒ Object
-
#copy(options = {}) ⇒ Object
Copy this object to a new location (optionally in a new container).
-
#data(size = -1,, offset = 0, headers = {}) ⇒ Object
(also: #read)
Retrieves the data from an object and stores the data in memory.
-
#data_stream(size = -1,, offset = 0, headers = {}, &block) ⇒ Object
Retrieves the data from an object and returns a stream that must be passed to a block.
- #escape_name(name) ⇒ Object
- #escaped_name ⇒ Object
-
#etag ⇒ Object
ETag of the object data.
-
#initialize(container, objectname, force_exists = false, make_path = false) ⇒ StorageObject
constructor
Builds a new CloudFiles::StorageObject in the current container.
-
#last_modified ⇒ Object
Date of the object’s last modification.
-
#load_from_filename(filename, headers = {}, check_md5 = false) ⇒ Object
A convenience method to stream data into an object from a local file (or anything that can be loaded by Ruby’s open method).
-
#manifest ⇒ Object
Returns the object’s manifest.
-
#metadata ⇒ Object
Returns the object’s metadata as a nicely formatted hash, stripping off the X-Meta-Object- prefix that the system prepends to the key name.
-
#move(options = {}) ⇒ Object
Takes the same options as the copy method, only it does a copy followed by a delete on the original object.
-
#object_metadata ⇒ Object
Retrieves Metadata for the object.
-
#public_ssl_url ⇒ Object
If the parent container is public (CDN-enabled), returns the SSL CDN URL to this object.
-
#public_streaming_url ⇒ Object
If the parent container is public (CDN-enabled), returns the SSL CDN URL to this object.
-
#public_url ⇒ Object
If the parent container is public (CDN-enabled), returns the CDN URL to this object.
-
#purge_from_cdn(email = nil) ⇒ Object
Purges CDN Edge Cache for all objects inside of this container.
-
#refresh ⇒ Object
(also: #populate)
Refreshes the object metadata.
-
#save_to_filename(filename) ⇒ Object
A convenience method to stream data from an object into a local file.
-
#set_manifest(manifest) ⇒ Object
Sets the manifest for an object.
-
#set_metadata(metadatahash) ⇒ Object
(also: #metadata=)
Sets the metadata for an object.
-
#to_s ⇒ Object
:nodoc:.
-
#write(data = nil, headers = {}) ⇒ Object
Takes supplied data and writes it to the object, saving it.
Constructor Details
#initialize(container, objectname, force_exists = false, make_path = false) ⇒ StorageObject
Builds a new CloudFiles::StorageObject in the current container. If force_exist is set, the object must exist or a CloudFiles::Exception::NoSuchObject Exception will be raised. If not, an “empty” CloudFiles::StorageObject will be returned, ready for data via CloudFiles::StorageObject.write
15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/cloudfiles/storage_object.rb', line 15 def initialize(container, objectname, force_exists = false, make_path = false) @container = container @containername = container.name @name = objectname @make_path = make_path @storagepath = "#{CloudFiles.escape @containername}/#{escaped_name}" if force_exists raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless container.object_exists?(objectname) end end |
Instance Attribute Details
#container ⇒ Object (readonly)
The parent CloudFiles::Container object
10 11 12 |
# File 'lib/cloudfiles/storage_object.rb', line 10 def container @container end |
#name ⇒ Object (readonly)
Name of the object corresponding to the instantiated object
7 8 9 |
# File 'lib/cloudfiles/storage_object.rb', line 7 def name @name end |
Instance Method Details
#bytes ⇒ Object
Size of the object (in bytes)
65 66 67 |
# File 'lib/cloudfiles/storage_object.rb', line 65 def bytes self.[:bytes] end |
#content_type ⇒ Object
Content type of the object data
80 81 82 |
# File 'lib/cloudfiles/storage_object.rb', line 80 def content_type self.[:content_type] end |
#content_type=(type) ⇒ Object
84 85 86 |
# File 'lib/cloudfiles/storage_object.rb', line 84 def content_type=(type) self.copy(:headers => {'Content-Type' => type}) end |
#copy(options = {}) ⇒ Object
Copy this object to a new location (optionally in a new container)
You must supply either a name for the new object or a container name, or both. If a :name is supplied without a :container, the object is copied within the current container. If the :container is specified with no :name, then the object is copied to the new container with its current name.
object.copy(:name => "images/funny/lolcat.jpg", :container => "pictures")
You may also supply a hash of headers in the :headers option. From there, you can set things like Content-Type, or other headers as available in the API document.
object.copy(:name => 'newfile.tmp', :headers => {'Content-Type' => 'text/plain'})
Returns the new CloudFiles::StorageObject for the copied item.
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/cloudfiles/storage_object.rb', line 368 def copy( = {}) raise CloudFiles::Exception::Syntax, "You must provide the :container, :name, or :headers for this operation" unless ([:container] || [:name] || [:headers]) new_container = [:container] || self.container.name new_name = [:name] || self.name new_headers = [:headers] || {} raise CloudFiles::Exception::Syntax, "The :headers option must be a hash" unless new_headers.is_a?(Hash) new_name.sub!(/^\//,'') headers = {'X-Copy-From' => "#{self.container.name}/#{self.name}", 'Content-Type' => self.content_type.sub(/;.+/, '')}.merge(new_headers) # , 'Content-Type' => self.content_type new_path = "#{CloudFiles.escape new_container}/#{escape_name new_name}" begin response = SwiftClient.put_object(self.container.connection.storageurl, self.container.connection.authtoken, (CloudFiles.escape new_container), escape_name(new_name), nil, nil, nil, nil, nil, headers) return CloudFiles::Container.new(self.container.connection, new_container).object(new_name) rescue ClientException => e code = e.status.to_s raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code =~ /^20/) end end |
#data(size = -1,, offset = 0, headers = {}) ⇒ Object Also known as: read
Retrieves the data from an object and stores the data in memory. The data is returned as a string. Throws a NoSuchObjectException if the object doesn’t exist.
If the optional size and range arguments are provided, the call will return the number of bytes provided by size, starting from the offset provided in offset.
object.data
=> "This is the text stored in the file"
96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/cloudfiles/storage_object.rb', line 96 def data(size = -1, offset = 0, headers = {}) if size.to_i > 0 range = sprintf("bytes=%d-%d", offset.to_i, (offset.to_i + size.to_i) - 1) headers['Range'] = range end begin response = SwiftClient.get_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name) response[1] rescue ClientException => e raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless (e.status.to_s =~ /^20/) end end |
#data_stream(size = -1,, offset = 0, headers = {}, &block) ⇒ Object
Retrieves the data from an object and returns a stream that must be passed to a block. Throws a NoSuchObjectException if the object doesn’t exist.
If the optional size and range arguments are provided, the call will return the number of bytes provided by size, starting from the offset provided in offset.
data = ""
object.data_stream do |chunk|
data += chunk
end
data
=> "This is the text stored in the file"
123 124 125 126 127 128 129 130 131 |
# File 'lib/cloudfiles/storage_object.rb', line 123 def data_stream(size = -1, offset = 0, headers = {}, &block) if size.to_i > 0 range = sprintf("bytes=%d-%d", offset.to_i, (offset.to_i + size.to_i) - 1) headers['Range'] = range end begin SwiftClient.get_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, nil, nil, &block) end end |
#escape_name(name) ⇒ Object
402 403 404 |
# File 'lib/cloudfiles/storage_object.rb', line 402 def escape_name(name) CloudFiles.escape name end |
#escaped_name ⇒ Object
60 61 62 |
# File 'lib/cloudfiles/storage_object.rb', line 60 def escaped_name @escaped_name ||= escape_name @name end |
#etag ⇒ Object
ETag of the object data
75 76 77 |
# File 'lib/cloudfiles/storage_object.rb', line 75 def etag self.[:etag] end |
#last_modified ⇒ Object
Date of the object’s last modification
70 71 72 |
# File 'lib/cloudfiles/storage_object.rb', line 70 def last_modified self.[:last_modified] end |
#load_from_filename(filename, headers = {}, check_md5 = false) ⇒ Object
A convenience method to stream data into an object from a local file (or anything that can be loaded by Ruby’s open method)
You can provide an optional hash of headers, in case you want to do something like set the Content-Type manually.
Throws an Errno::ENOENT if the file cannot be read.
object.data
=> "This is my data"
object.load_from_filename("/tmp/file.txt")
=> true
object.load_from_filename("/home/rackspace/myfile.tmp", 'Content-Type' => 'text/plain')
object.data
=> "This data was in the file /tmp/file.txt"
object.load_from_filename("/tmp/nonexistent.txt")
=> Errno::ENOENT: No such file or directory - /tmp/nonexistent.txt
284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/cloudfiles/storage_object.rb', line 284 def load_from_filename(filename, headers = {}, check_md5 = false) f = open(filename) if check_md5 require 'digest/md5' md5_hash = Digest::MD5.file(filename) headers["Etag"] = md5_hash.to_s() end self.write(f, headers) f.close true end |
#manifest ⇒ Object
Returns the object’s manifest.
object.manifest
=> "container/prefix"
168 169 170 |
# File 'lib/cloudfiles/storage_object.rb', line 168 def manifest self.[:manifest] end |
#metadata ⇒ Object
Returns the object’s metadata as a nicely formatted hash, stripping off the X-Meta-Object- prefix that the system prepends to the key name.
object.metadata
=> {"ruby"=>"cool", "foo"=>"bar"}
138 139 140 141 142 |
# File 'lib/cloudfiles/storage_object.rb', line 138 def = {} self.[:metadata].each{ |key, value| [key.gsub(/x-object-meta-/, '').gsub(/\+\-/, ' ')] = URI.decode(value).gsub(/\+\-/, ' ') } end |
#move(options = {}) ⇒ Object
Takes the same options as the copy method, only it does a copy followed by a delete on the original object.
Returns the new CloudFiles::StorageObject for the moved item. You should not attempt to use the old object after doing a move.
391 392 393 394 395 396 |
# File 'lib/cloudfiles/storage_object.rb', line 391 def move( = {}) new_object = self.copy() self.container.delete_object(self.name) self.freeze return new_object end |
#object_metadata ⇒ Object
Retrieves Metadata for the object
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/cloudfiles/storage_object.rb', line 35 def @object_metadata ||= ( begin response = SwiftClient.head_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name) rescue ClientException => e raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless (e.status.to_s =~ /^20/) end resphash = {} = response.to_hash.select { |k,v| k.match(/^x-object-meta/) } .each do |x,y| resphash[x] = (y.respond_to?(:join) ? y.join('') : y.to_s) end { :manifest => response["x-object-manifest"], :bytes => response["content-length"], :last_modified => Time.parse(response["last-modified"]), :etag => response["etag"], :content_type => response["content-type"], :metadata => resphash } ) end |
#public_ssl_url ⇒ Object
If the parent container is public (CDN-enabled), returns the SSL CDN URL to this object. Otherwise, return nil
public_object.public_ssl_url
=> "https://c61.ssl.cf0.rackcdn.com/myfile.jpg"
private_object.public_ssl_url
=> nil
339 340 341 |
# File 'lib/cloudfiles/storage_object.rb', line 339 def public_ssl_url self.container.public? ? self.container.cdn_ssl_url + "/#{escaped_name}" : nil end |
#public_streaming_url ⇒ Object
If the parent container is public (CDN-enabled), returns the SSL CDN URL to this object. Otherwise, return nil
public_object.public_streaming_url
=> "https://c61.stream.rackcdn.com/myfile.jpg"
private_object.public_streaming_url
=> nil
350 351 352 |
# File 'lib/cloudfiles/storage_object.rb', line 350 def public_streaming_url self.container.public? ? self.container.cdn_streaming_url + "/#{escaped_name}" : nil end |
#public_url ⇒ Object
If the parent container is public (CDN-enabled), returns the CDN URL to this object. Otherwise, return nil
public_object.public_url
=> "http://c0001234.cdn.cloudfiles.rackspacecloud.com/myfile.jpg"
private_object.public_url
=> nil
328 329 330 |
# File 'lib/cloudfiles/storage_object.rb', line 328 def public_url self.container.public? ? self.container.cdn_url + "/#{escaped_name}" : nil end |
#purge_from_cdn(email = nil) ⇒ Object
Purges CDN Edge Cache for all objects inside of this container
:email, An valid email address or comma seperated list of emails to be notified once purge is complete .
obj.purge_from_cdn
=> true
or
obj.purge_from_cdn("[email protected]")
=> true
or
obj.purge_from_cdn("[email protected], [email protected]")
=> true
252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/cloudfiles/storage_object.rb', line 252 def purge_from_cdn(email=nil) raise Exception::CDNNotAvailable unless cdn_available? headers = {} headers = {"X-Purge-Email" => email} if email begin SwiftClient.delete_object(self.container.connection.cdnurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, nil, headers) true rescue ClientException => e raise CloudFiles::Exception::Connection, "Error Unable to Purge Object: #{@name}" unless (e.status.to_s =~ /^20.$/) false end end |
#refresh ⇒ Object Also known as: populate
Refreshes the object metadata
28 29 30 31 |
# File 'lib/cloudfiles/storage_object.rb', line 28 def refresh @object_metadata = nil true end |
#save_to_filename(filename) ⇒ Object
A convenience method to stream data from an object into a local file
Throws an Errno::ENOENT if the file cannot be opened for writing due to a path error, and Errno::EACCES if the file cannot be opened for writing due to permissions.
object.data
=> "This is my data"
object.save_to_filename("/tmp/file.txt")
=> true
$ cat /tmp/file.txt
"This is my data"
object.save_to_filename("/tmp/owned_by_root.txt")
=> Errno::EACCES: Permission denied - /tmp/owned_by_root.txt
312 313 314 315 316 317 318 319 |
# File 'lib/cloudfiles/storage_object.rb', line 312 def save_to_filename(filename) File.open(filename, 'wb+') do |f| self.data_stream do |chunk| f.write chunk end end true end |
#set_manifest(manifest) ⇒ Object
Sets the manifest for an object. By passing a string as an argument, you can set the manifest for an object. However, setting manifest will overwrite any existing manifest for the object.
Throws NoSuchObjectException if the object doesn’t exist. Throws InvalidResponseException if the request fails.
178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/cloudfiles/storage_object.rb', line 178 def set_manifest(manifest) headers = {'X-Object-Manifest' => manifest} begin SwiftClient.post_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, headers) true rescue ClientException => e raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" if (e.status.to_s == "404") raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status.to_s}" unless (e.status.to_s =~ /^20/) false end end |
#set_metadata(metadatahash) ⇒ Object Also known as: metadata=
Sets the metadata for an object. By passing a hash as an argument, you can set the metadata for an object. However, setting metadata will overwrite any existing metadata for the object.
Throws NoSuchObjectException if the object doesn’t exist. Throws InvalidResponseException if the request fails.
149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/cloudfiles/storage_object.rb', line 149 def () headers = {} .each{ |key, value| headers['X-Object-Meta-' + key.to_s.capitalize] = value.to_s } begin SwiftClient.post_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, headers) true rescue ClientException => e raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" if (e.status.to_s == "404") raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status.to_s}" unless (e.status.to_s =~ /^20/) false end end |
#to_s ⇒ Object
:nodoc:
398 399 400 |
# File 'lib/cloudfiles/storage_object.rb', line 398 def to_s # :nodoc: @name end |
#write(data = nil, headers = {}) ⇒ Object
Takes supplied data and writes it to the object, saving it. You can supply an optional hash of headers, including Content-Type and ETag, that will be applied to the object.
If you would rather stream the data in chunks, instead of reading it all into memory at once, you can pass an IO object for the data, such as: object.write(open(‘/path/to/file.mp3’))
You can compute your own MD5 sum and send it in the “ETag” header. If you provide yours, it will be compared to the MD5 sum on the server side. If they do not match, the server will return a 422 status code and a CloudFiles::Exception::MisMatchedChecksum Exception will be raised. If you do not provide an MD5 sum as the ETag, one will be computed on the server side.
Updates the container cache and returns true on success, raises exceptions if stuff breaks.
object = container.create_object("newfile.txt")
object.write("This is new data")
=> true
object.data
=> "This is new data"
If you are passing your data in via STDIN, just do an
object.write
with no data (or, if you need to pass headers)
object.write(nil,{'header' => 'value})
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/cloudfiles/storage_object.rb', line 219 def write(data = nil, headers = {}) raise CloudFiles::Exception::Syntax, "No data or header updates supplied" if ((data.nil? && $stdin.tty?) and headers.empty?) # If we're taking data from standard input, send that IO object to cfreq data = $stdin if (data.nil? && $stdin.tty? == false) begin response = SwiftClient.put_object(self.container.connection.storageurl, self.container.connection.authtoken, self.container.escaped_name, escaped_name, data, nil, nil, nil, nil, headers) rescue ClientException => e code = e.status.to_s raise CloudFiles::Exception::InvalidResponse, "Invalid content-length header sent" if (code == "412") raise CloudFiles::Exception::MisMatchedChecksum, "Mismatched etag" if (code == "422") raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{code}" unless (code =~ /^20./) end make_path(File.dirname(self.name)) if @make_path == true self.refresh true end |