jeremyboles-graffic 0.2.7 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/graffic.rb +80 -87
- data/lib/graffic/view_helpers.rb +1 -1
- metadata +1 -1
data/lib/graffic.rb
CHANGED
@@ -11,21 +11,26 @@ require 'graffic/view_helpers'
|
|
11
11
|
# A Graffic record progresses through four states: received, moved, uploaded and processed.
|
12
12
|
# Graffic is designed in a way to let slow operating states out of the request cycle, if desired.
|
13
13
|
#
|
14
|
+
# TODO: Figure out how to make this read-only
|
15
|
+
#
|
14
16
|
class Graffic < ActiveRecord::Base
|
17
|
+
after_create :move
|
15
18
|
after_destroy :delete_s3_file
|
16
19
|
|
17
|
-
attr_writer :file, :processor
|
18
|
-
|
19
20
|
before_validation_on_create :set_initial_state
|
20
21
|
|
21
22
|
belongs_to :resource, :polymorphic => true
|
22
23
|
|
23
|
-
class_inheritable_accessor :bucket_name
|
24
|
+
class_inheritable_accessor :bucket_name
|
24
25
|
class_inheritable_accessor :format, :default => 'png'
|
25
26
|
class_inheritable_accessor :process_queue_name, :default => 'graffic_process'
|
26
27
|
class_inheritable_accessor :upload_queue_name, :default => 'graffic_upload'
|
28
|
+
class_inheritable_accessor :should_process_versions, :use_queue, :default => true
|
27
29
|
class_inheritable_accessor :tmp_dir, :default => RAILS_ROOT + '/tmp/graffics'
|
28
|
-
|
30
|
+
class_inheritable_accessor :processors, :default => []
|
31
|
+
class_inheritable_accessor :versions, :default => {}
|
32
|
+
|
33
|
+
attr_writer :file, :processors
|
29
34
|
|
30
35
|
validate_on_create :file_was_given
|
31
36
|
|
@@ -35,6 +40,7 @@ class Graffic < ActiveRecord::Base
|
|
35
40
|
@bucket ||= Graffic::Aws.s3.bucket(bucket_name, true, 'public-read')
|
36
41
|
end
|
37
42
|
|
43
|
+
# Create the tmp dir to store files until we upload them
|
38
44
|
def create_tmp_dir
|
39
45
|
FileUtils.mkdir(tmp_dir) unless File.exists?(tmp_dir)
|
40
46
|
end
|
@@ -45,7 +51,7 @@ class Graffic < ActiveRecord::Base
|
|
45
51
|
data = YAML.load(message.to_s)
|
46
52
|
begin
|
47
53
|
record = find(data[:id])
|
48
|
-
record.process
|
54
|
+
record.process
|
49
55
|
rescue ActiveRecord::RecordNotFound
|
50
56
|
return 'Not found'
|
51
57
|
ensure
|
@@ -55,13 +61,14 @@ class Graffic < ActiveRecord::Base
|
|
55
61
|
end
|
56
62
|
|
57
63
|
# Handles the first message in the upload queue
|
64
|
+
# TODO: Figure out a better way to handle messages when records aren't there
|
58
65
|
def handle_top_in_upload_queue!
|
59
66
|
if message = upload_queue.receive
|
60
67
|
data = YAML.load(message.to_s)
|
61
68
|
return if data[:hostname] != `hostname`.strip
|
62
69
|
begin
|
63
70
|
record = find(data[:id])
|
64
|
-
record.upload
|
71
|
+
record.upload
|
65
72
|
rescue ActiveRecord::RecordNotFound
|
66
73
|
return 'Not found'
|
67
74
|
ensure
|
@@ -70,10 +77,13 @@ class Graffic < ActiveRecord::Base
|
|
70
77
|
end
|
71
78
|
end
|
72
79
|
|
80
|
+
# DSL method for processing images
|
73
81
|
def process(&block)
|
74
|
-
self.
|
82
|
+
self.processors ||= []
|
83
|
+
self.processors << block if block_given?
|
75
84
|
end
|
76
85
|
|
86
|
+
# When we create a new type of Graffic, make sure we save the original
|
77
87
|
def inherited(subclass)
|
78
88
|
subclass.has_one(:original, :class_name => 'Graffic', :as => :resource, :dependent => :destroy, :conditions => { :name => 'original' })
|
79
89
|
super
|
@@ -84,12 +94,10 @@ class Graffic < ActiveRecord::Base
|
|
84
94
|
@process_queue ||= Graffic::Aws.sqs.queue(process_queue_name, true)
|
85
95
|
end
|
86
96
|
|
97
|
+
# DSL method for making thumbnails
|
87
98
|
def size(name, size = {})
|
88
99
|
size.assert_valid_keys(:width, :height)
|
89
|
-
version(name)
|
90
|
-
img = img.first if img.respond_to?(:first)
|
91
|
-
img.crop_resized(size[:width], size[:height])
|
92
|
-
end
|
100
|
+
version(name) { |img| img.crop_resized(size[:width], size[:height]) }
|
93
101
|
end
|
94
102
|
|
95
103
|
# The queue for uploading images
|
@@ -97,12 +105,11 @@ class Graffic < ActiveRecord::Base
|
|
97
105
|
@upload_queue ||= Graffic::Aws.sqs.queue(upload_queue_name, true)
|
98
106
|
end
|
99
107
|
|
108
|
+
# DSL method for declaring a version of an image
|
100
109
|
def version(name, &block)
|
101
|
-
self.versions ||=
|
102
|
-
if block_given?
|
103
|
-
|
104
|
-
has_one(name, :class_name => 'Graffic', :as => :resource, :dependent => :destroy, :conditions => { :name => name.to_s })
|
105
|
-
end
|
110
|
+
self.versions[name] ||= []
|
111
|
+
self.versions[name] << block if block_given?
|
112
|
+
has_one(name, :class_name => 'Graffic', :as => :resource, :dependent => :destroy, :conditions => { :name => name.to_s })
|
106
113
|
end
|
107
114
|
end
|
108
115
|
|
@@ -111,6 +118,7 @@ class Graffic < ActiveRecord::Base
|
|
111
118
|
attributes['format'] || self.class.format
|
112
119
|
end
|
113
120
|
|
121
|
+
# Return an RMagick image, based on the state of image
|
114
122
|
def image
|
115
123
|
@image ||= case self.state
|
116
124
|
when 'moved': Magick::Image.read(tmp_file_path).first
|
@@ -119,70 +127,51 @@ class Graffic < ActiveRecord::Base
|
|
119
127
|
end
|
120
128
|
|
121
129
|
# Move the file to the temporary directory
|
122
|
-
def move
|
123
|
-
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
# Move the file to the temporary directory
|
128
|
-
def move_without_queue!
|
130
|
+
def move
|
131
|
+
logger.debug("***** Moving? #{self.state}")
|
132
|
+
return unless self.state == 'received'
|
129
133
|
logger.debug("***** Graffic[#{self.id}](#{self.name})#move!")
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
134
|
+
logger.debug("***** File type: #{@file.class.name}")
|
135
|
+
if @file.is_a?(Tempfile) # Uploaded File
|
136
|
+
FileUtils.cp(@file.path, tmp_file_path)
|
137
|
+
logger.debug("***** Moving file: #{@file.path}, #{tmp_file_path}")
|
138
|
+
elsif @file.is_a?(String) # String representing a file's location
|
139
|
+
FileUtils.cp(@file.strip, tmp_file_path)
|
140
|
+
logger.debug("***** Moving file: #{@file.strip}, #{tmp_file_path}")
|
141
|
+
elsif @file.is_a?(Magick::Image) # An actually RMagick file
|
137
142
|
@image = @file
|
138
|
-
|
143
|
+
self.use_queue = false
|
139
144
|
change_state('uploaded')
|
145
|
+
process
|
146
|
+
return
|
147
|
+
else
|
148
|
+
raise "Don't know how to handle file type #{@file.class.name}"
|
140
149
|
end
|
150
|
+
|
151
|
+
change_state('moved')
|
152
|
+
use_queue? ? queue_for_upload : upload
|
141
153
|
end
|
142
154
|
|
143
|
-
|
144
|
-
def
|
145
|
-
|
146
|
-
process_versions
|
155
|
+
attr_accessor :should_process_versions
|
156
|
+
def should_process_versions?
|
157
|
+
should_process_versions.nil? ? self.class.should_process_versions : should_process_versions
|
147
158
|
end
|
148
159
|
|
149
|
-
# Process the image
|
150
|
-
def
|
160
|
+
# Process the image
|
161
|
+
def process
|
162
|
+
return unless self.state == 'uploaded'
|
151
163
|
logger.debug("***** Graffic[#{self.id}](#{self.name})#process!")
|
152
164
|
run_processors
|
153
165
|
record_image_dimensions_and_format
|
154
166
|
upload_image
|
155
167
|
change_state('processed')
|
168
|
+
|
169
|
+
process_versions if should_process_versions?
|
156
170
|
end
|
157
|
-
|
171
|
+
|
158
172
|
# Returns the processor for the instance
|
159
|
-
def
|
160
|
-
@
|
161
|
-
end
|
162
|
-
|
163
|
-
# Move the file if it saved successfully
|
164
|
-
def save_and_move
|
165
|
-
move! if status = save
|
166
|
-
status
|
167
|
-
end
|
168
|
-
|
169
|
-
# Save the file and process it immediately. Does to use queues.
|
170
|
-
def save_and_process
|
171
|
-
if status = save
|
172
|
-
move_without_queue!
|
173
|
-
upload_without_queue!
|
174
|
-
process!
|
175
|
-
end
|
176
|
-
status
|
177
|
-
end
|
178
|
-
|
179
|
-
def save_and_process_without_versions
|
180
|
-
if status = save
|
181
|
-
move_without_queue!
|
182
|
-
upload_without_queue!
|
183
|
-
process_without_verions!
|
184
|
-
end
|
185
|
-
status
|
173
|
+
def processors
|
174
|
+
@processors || self.class.processors
|
186
175
|
end
|
187
176
|
|
188
177
|
# Returns a size string. Good for RMagick and image_tag :size
|
@@ -191,18 +180,15 @@ class Graffic < ActiveRecord::Base
|
|
191
180
|
end
|
192
181
|
|
193
182
|
# Upload the file
|
194
|
-
def upload
|
195
|
-
|
196
|
-
queue_for_processing
|
197
|
-
end
|
198
|
-
|
199
|
-
# Upload the file
|
200
|
-
def upload_without_queue!
|
183
|
+
def upload
|
184
|
+
return unless self.state == 'moved'
|
201
185
|
logger.debug("***** Graffic[#{self.id}](#{self.name})#upload!")
|
202
186
|
upload_image
|
203
187
|
save_original
|
204
188
|
remove_tmp_file
|
189
|
+
|
205
190
|
change_state('uploaded')
|
191
|
+
use_queue? ? queue_for_processing : process
|
206
192
|
end
|
207
193
|
|
208
194
|
# Return the url for displaying the image
|
@@ -210,6 +196,11 @@ class Graffic < ActiveRecord::Base
|
|
210
196
|
self.s3_key.public_link
|
211
197
|
end
|
212
198
|
|
199
|
+
attr_accessor :use_queue
|
200
|
+
def use_queue?
|
201
|
+
use_queue.nil? ? self.class.use_queue : use_queue
|
202
|
+
end
|
203
|
+
|
213
204
|
protected
|
214
205
|
|
215
206
|
# Connivence method for getting the bucket
|
@@ -243,15 +234,12 @@ protected
|
|
243
234
|
end
|
244
235
|
|
245
236
|
def process_versions
|
246
|
-
|
247
|
-
self.
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
self.update_attribute(version, g)
|
253
|
-
end
|
254
|
-
end
|
237
|
+
self.versions.each do |version, processors|
|
238
|
+
logger.debug("***** Graffic[#{self.id}](#{self.name}): Processing version: #{version} (#{processors.size} processors)")
|
239
|
+
g = Graffic.new(:file => self.image, :name => version.to_s, :use_queue => false)
|
240
|
+
g.processors += processors unless processors.nil?
|
241
|
+
self.update_attribute(version, g)
|
242
|
+
end unless self.versions.blank?
|
255
243
|
end
|
256
244
|
|
257
245
|
def queue_for_upload
|
@@ -281,11 +269,17 @@ protected
|
|
281
269
|
end
|
282
270
|
|
283
271
|
def run_processors
|
284
|
-
logger.debug("***** Graffic[#{self.id}](#{self.name}): Running processor")
|
285
|
-
|
286
|
-
|
272
|
+
logger.debug("***** Graffic[#{self.id}](#{self.name}): Running processor (#{self.processors.try(:size)} processors)")
|
273
|
+
self.processors.each do |processor|
|
274
|
+
img = self.image
|
275
|
+
img = img.first if img.respond_to?(:first)
|
276
|
+
@image = case processor.arity # Pass in the record itself, if the block wants it
|
277
|
+
when 1: processor.call(img)
|
278
|
+
when 2: processor.call(img, self)
|
279
|
+
end
|
287
280
|
raise 'You need to return an image' unless @image.is_a?(Magick::Image)
|
288
|
-
|
281
|
+
logger.debug("Returned Image Size: #{@image.columns}x#{@image.rows}")
|
282
|
+
end unless self.processors.blank?
|
289
283
|
end
|
290
284
|
|
291
285
|
def s3_key
|
@@ -295,8 +289,7 @@ protected
|
|
295
289
|
def save_original
|
296
290
|
if respond_to?(:original)
|
297
291
|
logger.debug("***** Graffic[#{self.id}](#{self.name}): Saving Original")
|
298
|
-
g = Graffic.new(:file => tmp_file_path, :name => 'original')
|
299
|
-
g.save_and_process
|
292
|
+
g = Graffic.new(:file => tmp_file_path, :name => 'original', :use_queue => false)
|
300
293
|
self.update_attribute(:original, g)
|
301
294
|
end
|
302
295
|
end
|
data/lib/graffic/view_helpers.rb
CHANGED