Permalink
Browse files

Initial commit of Dragonfly-MogileFS

  • Loading branch information...
0 parents commit 57a66b22d4fc56082dd07a1001d75afd0d83fb06 Jamie Winsor committed Jun 25, 2011
5 .gitignore
@@ -0,0 +1,5 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
+.rspec
4 Gemfile
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in dragonfly-mogilefs.gemspec
+gemspec
6 README.md
@@ -0,0 +1,6 @@
+Dragonfly-MogileFS
+==================
+
+Dragonfly-MogileFS is a plugin for Dragonfly that provides a MogileFS data store to use when you need replicated and highly available data. Shove images and videos in MogileFS, he loves it.
+
+See the [dragonfly documentation](http://markevans.github.com/dragonfly) for more info.
12 Rakefile
@@ -0,0 +1,12 @@
+require 'bundler'
+Bundler::GemHelper.install_tasks
+
+require 'rake'
+
+require 'rspec/core'
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new(:spec) do |spec|
+ spec.pattern = FileList['spec/**/*_spec.rb']
+end
+
+task :default => :spec
25 dragonfly-mogilefs.gemspec
@@ -0,0 +1,25 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "dragonfly-mogilefs/version"
+
+Gem::Specification.new do |s|
+ s.name = "dragonfly-mogilefs"
+ s.version = EnMasse::Dragonfly::MogileFS::VERSION
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["Jamie Winsor"]
+ s.email = ["jamie@enmasse.com"]
+ s.homepage = ""
+ s.summary = %q{MogileFS Data Store for Dragonfly}
+ s.description = %q{MogileFS Data Store for Dragonfly}
+
+ s.rubyforge_project = "dragonfly-mogilefs"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+
+ s.add_dependency 'dragonfly', '>= 0.9'
+ s.add_dependency 'mogilefs-client', '~> 2.2.0'
+ s.add_development_dependency 'rspec', '>= 2.6.0'
+end
10 lib/dragonfly-mogilefs.rb
@@ -0,0 +1,10 @@
+module EnMasse
+ module Dragonfly
+ module MogileFS
+ end
+ end
+end
+
+require 'dragonfly'
+require 'mogilefs'
+require 'dragonfly-mogilefs/data_store'
84 lib/dragonfly-mogilefs/data_store.rb
@@ -0,0 +1,84 @@
+module EnMasse
+ module Dragonfly
+ module MogileFS
+ class DataStore
+
+ include ::Dragonfly::Configurable
+
+ configurable_attr :hosts
+ configurable_attr :domain, 'dragonfly'
+ configurable_attr :klass, nil
+ configurable_attr :timeout
+ configurable_attr :readonly
+ configurable_attr :db_backend
+
+ def initialize(options = {})
+ self.hosts = options[:hosts]
+ self.domain = options[:domain]
+ self.klass = options[:klass] if options[:klass]
+ self.timeout = options[:timeout] if options[:timeout]
+ self.readonly = options[:readonly] if options[:readonly]
+ self.db_backend = options[:db_backend] if options[:db_backend]
+ end
+
+ def store(temp_object, options = {})
+ meta = options[:meta] || {}
+ uid = options[:key] || generate_uid(meta[:name] || temp_object.original_filename || 'file')
+
+ temp_object.file do |fp|
+ connection.store_file(uid, self.klass, fp)
+ end
+ store_meta_data(uid, meta)
+
+ uid
+ end
+
+ def retrieve(uid)
+ [
+ connection.get_file_data(uid),
+ retrieve_meta_data(uid)
+ ]
+ rescue ::MogileFS::Backend::UnknownKeyError => e
+ raise ::Dragonfly::DataStorage::DataNotFound, "#{e} - #{uid}"
+ end
+
+ def destroy(uid)
+ connection.delete(uid)
+ rescue ::MogileFS::Backend::UnknownKeyError => e
+ raise ::Dragonfly::DataStorage::DataNotFound, "#{e} - #{uid}"
+ end
+
+ def connection
+ options = {
+ :hosts => self.hosts,
+ :domain => self.domain
+ }
+ options[:timeout] = self.timeout if self.timeout
+ options[:readonly] = self.readonly if self.readonly
+ options[:db_backend] = self.db_backend if self.db_backend
+ @connection ||= ::MogileFS::MogileFS.new(options)
+ end
+
+ private
+
+ def generate_uid(name)
+ "#{Time.now.strftime '%Y/%m/%d/%H/%M/%S'}/#{rand(1000)}/#{name.gsub(/[^\w.]+/, '_')}"
+ end
+
+ def meta_data_key(data_key)
+ "#{data_key}.meta"
+ end
+
+ def store_meta_data(data_key, meta)
+ connection.store_content(meta_data_key(data_key), self.klass, Marshal.dump(meta))
+ end
+
+ def retrieve_meta_data(data_key)
+ data = connection.get_file_data(meta_data_key(data_key))
+ data ? Marshal.load(data) : {}
+ end
+
+ end
+ end
+ end
+end
7 lib/dragonfly-mogilefs/version.rb
@@ -0,0 +1,7 @@
+module EnMasse
+ module Dragonfly
+ module MogileFS
+ VERSION = "0.0.1"
+ end
+ end
+end
85 spec/dragonfly-mogilefs/data_store_spec.rb
@@ -0,0 +1,85 @@
+require 'spec_helper'
+
+describe EnMasse::Dragonfly::MogileFS::DataStore do
+
+ before(:each) do
+ options = {
+ :domain => 'dragonfly-test',
+ :hosts => ['127.0.0.1:7001']
+ }
+ begin
+ mog = MogileFS::MogileFS.new(options)
+ mog.list_keys('/')
+ rescue MogileFS::UnreachableBackendError
+ pending "You need to start a MogileFS tracker on 127.0.0.1:7001 to test the MogileFS DataStore"
+ rescue MogileFS::Backend::UnregDomainError
+ pending "You need to create a MogileFS domain called 'dragonfly-test' to test the MogileFS DataStore"
+ end
+ @data_store = EnMasse::Dragonfly::MogileFS::DataStore.new(options)
+ @temp_object = Dragonfly::TempObject.new('gollum')
+ end
+
+ describe "store" do
+ it "should return a unique identifier for each storage" do
+ temp_object2 = Dragonfly::TempObject.new('gollum')
+ @data_store.store(@temp_object).should_not == @data_store.store(temp_object2)
+ end
+ it "should return a unique identifier for each storage even when the first is deleted" do
+ uid1 = @data_store.store(@temp_object)
+ @data_store.destroy(uid1)
+ uid2 = @data_store.store(@temp_object)
+ uid1.should_not == uid2
+ end
+ it "should allow for passing in options as a second argument" do
+ @data_store.store(@temp_object, :some => :option)
+ end
+ end
+
+ describe "retrieve" do
+ describe "without meta" do
+ before(:each) do
+ uid = @data_store.store(@temp_object)
+ @obj, @meta = @data_store.retrieve(uid)
+ end
+
+ it "should retrieve the stored data" do
+ Dragonfly::TempObject.new(@obj).data.should == @temp_object.data
+ end
+
+ it "should return a meta hash (probably empty)" do
+ @meta.should be_a(Hash)
+ end
+
+ end
+
+ describe "when meta is given" do
+ before(:each) do
+ temp_object = Dragonfly::TempObject.new('gollum')
+ @uid = @data_store.store(temp_object, :meta => {:bitrate => '35', :name => 'danny.boy'})
+ @obj, @meta = @data_store.retrieve(@uid)
+ end
+
+ it "should return the stored meta" do
+ @meta[:bitrate].should == '35'
+ @meta[:name].should == 'danny.boy'
+ end
+ end
+
+ it "should raise an exception if the data doesn't exist" do
+ lambda{
+ @data_store.retrieve('gooble/gubbub')
+ }.should raise_error(Dragonfly::DataStorage::DataNotFound)
+ end
+ end
+
+ describe "destroy" do
+ it "should destroy the stored data" do
+ uid = @data_store.store(@temp_object)
+ @data_store.destroy(uid)
+ lambda{
+ @data_store.retrieve(uid)
+ }.should raise_error(Dragonfly::DataStorage::DataNotFound)
+ end
+ end
+
+end
12 spec/spec_helper.rb
@@ -0,0 +1,12 @@
+require 'rubygems'
+require 'bundler'
+Bundler.setup(:default, :test)
+
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require 'rspec'
+require 'dragonfly-mogilefs'
+
+def test_app
+ Dragonfly::App.send(:new)
+end

0 comments on commit 57a66b2

Please sign in to comment.