[ninefold|storage] File operations.

This commit is contained in:
Lincoln Stoll 2011-07-10 23:44:35 +10:00
parent 083f7b9038
commit ef44cd0b38
9 changed files with 212 additions and 33 deletions

View File

@ -13,20 +13,25 @@ module Fog
def all
directory ? ns = directory.key : ns = ''
ns = ns + '/' unless ns =~ /\/$/
data = connection.get_namespace(ns).body[:DirectoryList]
data = {:DirectoryEntry => []} if data.kind_of? String
data[:DirectoryEntry] = [data[:DirectoryEntry]] if data[:DirectoryEntry].kind_of? Hash
dirs = data[:DirectoryEntry].select {|de| de[:FileType] == 'directory'}
dirs.each {|d| d[:Filename] = ns + '/' + d[:Filename] if directory}
load(data[:DirectoryEntry].select {|de| de[:FileType] == 'directory'})
dirs.each do |d|
d[:Filename] = ns + d[:Filename] if directory
d[:Filename] += '/' unless d[:Filename] =~ /\/$/
end
load(dirs)
end
def get(key, options = {})
return nil if key == '' # Root dir shouldn't be retrieved like this.
res = connection.get_namespace key
key =~ /\/$/ ? ns = key : ns = key + '/'
res = connection.get_namespace ns
emc_meta = res.headers['x-emc-meta']
obj_id = emc_meta.scan(/objectid=(\w+),/).flatten[0]
new(:objectid => obj_id, :key => key)
new(:objectid => obj_id, :key => ns)
rescue Fog::Storage::Ninefold::NotFound
nil
end

View File

@ -28,14 +28,19 @@ module Fog
end
def save
self.key = attributes[:directory].key + '/' + key if attributes[:directory]
self.key = attributes[:directory].key + key if attributes[:directory]
self.key = key + '/' unless key =~ /\/$/
res = connection.post_namespace key
reload
end
def destroy(opts={})
if opts[:recursive]
directories.each { |d| d.destroy(opts) }
files.each {|f| f.destroy }
directories.each do |d|
d.files.each {|f| f.destroy }
d.destroy(opts)
end
end
connection.delete_namespace key
end

View File

@ -0,0 +1,91 @@
require 'fog/core/model'
module Fog
module Storage
class Ninefold
class File < Fog::Model
identity :key, :aliases => :Filename
attribute :content_length, :aliases => ['bytes', 'Content-Length'], :type => :integer
attribute :content_type, :aliases => ['content_type', 'Content-Type']
attribute :objectid, :aliases => :ObjectID
def body
attributes[:body] ||= if last_modified
collection.get(identity).body
else
''
end
end
def body=(new_body)
attributes[:body] = new_body
end
def directory
@directory
end
def destroy
requires :directory, :key
connection.delete_namespace(directory.key + key)
true
end
# def owner=(new_owner)
# if new_owner
# attributes[:owner] = {
# :display_name => new_owner['DisplayName'],
# :id => new_owner['ID']
# }
# end
# end
def public=(new_public)
# NOOP - we don't need to flag files as public, getting the public URL for a file handles it.
end
# By default, expire in 5 years
def public_url(expires = (Time.now + 5 * 365 * 24 * 60 * 60))
requires :objectid
# TODO - more efficient method to get this?
storage = Fog::Storage.new(:provider => 'Ninefold')
uri = URI::HTTP.build(:scheme => Fog::Storage::Ninefold::STORAGE_SCHEME, :host => Fog::Storage::Ninefold::STORAGE_HOST, :port => Fog::Storage::Ninefold::STORAGE_PORT.to_i, :path => "/rest/objects/#{objectid}" )
Fog::Storage.new(:provider => 'Ninefold').uid
sb = "GET\n"
sb += uri.path.downcase + "\n"
sb += storage.uid + "\n"
sb += String(expires.to_i())
signature = storage.sign( sb )
uri.query = "uid=#{CGI::escape(storage.uid)}&expires=#{expires.to_i()}&signature=#{CGI::escape(signature)}"
uri.to_s
end
def save(options = {})
requires :body, :directory, :key
directory.kind_of?(Directory) ? ns = directory.key : ns = directory
ns += key
options['Content-Type'] = content_type if content_type
data = connection.post_namespace(ns, :body => body)
#p data
self.objectid = data.headers['location'].split('/')[-1]
merge_attributes(data.headers)
true
end
private
def directory=(new_directory)
@directory = new_directory
end
end
end
end
end

View File

@ -0,0 +1,72 @@
require 'fog/core/collection'
require 'fog/storage/models/ninefold/file'
module Fog
module Storage
class Ninefold
class Files < Fog::Collection
attribute :directory
attribute :limit
attribute :marker
attribute :path
attribute :prefix
model Fog::Storage::Ninefold::File
def all(options = {})
requires :directory
directory ? ns = directory.key : ns = ''
ns = ns + '/' unless ns =~ /\/$/
data = connection.get_namespace(ns).body[:DirectoryList]
data = {:DirectoryEntry => []} if data.kind_of? String
data[:DirectoryEntry] = [data[:DirectoryEntry]] if data[:DirectoryEntry].kind_of? Hash
files = data[:DirectoryEntry].select {|de| de[:FileType] == 'regular'}
files.each do |s|
s[:directory] = directory
end
# TODO - Load additional file meta?
load(files)
end
def get(key, &block)
requires :directory
data = connection.get_namespace(directory.key + key, :parse => false)#, &block)
file_data = data.headers.merge({
:body => data.body,
:key => key
})
new(file_data)
rescue Fog::Storage::Ninefold::NotFound
nil
end
def get_url(key)
requires :directory
if self.directory.public_url
"#{self.directory.public_url}/#{key}"
end
end
def head(key, options = {})
requires :directory
data = connection.head_object(directory.key, key)
file_data = data.headers.merge({
:key => key
})
new(file_data)
rescue Fog::Storage::Rackspace::NotFound
nil
end
def new(attributes = {})
requires :directory
super({ :directory => directory }.merge!(attributes))
end
end
end
end
end

View File

@ -14,8 +14,8 @@ module Fog
model_path 'fog/storage/models/ninefold'
model :directory
collection :directories
# model :file
# collection :files
model :file
collection :files
request_path 'fog/storage/requests/ninefold'
# request :delete_container
@ -54,6 +54,15 @@ module Fog
@connection = Fog::Connection.new("#{Fog::Storage::Ninefold::STORAGE_SCHEME}://#{Fog::Storage::Ninefold::STORAGE_HOST}:#{Fog::Storage::Ninefold::STORAGE_PORT}", true) # persistent
end
def uid
@ninefold_storage_token#.split('/')[-1]
end
def sign(string)
value = ::HMAC::SHA1.digest( @ninefold_storage_secret_decoded, string )
Base64.encode64( value ).chomp()
end
def reload
@connection.reset
end
@ -89,7 +98,7 @@ module Fog
signstring += "/rest/" + URI.unescape( req_path ).downcase
query_str = params[:query].map{|k,v| "#{k}=#{v}"}.join('&')
signstring += '?' + params[:query] unless query_str.empty?
signstring += '?' + query_str unless query_str.empty?
signstring += "\n"
customheaders = {}

View File

@ -4,14 +4,13 @@ module Fog
class Real
def delete_namespace(namespace = '', options = {})
namespace = namespace + '/' unless namespace =~ /\/$/
options = options.reject {|key, value| value.nil?}
request(
:expects => 204,
:method => 'DELETE',
:path => "namespace/" + namespace,
:query => options
)
request({
:expects => 204,
:method => 'DELETE',
:path => "namespace/" + namespace,
:query => options
}.merge(options))
end
end

View File

@ -4,15 +4,14 @@ module Fog
class Real
def get_namespace(namespace = '', options = {})
namespace = namespace + '/' unless namespace =~ /\/$/
options = options.reject {|key, value| value.nil?}
request(
:expects => 200,
:method => 'GET',
:path => "namespace/" + namespace,
:query => options,
:parse => true
)
request({
:expects => 200,
:method => 'GET',
:path => "namespace/" + namespace,
:query => {},
:parse => true
}.merge(options))
end
end

View File

@ -4,15 +4,14 @@ module Fog
class Real
def post_namespace(namespace = '', options = {})
namespace = namespace + '/' unless namespace =~ /\/$/
options = options.reject {|key, value| value.nil?}
request(
:expects => 201,
:method => 'POST',
:path => "namespace/" + namespace,
:query => options,
:parse => true
)
request({
:expects => 201,
:method => 'POST',
:path => "namespace/" + namespace,
:query => {},
:parse => true
}.merge(options))
end
end

View File

@ -11,7 +11,7 @@ if storage_providers.keys.include? :ninefold
ninefold.directories.get('sub').directories.count
end
tests("create a directory in a sub dir").returns('sub/path/newdir') do
tests("create a directory in a sub dir").returns('sub/path/newdir/') do
ninefold.directories.get('sub/path').directories.create(:key => 'newdir').identity
end