shutterbug 0.0.11 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.ruby-version +1 -1
  2. data/.travis.yml +2 -3
  3. data/Guardfile +5 -0
  4. data/README.md +59 -10
  5. data/config.ru +5 -3
  6. data/demo/{withIframe.html → iframe_example.html} +0 -0
  7. data/demo/index.html +7 -24
  8. data/demo/oil-and-water/heatbath.svg +20 -0
  9. data/demo/oil-and-water/ke-gradient.svg +27 -0
  10. data/demo/oil-and-water/oil-and-water.svg +487 -0
  11. data/demo/simple_example.html +35 -0
  12. data/demo/svg_example.html +571 -0
  13. data/images/shutterbug.jpg +0 -0
  14. data/lib/shutterbug.rb +4 -6
  15. data/lib/shutterbug/cache_manager.rb +6 -0
  16. data/lib/shutterbug/cache_manager/cache_entry.rb +19 -0
  17. data/lib/shutterbug/cache_manager/no_cache.rb +19 -0
  18. data/lib/shutterbug/configuration.rb +20 -24
  19. data/lib/shutterbug/handlers.rb +7 -0
  20. data/lib/shutterbug/handlers/convert_handler.rb +38 -0
  21. data/lib/shutterbug/handlers/file_handlers.rb +9 -0
  22. data/lib/shutterbug/handlers/file_handlers/base.rb +39 -0
  23. data/lib/shutterbug/handlers/file_handlers/html_file.rb +22 -0
  24. data/lib/shutterbug/handlers/file_handlers/png_file.rb +23 -0
  25. data/lib/shutterbug/handlers/js_file_handler.rb +27 -0
  26. data/lib/shutterbug/{shutterbug.js → handlers/shutterbug.js} +26 -3
  27. data/lib/shutterbug/phantom_job.rb +17 -12
  28. data/lib/shutterbug/rackapp.rb +33 -31
  29. data/lib/shutterbug/storage.rb +6 -0
  30. data/lib/shutterbug/storage/file_storage.rb +20 -0
  31. data/lib/shutterbug/storage/s3_storage.rb +75 -0
  32. data/shutterbug.gemspec +3 -0
  33. data/spec/shared_examples_for_file_handlers.rb +16 -0
  34. data/spec/shared_examples_for_handlers.rb +26 -0
  35. data/spec/shared_examples_for_storage.rb +17 -0
  36. data/spec/shutterbug/configuration_spec.rb +83 -0
  37. data/spec/shutterbug/convert_handler_spec.rb +29 -0
  38. data/spec/shutterbug/file_storage_spec.rb +5 -0
  39. data/spec/shutterbug/html_file_handler_spec.rb +10 -0
  40. data/spec/shutterbug/js_file_handler_spec.rb +4 -0
  41. data/spec/shutterbug/png_file_handler_spec.rb +10 -0
  42. data/spec/shutterbug/rackapp_spec.rb +49 -41
  43. data/spec/shutterbug/s3_storage_spec.rb +12 -0
  44. metadata +205 -105
  45. data/lib/shutterbug/bug_file.rb +0 -22
  46. data/lib/shutterbug/html_file.rb +0 -3
  47. data/lib/shutterbug/js_file.rb +0 -11
  48. data/lib/shutterbug/png_file.rb +0 -3
  49. data/lib/shutterbug/service.rb +0 -39
Binary file
data/lib/shutterbug.rb CHANGED
@@ -1,11 +1,9 @@
1
1
  module Shutterbug
2
- VERSION = "0.0.11"
3
- autoload :Service, "shutterbug/service"
2
+ VERSION = "0.1.0"
4
3
  autoload :Rackapp, "shutterbug/rackapp"
5
4
  autoload :Configuration, "shutterbug/configuration"
6
- autoload :BugFile, "shutterbug/bug_file"
7
- autoload :HtmlFile, "shutterbug/html_file"
8
- autoload :PngFile, "shutterbug/png_file"
9
- autoload :JsFile, "shutterbug/js_file"
5
+ autoload :Storage, "shutterbug/storage"
6
+ autoload :Handlers, "shutterbug/handlers"
10
7
  autoload :PhantomJob, "shutterbug/phantom_job"
8
+ autoload :CacheManager, "shutterbug/cache_manager"
11
9
  end
@@ -0,0 +1,6 @@
1
+ module Shutterbug
2
+ module CacheManager
3
+ autoload :NoCache, "shutterbug/cache_manager/no_cache"
4
+ autoload :CacheEntry, "shutterbug/cache_manager/cache_entry"
5
+ end
6
+ end
@@ -0,0 +1,19 @@
1
+ module Shutterbug
2
+ module CacheManager
3
+ class CacheEntry
4
+ attr_accessor :key
5
+ attr_accessor :url
6
+ attr_accessor :preview_url
7
+
8
+ def initialize(storage)
9
+ @key = storage.filename
10
+ @url = storage.url
11
+ @preview_url = storage.url
12
+ end
13
+
14
+ def image_tag
15
+ "<img src='#{self.preview_url}' alt='#{self.preview_url}'>"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Shutterbug
2
+ module CacheManager
3
+ class NoCache
4
+ attr_accessor :entries
5
+ def initialize
6
+ @entries = {}
7
+ end
8
+
9
+ def find(key)
10
+ return @entries[key]
11
+ end
12
+
13
+ def add_entry(cache_entry)
14
+ @entries[cache_entry.key] = cache_entry
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,4 @@
1
+ require 'tmpdir'
1
2
  module Shutterbug
2
3
  class Configuration
3
4
 
@@ -5,6 +6,10 @@ module Shutterbug
5
6
  attr_accessor :path_prefix
6
7
  attr_accessor :resource_dir
7
8
  attr_accessor :phantom_bin_path
9
+ attr_accessor :s3_bin
10
+ attr_accessor :s3_key
11
+ attr_accessor :s3_secret
12
+ attr_accessor :cache_manager
8
13
 
9
14
  def self.instance(opts={})
10
15
  return @instance || @instance = self.new(opts)
@@ -15,43 +20,34 @@ module Shutterbug
15
20
  self.path_prefix = opts[:path_prefix] || "/shutterbug"
16
21
  self.resource_dir = opts[:resource_dir] || Dir.tmpdir
17
22
  self.phantom_bin_path = opts[:phantom_bin_path] || "phantomjs"
23
+ self.s3_bin = opts[:s3_bin]
24
+ self.s3_key = opts[:s3_key]
25
+ self.s3_secret = opts[:s3_secret]
26
+ self.cache_manager = opts[:cache_manager] || Shutterbug::CacheManager::NoCache.new
18
27
  end
19
28
 
20
- def js_path
21
- "#{uri_prefix}#{path_prefix}/shutterbug.js"
29
+ def fs_path_for(filename)
30
+ File.join(resource_dir,"phantom_#{filename}")
22
31
  end
23
32
 
24
- def js_regex
25
- /#{path_prefix}\/shutterbug.js/
26
- end
27
-
28
- def js_file
29
- File.join(File.dirname(__FILE__),"shutterbug.js")
33
+ def url_prefix
34
+ "#{uri_prefix}#{path_prefix}"
30
35
  end
31
36
 
32
37
  def convert_path
33
- "#{uri_prefix}#{path_prefix}/make_snapshot"
34
- end
35
- def convert_regex
36
- /#{path_prefix}\/make_snapshot/
38
+ "#{url_prefix}/make_snapshot"
37
39
  end
38
40
 
39
- def png_path(sha='')
40
- "#{uri_prefix}#{path_prefix}/get_png/#{sha}"
41
- end
42
- def png_regex
43
- /#{path_prefix}\/get_png\/([^\/]+)/
41
+ def base_url(req)
42
+ req.POST()['base_url'] || req.referrer || "#{req.scheme}://#{req.host_with_port}"
44
43
  end
45
44
 
46
- def html_path(sha='')
47
- "#{uri_prefix}#{path_prefix}/get_html/#{sha}"
48
- end
49
- def html_regex
50
- /#{path_prefix}\/get_html\/([^\/]+)/
45
+ def storage
46
+ use_s3? ? Storage::S3Storage : Storage::FileStorage
51
47
  end
52
48
 
53
- def base_url(req)
54
- req.POST()['base_url'] || req.referrer || "#{req.scheme}://#{req.host_with_port}"
49
+ def use_s3?
50
+ return (self.s3_bin && self.s3_key && self.s3_secret)
55
51
  end
56
52
  end
57
53
  end
@@ -0,0 +1,7 @@
1
+ require "shutterbug/handlers/file_handlers"
2
+ module Shutterbug
3
+ module Handlers
4
+ autoload :ConvertHandler, "shutterbug/handlers/convert_handler"
5
+ autoload :JsFileHandler, "shutterbug/handlers/js_file_handler"
6
+ end
7
+ end
@@ -0,0 +1,38 @@
1
+ require 'stringio'
2
+ module Shutterbug
3
+ module Handlers
4
+ class ConvertHandler
5
+
6
+ def initialize(_config = Configuration.instance)
7
+ @config = _config
8
+ end
9
+
10
+ def regex
11
+ /#{@config.path_prefix}\/make_snapshot/
12
+ end
13
+
14
+ def handle(helper, req, env)
15
+ response_text = convert(req).image_tag
16
+ helper.good_response(response_text,'text/plain')
17
+ end
18
+
19
+ def convert(req)
20
+ html = req.POST()['content'] || ""
21
+ width = req.POST()['width'] || 1000
22
+ height = req.POST()['height'] || 700
23
+ css = req.POST()['css'] || ""
24
+ job = PhantomJob.new(@config.base_url(req), html, css, width, height)
25
+ unless (cache_entry = @config.cache_manager.find(job.cache_key))
26
+ job.rasterize
27
+ html_entry = Shutterbug::CacheManager::CacheEntry.new(job.html_file)
28
+ png_entry = Shutterbug::CacheManager::CacheEntry.new(job.png_file)
29
+ html_entry.preview_url = png_entry.preview_url
30
+ @config.cache_manager.add_entry(html_entry)
31
+ cache_entry = @config.cache_manager.add_entry(png_entry)
32
+ end
33
+ # return the image tag
34
+ return cache_entry
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,9 @@
1
+ module Shutterbug
2
+ module Handlers
3
+ module FileHandlers
4
+ require "shutterbug/handlers/file_handlers/base"
5
+ require "shutterbug/handlers/file_handlers/html_file"
6
+ require "shutterbug/handlers/file_handlers/png_file"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ require 'tmpdir'
2
+ module Shutterbug
3
+ module Handlers
4
+ module FileHandlers
5
+ class Base
6
+ attr_accessor :config
7
+
8
+ def self.instance
9
+ return @instance || self.new
10
+ end
11
+
12
+ def initialize(_config = Configuration.instance)
13
+ self.config = _config
14
+ end
15
+
16
+ def urlify(name)
17
+ "#{self.path_prefix}/#{name}"
18
+ end
19
+
20
+ def path_prefix
21
+ "#{self.config.path_prefix}/get_#{file_extension}"
22
+ end
23
+
24
+ def filename_matcher
25
+ "(([^\/|\.]+)\.?([^\/]+))?"
26
+ end
27
+
28
+ def regex
29
+ /#{path_prefix}\/#{filename_matcher}/
30
+ end
31
+
32
+ def filename(base)
33
+ "#{base}.#{file_extension}"
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ module Shutterbug
2
+ module Handlers
3
+ module FileHandlers
4
+ class HtmlFile < Base
5
+
6
+ def file_extension
7
+ "html"
8
+ end
9
+
10
+ def mime_type
11
+ "text/html"
12
+ end
13
+
14
+ def handle(helper, req, env)
15
+ sha = regex.match(req.path)[1]
16
+ file = @config.storage.new(filename(sha),self)
17
+ helper.good_response(file.get_content, self.mime_type)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module Shutterbug
2
+ module Handlers
3
+ module FileHandlers
4
+ class PngFile < Base
5
+
6
+ def file_extension
7
+ "png"
8
+ end
9
+
10
+ def mime_type
11
+ "image/png"
12
+ end
13
+
14
+ def handle(helper, req, env)
15
+ local_filename = regex.match(req.path)[1]
16
+ file = @config.storage.new(local_filename,self)
17
+ helper.good_response(file.get_content, self.mime_type)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,27 @@
1
+ module Shutterbug
2
+ module Handlers
3
+ class JsFileHandler
4
+
5
+ def self.js_path
6
+ "#{Configuration.instance.url_prefix}/shutterbug.js"
7
+ end
8
+
9
+ def regex
10
+ /#{@config.path_prefix}\/shutterbug.js/
11
+ end
12
+
13
+ def js_file
14
+ File.join(File.dirname(__FILE__),"shutterbug.js")
15
+ end
16
+
17
+ def initialize(_config=Configuration.instance())
18
+ @config = _config
19
+ @javascript = File.read(js_file).gsub(/CONVERT_PATH/,@config.convert_path)
20
+ end
21
+
22
+ def handle(helper, req, env)
23
+ helper.good_response(@javascript, 'application/javascript')
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,5 +1,6 @@
1
1
  /*global $ */
2
2
  (function(){
3
+ var $ = window.$;
3
4
 
4
5
  var getBaseUrl = function() {
5
6
  var base = window.location.href;
@@ -72,17 +73,31 @@
72
73
  }
73
74
  }
74
75
  var self = this;
76
+ var time = 0;
77
+ var counter = $("<span>");
78
+ counter.html(time);
79
+
80
+ $(self.imgDst).html("creating snapshot: ").append(counter);
81
+ var timer = setInterval(function(t) {
82
+ time = time + 1;
83
+ counter.html(time);
84
+ }, 1000);
85
+
75
86
  $.ajax({
76
87
  url: "CONVERT_PATH",
77
88
  type: "POST",
78
89
  data: html
79
- }).done(function(msg) {
90
+ }).success(function(msg) {
80
91
  if(self.imgDst) {
81
92
  $(self.imgDst).html(msg);
82
93
  }
83
94
  if (self.callback) {
84
95
  self.callback(msg);
85
96
  }
97
+ clearInterval(timer);
98
+ }).fail(function(e) {
99
+ $(self.imgDst).html("snapshot failed");
100
+ clearInterval(timer);
86
101
  });
87
102
  };
88
103
 
@@ -95,7 +110,16 @@
95
110
  destination.postMessage(JSON.stringify(message),"*");
96
111
  };
97
112
 
98
- window.Shutterbug = function(selector,imgDst,callback,id) {
113
+ window.Shutterbug = function(selector,imgDst,callback,id,jQuery) {
114
+ if (typeof(jQuery) != "undefined" && jQuery != null) {
115
+ $ = jQuery;
116
+ }
117
+ // If we still don't have a valid jQuery, try setting it from the global jQuery default.
118
+ // This can happen if shutterbug.js is included before jquery.js
119
+ if ((typeof($) == "undefined" || $ == null) && typeof(window.$) != "undefined" && window.$ != null) {
120
+ $ = window.$;
121
+ }
122
+
99
123
  var shutterbugInstance = {
100
124
  element: selector,
101
125
  imgDst: imgDst,
@@ -150,5 +174,4 @@
150
174
  });
151
175
  return shutterbugInstance;
152
176
  };
153
-
154
177
  })();
@@ -5,7 +5,7 @@ module Shutterbug
5
5
  attr_accessor :html_file
6
6
 
7
7
  def program
8
- Configuration.instance.phantom_bin_path
8
+ @config.phantom_bin_path
9
9
  end
10
10
 
11
11
  def rasterize_js
@@ -18,10 +18,11 @@ module Shutterbug
18
18
  @css = css
19
19
  @width = width
20
20
  @height = height
21
+ @config = Configuration.instance
21
22
  end
22
23
 
23
24
  def cache_key
24
- return @key || @key = Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}")[0..10]
25
+ @cache_key ||= Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}")[0..10]
25
26
  end
26
27
 
27
28
  def document
@@ -42,29 +43,33 @@ module Shutterbug
42
43
  """
43
44
  end
44
45
 
45
- def base_path
46
- Configuration.instance.resource_dir
46
+ def html_file_name
47
+ "#{cache_key}.html"
47
48
  end
48
49
 
49
- def infilename
50
- File.join(base_path,"phantom_#{cache_key}.html")
50
+ def png_file_name
51
+ "#{cache_key}.png"
51
52
  end
52
53
 
53
- def outfilename
54
- File.join(base_path,"phantom_#{cache_key}.png")
54
+ def input_path
55
+ @config.fs_path_for(html_file_name)
56
+ end
57
+
58
+ def output_path
59
+ @config.fs_path_for(png_file_name)
55
60
  end
56
61
 
57
62
  def rasterize_cl
58
- %x[#{self.program} #{self.rasterize_js} #{self.infilename} #{self.outfilename} #{@width}*#{@height}]
63
+ %x[#{self.program} #{self.rasterize_js} #{self.input_path} #{self.output_path} #{@width}*#{@height}]
59
64
  end
60
65
 
61
66
  def rasterize
62
- File.open(infilename, 'w') do |f|
67
+ File.open(input_path, 'w') do |f|
63
68
  f.write(document)
64
69
  end
65
70
  rasterize_cl()
66
- self.png_file = PngFile.new(outfilename)
67
- self.html_file = HtmlFile.new(infilename)
71
+ self.png_file = @config.storage.new(png_file_name, Shutterbug::Handlers::FileHandlers::PngFile.new)
72
+ self.html_file = @config.storage.new(html_file_name, Shutterbug::Handlers::FileHandlers::HtmlFile.new)
68
73
  end
69
74
  end
70
75
  end