jeremyboles-graffic 0.2.7 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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