dragonfly 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dragonfly might be problematic. Click here for more details.
- data/.gitignore +2 -0
- data/.specopts +2 -0
- data/.yardopts +11 -5
- data/Gemfile +22 -0
- data/Gemfile.rails.2.3.5 +13 -0
- data/History.md +49 -0
- data/README.md +18 -28
- data/Rakefile +24 -36
- data/VERSION +1 -1
- data/config.ru +4 -1
- data/dragonfly.gemspec +85 -99
- data/extra_docs/Analysers.md +66 -30
- data/extra_docs/Caching.md +22 -0
- data/extra_docs/Configuration.md +116 -0
- data/extra_docs/DataStorage.md +114 -14
- data/extra_docs/Encoding.md +62 -37
- data/extra_docs/GeneralUsage.md +118 -0
- data/extra_docs/Generators.md +92 -0
- data/extra_docs/Heroku.md +51 -0
- data/extra_docs/Index.md +8 -9
- data/extra_docs/MimeTypes.md +18 -17
- data/extra_docs/Models.md +251 -0
- data/extra_docs/Processing.md +94 -70
- data/extra_docs/Rack.md +53 -0
- data/extra_docs/Rails2.md +44 -0
- data/extra_docs/Rails3.md +51 -0
- data/extra_docs/Sinatra.md +21 -0
- data/extra_docs/URLs.md +114 -0
- data/features/images.feature +6 -7
- data/features/no_processing.feature +0 -6
- data/features/rails_2.3.5.feature +1 -1
- data/features/rails_3.0.0.rc.feature +8 -0
- data/features/steps/dragonfly_steps.rb +14 -12
- data/features/steps/rails_steps.rb +20 -9
- data/features/support/env.rb +10 -11
- data/fixtures/files/app/views/albums/new.html.erb +4 -4
- data/fixtures/files/app/views/albums/show.html.erb +1 -1
- data/fixtures/files/features/manage_album_images.feature +1 -1
- data/fixtures/files/features/step_definitions/{album_steps.rb → image_steps.rb} +4 -3
- data/fixtures/files/features/support/paths.rb +2 -0
- data/fixtures/files/features/text_images.feature +7 -0
- data/fixtures/rails_3.0.0.rc/template.rb +21 -0
- data/irbrc.rb +2 -1
- data/lib/dragonfly.rb +4 -16
- data/lib/dragonfly/{active_record_extensions.rb → active_model_extensions.rb} +1 -1
- data/lib/dragonfly/active_model_extensions/attachment.rb +146 -0
- data/lib/dragonfly/{active_record_extensions → active_model_extensions}/class_methods.rb +5 -6
- data/lib/dragonfly/{active_record_extensions → active_model_extensions}/instance_methods.rb +1 -1
- data/lib/dragonfly/{active_record_extensions → active_model_extensions}/validations.rb +5 -9
- data/lib/dragonfly/analyser.rb +59 -0
- data/lib/dragonfly/analysis/file_command_analyser.rb +1 -1
- data/lib/dragonfly/analysis/r_magick_analyser.rb +46 -31
- data/lib/dragonfly/app.rb +138 -173
- data/lib/dragonfly/config/heroku.rb +19 -0
- data/lib/dragonfly/config/r_magick.rb +37 -0
- data/lib/dragonfly/config/{rails_defaults.rb → rails.rb} +6 -7
- data/lib/dragonfly/configurable.rb +30 -27
- data/lib/dragonfly/core_ext/object.rb +1 -1
- data/lib/dragonfly/data_storage/file_data_store.rb +59 -26
- data/lib/dragonfly/data_storage/mongo_data_store.rb +65 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +31 -12
- data/lib/dragonfly/encoder.rb +13 -0
- data/lib/dragonfly/encoding/r_magick_encoder.rb +10 -19
- data/lib/dragonfly/endpoint.rb +43 -0
- data/lib/dragonfly/function_manager.rb +65 -0
- data/lib/dragonfly/{processing/r_magick_text_processor.rb → generation/r_magick_generator.rb} +25 -11
- data/lib/dragonfly/generator.rb +9 -0
- data/lib/dragonfly/job.rb +290 -0
- data/lib/dragonfly/job_builder.rb +39 -0
- data/lib/dragonfly/job_definitions.rb +26 -0
- data/lib/dragonfly/job_endpoint.rb +17 -0
- data/lib/dragonfly/loggable.rb +28 -0
- data/lib/dragonfly/middleware.rb +21 -14
- data/lib/dragonfly/processing/r_magick_processor.rb +71 -48
- data/lib/dragonfly/processor.rb +9 -0
- data/lib/dragonfly/r_magick_utils.rb +24 -0
- data/lib/dragonfly/rails/images.rb +10 -7
- data/lib/dragonfly/routed_endpoint.rb +42 -0
- data/lib/dragonfly/serializer.rb +32 -0
- data/lib/dragonfly/simple_cache.rb +23 -0
- data/lib/dragonfly/simple_endpoint.rb +64 -0
- data/lib/dragonfly/temp_object.rb +77 -45
- data/spec/argument_matchers.rb +7 -17
- data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
- data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
- data/spec/dragonfly/{active_record_extensions → active_model_extensions}/model_spec.rb +282 -244
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
- data/spec/dragonfly/analyser_spec.rb +123 -0
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +2 -2
- data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +10 -1
- data/spec/dragonfly/app_spec.rb +175 -69
- data/spec/dragonfly/configurable_spec.rb +14 -0
- data/spec/dragonfly/data_storage/data_store_spec.rb +36 -9
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +61 -38
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +18 -0
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +34 -39
- data/spec/dragonfly/deprecation_spec.rb +20 -0
- data/spec/dragonfly/function_manager_spec.rb +154 -0
- data/spec/dragonfly/generation/r_magick_generator_spec.rb +119 -0
- data/spec/dragonfly/job_builder_spec.rb +37 -0
- data/spec/dragonfly/job_definitions_spec.rb +35 -0
- data/spec/dragonfly/job_endpoint_spec.rb +66 -0
- data/spec/dragonfly/job_spec.rb +605 -0
- data/spec/dragonfly/loggable_spec.rb +80 -0
- data/spec/dragonfly/middleware_spec.rb +37 -17
- data/spec/dragonfly/processing/r_magick_processor_spec.rb +182 -166
- data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
- data/spec/dragonfly/serializer_spec.rb +61 -0
- data/spec/dragonfly/simple_cache_spec.rb +27 -0
- data/spec/dragonfly/simple_endpoint_spec.rb +78 -0
- data/spec/dragonfly/temp_object_spec.rb +154 -119
- data/spec/simple_matchers.rb +22 -0
- data/spec/spec_helper.rb +28 -4
- data/yard/templates/default/layout/html/layout.erb +18 -11
- metadata +89 -190
- data/config.rb +0 -5
- data/extra_docs/ActiveRecord.md +0 -196
- data/extra_docs/ExampleUseCases.md +0 -189
- data/extra_docs/GettingStarted.md +0 -114
- data/extra_docs/Shortcuts.md +0 -118
- data/extra_docs/UsingWithRails.md +0 -81
- data/features/rails_3.0.0.beta3.feature +0 -7
- data/fixtures/rails_3.0.0.beta3/template.rb +0 -16
- data/lib/dragonfly/active_record_extensions/attachment.rb +0 -170
- data/lib/dragonfly/analyser_list.rb +0 -9
- data/lib/dragonfly/analysis/base.rb +0 -10
- data/lib/dragonfly/belongs_to_app.rb +0 -24
- data/lib/dragonfly/config/heroku_rails_images.rb +0 -23
- data/lib/dragonfly/config/r_magick_images.rb +0 -69
- data/lib/dragonfly/config/r_magick_text.rb +0 -25
- data/lib/dragonfly/config/rails_images.rb +0 -13
- data/lib/dragonfly/data_storage/base.rb +0 -21
- data/lib/dragonfly/data_storage/base64_data_store.rb +0 -23
- data/lib/dragonfly/data_storage/transparent_data_store.rb +0 -21
- data/lib/dragonfly/delegatable.rb +0 -14
- data/lib/dragonfly/delegator.rb +0 -62
- data/lib/dragonfly/encoder_list.rb +0 -9
- data/lib/dragonfly/encoding/base.rb +0 -14
- data/lib/dragonfly/encoding/transparent_encoder.rb +0 -14
- data/lib/dragonfly/extended_temp_object.rb +0 -120
- data/lib/dragonfly/parameters.rb +0 -163
- data/lib/dragonfly/processing/base.rb +0 -10
- data/lib/dragonfly/processor_list.rb +0 -9
- data/lib/dragonfly/url_handler.rb +0 -147
- data/spec/dragonfly/active_record_extensions/attachment_spec.rb +0 -8
- data/spec/dragonfly/active_record_extensions/migration.rb +0 -42
- data/spec/dragonfly/active_record_extensions/models.rb +0 -6
- data/spec/dragonfly/active_record_extensions/spec_helper.rb +0 -24
- data/spec/dragonfly/belongs_to_app_spec.rb +0 -55
- data/spec/dragonfly/delegatable_spec.rb +0 -32
- data/spec/dragonfly/delegator_spec.rb +0 -145
- data/spec/dragonfly/extended_temp_object_spec.rb +0 -71
- data/spec/dragonfly/parameters_spec.rb +0 -298
- data/spec/dragonfly/processing/r_magick_text_processor_spec.rb +0 -84
- data/spec/dragonfly/url_handler_spec.rb +0 -247
- data/spec/dragonfly_spec.rb +0 -16
- data/spec/ginger_scenarios.rb +0 -13
@@ -0,0 +1,19 @@
|
|
1
|
+
module Dragonfly
|
2
|
+
module Config
|
3
|
+
|
4
|
+
module Heroku
|
5
|
+
|
6
|
+
def self.apply_configuration(app, bucket_name)
|
7
|
+
app.configure do |c|
|
8
|
+
c.datastore = Dragonfly::DataStorage::S3DataStore.new
|
9
|
+
c.datastore.configure do |d|
|
10
|
+
d.bucket_name = bucket_name
|
11
|
+
d.access_key_id = ENV['S3_KEY'] || raise("ENV variable 'S3_KEY' needs to be set - use\n\theroku config:add S3_KEY=XXXXXXXXX")
|
12
|
+
d.secret_access_key = ENV['S3_SECRET'] || raise("ENV variable 'S3_SECRET' needs to be set - use\n\theroku config:add S3_SECRET=XXXXXXXXX")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Dragonfly
|
2
|
+
module Config
|
3
|
+
|
4
|
+
# RMagick is a saved configuration for Dragonfly apps, which does the following:
|
5
|
+
# - registers an rmagick analyser
|
6
|
+
# - registers an rmagick processor
|
7
|
+
# - registers an rmagick encoder
|
8
|
+
# - adds thumb shortcuts like '280x140!', etc.
|
9
|
+
# Look at the source code for apply_configuration to see exactly how it configures the app.
|
10
|
+
module RMagick
|
11
|
+
|
12
|
+
def self.apply_configuration(app)
|
13
|
+
app.configure do |c|
|
14
|
+
c.analyser.register(Analysis::RMagickAnalyser)
|
15
|
+
c.processor.register(Processing::RMagickProcessor)
|
16
|
+
c.encoder.register(Encoding::RMagickEncoder)
|
17
|
+
c.generator.register(Generation::RMagickGenerator)
|
18
|
+
c.job :thumb do |geometry, format|
|
19
|
+
process :thumb, geometry
|
20
|
+
encode format if format
|
21
|
+
end
|
22
|
+
c.job :gif do
|
23
|
+
encode :gif
|
24
|
+
end
|
25
|
+
c.job :jpg do
|
26
|
+
encode :jpg
|
27
|
+
end
|
28
|
+
c.job :png do
|
29
|
+
encode :png
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,15 +1,14 @@
|
|
1
1
|
module Dragonfly
|
2
2
|
module Config
|
3
|
-
|
4
|
-
module
|
5
|
-
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
|
6
6
|
def self.apply_configuration(app)
|
7
7
|
app.configure do |c|
|
8
8
|
c.log = ::Rails.logger
|
9
|
-
c.datastore.root_path = "#{::Rails.root}/public/system/dragonfly/#{::Rails.env}"
|
10
|
-
c.
|
11
|
-
|
12
|
-
end
|
9
|
+
c.datastore.root_path = "#{::Rails.root}/public/system/dragonfly/#{::Rails.env}" if c.datastore.is_a?(DataStorage::FileDataStore)
|
10
|
+
c.url_path_prefix = '/media'
|
11
|
+
c.analyser.register(Analysis::FileCommandAnalyser)
|
13
12
|
end
|
14
13
|
end
|
15
14
|
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module Dragonfly
|
2
2
|
module Configurable
|
3
|
-
|
3
|
+
|
4
4
|
# Exceptions
|
5
5
|
class BadConfigAttribute < StandardError; end
|
6
|
-
|
6
|
+
|
7
7
|
def self.included(klass)
|
8
8
|
klass.class_eval do
|
9
9
|
include Configurable::InstanceMethods
|
10
10
|
extend Configurable::ClassMethods
|
11
|
-
|
11
|
+
|
12
12
|
# These aren't included in InstanceMethods because we need access to 'klass'
|
13
13
|
# We can't just put them into InstanceMethods and use 'self.class' because
|
14
14
|
# this won't always point to the class in which we've included Configurable,
|
@@ -17,25 +17,28 @@ module Dragonfly
|
|
17
17
|
@configuration_hash ||= klass.default_configuration.dup
|
18
18
|
end
|
19
19
|
private :configuration_hash
|
20
|
-
|
20
|
+
|
21
21
|
define_method :configuration_methods do
|
22
22
|
klass.configuration_methods
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
module InstanceMethods
|
29
|
-
|
29
|
+
|
30
30
|
def configure(&block)
|
31
31
|
yield ConfigurationProxy.new(self)
|
32
|
+
self
|
32
33
|
end
|
33
|
-
|
34
|
+
|
34
35
|
def configure_with(configurer, *args, &block)
|
36
|
+
configurer = configurer_for(configurer) if configurer.is_a?(Symbol)
|
35
37
|
configurer.apply_configuration(self, *args)
|
36
38
|
configure(&block) if block
|
39
|
+
self
|
37
40
|
end
|
38
|
-
|
41
|
+
|
39
42
|
def configuration
|
40
43
|
configuration_hash.dup
|
41
44
|
end
|
@@ -45,22 +48,22 @@ module Dragonfly
|
|
45
48
|
end
|
46
49
|
|
47
50
|
end
|
48
|
-
|
51
|
+
|
49
52
|
module ClassMethods
|
50
|
-
|
53
|
+
|
51
54
|
def default_configuration
|
52
55
|
@default_configuration ||= {}
|
53
56
|
end
|
54
|
-
|
57
|
+
|
55
58
|
def configuration_methods
|
56
59
|
@configuration_methods ||= []
|
57
60
|
end
|
58
|
-
|
61
|
+
|
59
62
|
private
|
60
|
-
|
63
|
+
|
61
64
|
def configurable_attr attribute, default=nil, &blk
|
62
65
|
default_configuration[attribute] = blk || default
|
63
|
-
|
66
|
+
|
64
67
|
# Define the reader
|
65
68
|
define_method(attribute) do
|
66
69
|
if configuration_hash[attribute].respond_to? :call
|
@@ -68,28 +71,28 @@ module Dragonfly
|
|
68
71
|
end
|
69
72
|
configuration_hash[attribute]
|
70
73
|
end
|
71
|
-
|
74
|
+
|
72
75
|
# Define the writer
|
73
76
|
define_method("#{attribute}=") do |value|
|
74
77
|
configuration_hash[attribute] = value
|
75
78
|
end
|
76
|
-
|
79
|
+
|
77
80
|
configuration_method attribute
|
78
81
|
configuration_method "#{attribute}="
|
79
82
|
end
|
80
|
-
|
83
|
+
|
81
84
|
def configuration_method(*method_names)
|
82
85
|
configuration_methods.push(*method_names.map{|n| n.to_sym })
|
83
86
|
end
|
84
|
-
|
87
|
+
|
85
88
|
end
|
86
|
-
|
89
|
+
|
87
90
|
class ConfigurationProxy
|
88
|
-
|
91
|
+
|
89
92
|
def initialize(owner)
|
90
93
|
@owner = owner
|
91
94
|
end
|
92
|
-
|
95
|
+
|
93
96
|
def method_missing(method_name, *args, &block)
|
94
97
|
if owner.has_configuration_method?(method_name)
|
95
98
|
owner.send(method_name, *args, &block)
|
@@ -99,16 +102,16 @@ module Dragonfly
|
|
99
102
|
raise BadConfigAttribute, "You tried to configure using '#{method_name.inspect}', but the valid config attributes are #{owner.configuration_methods.map{|a| %('#{a.inspect}') }.sort.join(', ')}"
|
100
103
|
end
|
101
104
|
end
|
102
|
-
|
105
|
+
|
103
106
|
private
|
104
|
-
|
107
|
+
|
105
108
|
attr_reader :owner
|
106
|
-
|
109
|
+
|
107
110
|
def nested_configurable?(method, *args)
|
108
111
|
owner.respond_to?(method) && owner.send(method, *args).is_a?(Configurable)
|
109
112
|
end
|
110
|
-
|
113
|
+
|
111
114
|
end
|
112
|
-
|
115
|
+
|
113
116
|
end
|
114
117
|
end
|
@@ -3,23 +3,24 @@ require 'pathname'
|
|
3
3
|
module Dragonfly
|
4
4
|
module DataStorage
|
5
5
|
|
6
|
-
class FileDataStore
|
6
|
+
class FileDataStore
|
7
7
|
|
8
8
|
include Configurable
|
9
|
-
|
10
|
-
configurable_attr :root_path, '/var/tmp/dragonfly'
|
11
9
|
|
12
|
-
|
10
|
+
configurable_attr :root_path, '/var/tmp/dragonfly'
|
13
11
|
|
14
|
-
|
12
|
+
def store(temp_object, opts={})
|
13
|
+
filename = temp_object.name || 'file'
|
15
14
|
|
15
|
+
relative_path = relative_path_for(filename)
|
16
16
|
begin
|
17
|
-
while File.exist?(
|
18
|
-
|
17
|
+
while File.exist?(path = absolute_path(relative_path))
|
18
|
+
filename = disambiguate(filename)
|
19
|
+
relative_path = relative_path_for(filename)
|
19
20
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
prepare_path(path)
|
22
|
+
temp_object.to_file(path).close
|
23
|
+
store_extra_data(path, temp_object)
|
23
24
|
rescue Errno::EACCES => e
|
24
25
|
raise UnableToStore, e.message
|
25
26
|
end
|
@@ -28,33 +29,33 @@ module Dragonfly
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def retrieve(relative_path)
|
31
|
-
|
32
|
+
path = absolute_path(relative_path)
|
33
|
+
[
|
34
|
+
File.new(path),
|
35
|
+
retrieve_extra_data(path)
|
36
|
+
]
|
32
37
|
rescue Errno::ENOENT => e
|
33
38
|
raise DataNotFound, e.message
|
34
39
|
end
|
35
40
|
|
36
41
|
def destroy(relative_path)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
FileUtils.rmdir dir if directory_empty?(dir)
|
42
|
-
end
|
42
|
+
path = absolute_path(relative_path)
|
43
|
+
FileUtils.rm path
|
44
|
+
FileUtils.rm extra_data_path(path)
|
45
|
+
purge_empty_directories(relative_path)
|
43
46
|
rescue Errno::ENOENT => e
|
44
47
|
raise DataNotFound, e.message
|
45
48
|
end
|
46
49
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
50
|
+
def disambiguate(filename)
|
51
|
+
basename = File.basename(filename, '.*')
|
52
|
+
extname = File.extname(filename)
|
53
|
+
"#{basename}_#{Time.now.usec.to_s(32)}#{extname}"
|
51
54
|
end
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
def absolute_storage_path(relative_path)
|
56
|
+
private
|
57
|
+
|
58
|
+
def absolute_path(relative_path)
|
58
59
|
File.join(root_path, relative_path)
|
59
60
|
end
|
60
61
|
|
@@ -62,6 +63,38 @@ module Dragonfly
|
|
62
63
|
Dir.entries(path) == ['.','..']
|
63
64
|
end
|
64
65
|
|
66
|
+
def extra_data_path(data_path)
|
67
|
+
"#{data_path}.extra"
|
68
|
+
end
|
69
|
+
|
70
|
+
def relative_path_for(filename)
|
71
|
+
"#{Time.now.strftime '%Y/%m/%d'}/#{filename.gsub(/[^\w.]+/,'_')}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def store_extra_data(data_path, temp_object)
|
75
|
+
File.open(extra_data_path(data_path), 'w') do |f|
|
76
|
+
f.write Marshal.dump(temp_object.attributes)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def retrieve_extra_data(data_path)
|
81
|
+
path = extra_data_path(data_path)
|
82
|
+
File.exist?(path) ? Marshal.load(File.read(path)) : {}
|
83
|
+
end
|
84
|
+
|
85
|
+
def prepare_path(path)
|
86
|
+
dir = File.dirname(path)
|
87
|
+
FileUtils.mkdir_p(dir) unless File.exist?(dir)
|
88
|
+
end
|
89
|
+
|
90
|
+
def purge_empty_directories(path)
|
91
|
+
containing_directory = Pathname.new(path).dirname
|
92
|
+
containing_directory.ascend do |relative_dir|
|
93
|
+
dir = absolute_path(relative_dir)
|
94
|
+
FileUtils.rmdir dir if directory_empty?(dir)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
65
98
|
end
|
66
99
|
|
67
100
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
|
3
|
+
module Dragonfly
|
4
|
+
module DataStorage
|
5
|
+
class MongoDataStore
|
6
|
+
|
7
|
+
include Configurable
|
8
|
+
include Serializer
|
9
|
+
|
10
|
+
configurable_attr :host
|
11
|
+
configurable_attr :port
|
12
|
+
configurable_attr :database, 'dragonfly'
|
13
|
+
|
14
|
+
def initialize(opts={})
|
15
|
+
self.host = opts[:host]
|
16
|
+
self.port = opts[:port]
|
17
|
+
self.database = opts[:database] if opts[:database]
|
18
|
+
end
|
19
|
+
|
20
|
+
def store(temp_object, opts={})
|
21
|
+
temp_object.file do |f|
|
22
|
+
mongo_id = grid.put(f, :metadata => marshal_encode(temp_object.attributes))
|
23
|
+
mongo_id.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def retrieve(uid)
|
28
|
+
grid_io = grid.get(bson_id(uid))
|
29
|
+
extra = marshal_decode(grid_io.metadata)
|
30
|
+
extra[:meta].merge!(:stored_at => grid_io.upload_date)
|
31
|
+
[
|
32
|
+
grid_io.read,
|
33
|
+
extra
|
34
|
+
]
|
35
|
+
rescue Mongo::GridFileNotFound, BSON::InvalidObjectID => e
|
36
|
+
raise DataNotFound, "#{e} - #{uid}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def destroy(uid)
|
40
|
+
grid.delete(bson_id(uid))
|
41
|
+
rescue Mongo::GridFileNotFound, BSON::InvalidObjectID => e
|
42
|
+
raise DataNotFound, "#{e} - #{uid}"
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def connection
|
48
|
+
@connection ||= Mongo::Connection.new(host, port)
|
49
|
+
end
|
50
|
+
|
51
|
+
def db
|
52
|
+
@db ||= connection.db(database)
|
53
|
+
end
|
54
|
+
|
55
|
+
def grid
|
56
|
+
@grid ||= Mongo::Grid.new(db)
|
57
|
+
end
|
58
|
+
|
59
|
+
def bson_id(uid)
|
60
|
+
BSON::ObjectID.from_string(uid)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -3,16 +3,23 @@ require 'aws/s3'
|
|
3
3
|
module Dragonfly
|
4
4
|
module DataStorage
|
5
5
|
|
6
|
-
class S3DataStore
|
7
|
-
|
6
|
+
class S3DataStore
|
7
|
+
|
8
8
|
include Configurable
|
9
9
|
include AWS::S3
|
10
|
-
|
10
|
+
include Serializer
|
11
|
+
|
11
12
|
configurable_attr :bucket_name
|
12
13
|
configurable_attr :access_key_id
|
13
14
|
configurable_attr :secret_access_key
|
14
15
|
configurable_attr :use_filesystem, true
|
15
16
|
|
17
|
+
def initialize(opts={})
|
18
|
+
self.bucket_name = opts[:bucket_name]
|
19
|
+
self.access_key_id = opts[:access_key_id]
|
20
|
+
self.secret_access_key = opts[:secret_access_key]
|
21
|
+
end
|
22
|
+
|
16
23
|
def connect!
|
17
24
|
AWS::S3::Base.establish_connection!(
|
18
25
|
:access_key_id => access_key_id,
|
@@ -24,22 +31,27 @@ module Dragonfly
|
|
24
31
|
Bucket.create(bucket_name) unless bucket_names.include?(bucket_name)
|
25
32
|
end
|
26
33
|
|
27
|
-
def store(temp_object)
|
28
|
-
uid = generate_uid(temp_object.
|
34
|
+
def store(temp_object, opts={})
|
35
|
+
uid = generate_uid(temp_object.name || 'file')
|
29
36
|
ensure_initialized
|
30
37
|
object = use_filesystem ? temp_object.file : temp_object.data
|
31
|
-
|
38
|
+
extra_data = temp_object.attributes
|
39
|
+
S3Object.store(uid, object, bucket_name, s3_metadata_for(extra_data))
|
32
40
|
object.close if use_filesystem
|
33
41
|
uid
|
34
42
|
end
|
35
43
|
|
36
44
|
def retrieve(uid)
|
37
45
|
ensure_initialized
|
38
|
-
S3Object.
|
46
|
+
s3_object = S3Object.find(uid, bucket_name)
|
47
|
+
[
|
48
|
+
s3_object.value,
|
49
|
+
parse_s3_metadata(s3_object.metadata)
|
50
|
+
]
|
39
51
|
rescue AWS::S3::NoSuchKey => e
|
40
52
|
raise DataNotFound, "#{e} - #{uid}"
|
41
53
|
end
|
42
|
-
|
54
|
+
|
43
55
|
def destroy(uid)
|
44
56
|
ensure_initialized
|
45
57
|
S3Object.delete(uid, bucket_name)
|
@@ -61,12 +73,19 @@ module Dragonfly
|
|
61
73
|
end
|
62
74
|
end
|
63
75
|
|
64
|
-
def generate_uid(
|
65
|
-
|
66
|
-
|
76
|
+
def generate_uid(name)
|
77
|
+
"#{Time.now.strftime '%Y/%m/%d/%H/%M/%S'}/#{rand(1000)}/#{name.gsub(/[^\w.]+/, '_')}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def s3_metadata_for(extra_data)
|
81
|
+
{'x-amz-meta-extra' => marshal_encode(extra_data)}
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_s3_metadata(metadata)
|
85
|
+
marshal_decode(metadata['x-amz-meta-extra'])
|
67
86
|
end
|
68
87
|
|
69
88
|
end
|
70
|
-
|
89
|
+
|
71
90
|
end
|
72
91
|
end
|