dragonfly-cache 0.1.2 → 0.1.3
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +4 -0
- data/lib/dragonfly/cache/config.rb +7 -0
- data/lib/dragonfly/cache/manager.rb +39 -52
- data/lib/dragonfly/cache/mapper/yaml.rb +42 -0
- data/lib/dragonfly/cache/plugin.rb +11 -29
- data/lib/dragonfly/cache/storage/local.rb +38 -0
- data/lib/dragonfly/cache/version.rb +1 -1
- metadata +4 -3
- data/lib/dragonfly/cache/storage.rb +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9c2bd6a296538d40627ac2d72d59b22899b939f058df6733c536cb8ccb31154
|
4
|
+
data.tar.gz: c42cb333f27257b8b2522433dc1a303768eb8eca01c829793e7e30ac1e51aa23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 405297344133ee35cb4547dd1d7499020cb77f751e3e81e23cf2378a77e6e6d5cb83e91fc11e60d105cd131bf54d67364bf197ab244299e700ba8f41ea4e7b75
|
7
|
+
data.tar.gz: fbbf31316483fd3721015225e25145967ad0dc2a929b68e042d5a0a064ca23958eba53c1328aace339dce28aa7b926e430c44e978722541f12b6743f96fa1fa4
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dragonfly-cache (0.1.
|
4
|
+
dragonfly-cache (0.1.3)
|
5
5
|
dragonfly (~> 1.1.5)
|
6
6
|
i18n
|
7
7
|
|
@@ -42,7 +42,7 @@ GEM
|
|
42
42
|
diff-lcs (>= 1.2.0, < 2.0)
|
43
43
|
rspec-support (~> 3.8.0)
|
44
44
|
rspec-support (3.8.0)
|
45
|
-
rubocop (0.
|
45
|
+
rubocop (0.59.0)
|
46
46
|
jaro_winkler (~> 1.5.1)
|
47
47
|
parallel (~> 1.10)
|
48
48
|
parser (>= 2.5, != 2.5.1.1)
|
data/README.md
CHANGED
@@ -43,3 +43,7 @@ Configured as this, cached files will be stored in `/public/media-cache/:sha/:na
|
|
43
43
|
## How does it work?
|
44
44
|
|
45
45
|
`dragonfly-cache` use a method similar to [the one described in the Dragonfly documentation to process files on-the-fly and serve them remotely](http://markevans.github.io/dragonfly/cache#processing-on-the-fly-and-serving-remotely) but use only `define_url`.
|
46
|
+
|
47
|
+
## Credits
|
48
|
+
|
49
|
+
The dragonfly photography used in specs is a work from [André Karwath](https://commons.wikimedia.org/wiki/User:Aka) and is licensed under the [Creative Commons Attribution-Share Alike 2.5 Generic](https://creativecommons.org/licenses/by-sa/2.5/deed.en) license.
|
@@ -15,6 +15,13 @@ module Dragonfly
|
|
15
15
|
rewrite_url_format!
|
16
16
|
end
|
17
17
|
|
18
|
+
def base_dir
|
19
|
+
@base_dir ||= begin
|
20
|
+
path_format = File.join(servers_options[:server_root], servers_options[:url_format])
|
21
|
+
path_format.split('/').take_while { |p| p != ':shaish' }.join('/')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
18
25
|
protected
|
19
26
|
|
20
27
|
def validate!
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'dragonfly/cache/
|
3
|
+
require 'dragonfly/cache/mapper/yaml'
|
4
|
+
require 'dragonfly/cache/storage/local'
|
4
5
|
|
5
6
|
module Dragonfly
|
6
7
|
module Cache
|
@@ -10,79 +11,65 @@ module Dragonfly
|
|
10
11
|
MIN_SHA_SIZE = 2
|
11
12
|
MAX_SHA_SIZE = 16 # Length of SHA identifier generated by Dragonfly
|
12
13
|
|
13
|
-
attr_reader :plugin, :storage, :
|
14
|
+
attr_reader :plugin, :storage, :map
|
14
15
|
|
15
|
-
delegate %i[
|
16
|
-
delegate %i[write writen? current_max_sha_size base_dir] => :storage
|
16
|
+
delegate %i[config] => :plugin
|
17
17
|
|
18
18
|
def initialize(plugin)
|
19
|
-
@plugin
|
20
|
-
@
|
21
|
-
|
19
|
+
@plugin = plugin
|
20
|
+
@map = Dragonfly::Cache::Mapper::Yaml.new(config.servers_options)
|
21
|
+
@storage = Dragonfly::Cache::Storage::Local.new(config.servers_options)
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
return
|
26
|
-
increase_sha_size!
|
27
|
-
false
|
28
|
-
end
|
29
|
-
|
30
|
-
def store(job, uri)
|
31
|
-
write(job, uri) unless writen?(job, uri)
|
32
|
-
map(job, uri) unless mapped?(job, uri)
|
33
|
-
rescue Dragonfly::Cache::Error => e
|
34
|
-
Dragonfly.warn(e.message)
|
35
|
-
end
|
24
|
+
def cache(job)
|
25
|
+
return @map[job.sha] if @map.key?(job.sha)
|
36
26
|
|
37
|
-
|
38
|
-
|
39
|
-
def wrong_key?(job, uri)
|
40
|
-
@cache_map.value?(uri.path) && @cache_map.key(uri.path) != job.sha
|
27
|
+
store(job, yield)
|
41
28
|
end
|
42
29
|
|
43
|
-
def
|
44
|
-
@
|
30
|
+
def valid?(job, uri)
|
31
|
+
valid = (@map.key?(job.sha) && @map[job.sha] == uri) || !@map.key?(job.sha)
|
32
|
+
increase_sha_size! unless valid
|
33
|
+
valid
|
45
34
|
end
|
46
35
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
36
|
+
def job_options(job)
|
37
|
+
{
|
38
|
+
shaish: shaish(job),
|
39
|
+
normalized_name: normalized_name(job)
|
40
|
+
}
|
52
41
|
end
|
53
42
|
|
54
|
-
|
55
|
-
@sha_size = [current_max_sha_size, MIN_SHA_SIZE].compact.max
|
56
|
-
@sha_size = [@sha_size, MAX_SHA_SIZE].min
|
57
|
-
end
|
58
|
-
|
59
|
-
def increase_sha_size!
|
60
|
-
raise Error, "Can't build longer :sha identifier" if @sha_size == MAX_SHA_SIZE
|
61
|
-
@sha_size += 1
|
43
|
+
protected
|
62
44
|
|
63
|
-
|
64
|
-
|
45
|
+
def shaish(job)
|
46
|
+
job.sha[0..(sha_size - 1)]
|
65
47
|
end
|
66
48
|
|
67
|
-
def
|
68
|
-
|
49
|
+
def normalized_name(job)
|
50
|
+
basename = job.basename || job.signature
|
51
|
+
sanitized = basename.gsub(/[[:space:][:punct:][:cntrl:]]/, ' ').squeeze(' ').strip
|
52
|
+
transliterated = I18n.transliterate(sanitized, replacement: ' ').squeeze(' ').strip
|
53
|
+
downcased = (transliterated.empty? ? job.signature : transliterated).downcase.tr(' ', '-')
|
54
|
+
[downcased, job.ext].compact.join('.')
|
69
55
|
end
|
70
56
|
|
71
|
-
def
|
72
|
-
@
|
57
|
+
def sha_size
|
58
|
+
@sha_size ||= [[storage.sha_size, MIN_SHA_SIZE].compact.max, MAX_SHA_SIZE].min
|
73
59
|
end
|
74
60
|
|
75
|
-
def
|
76
|
-
|
77
|
-
end
|
61
|
+
def increase_sha_size!
|
62
|
+
raise Error, "Can't build longer :sha identifier" if @sha_size == MAX_SHA_SIZE
|
78
63
|
|
79
|
-
|
80
|
-
@cache_map[job.sha] = uri.path
|
81
|
-
save_map
|
64
|
+
@sha_size += 1
|
82
65
|
end
|
83
66
|
|
84
|
-
def
|
85
|
-
|
67
|
+
def store(job, url)
|
68
|
+
storage.store(url, job)
|
69
|
+
map.store(job.sha, url)
|
70
|
+
url
|
71
|
+
rescue Dragonfly::Cache::Error => e
|
72
|
+
Dragonfly.warn(e.message)
|
86
73
|
end
|
87
74
|
end
|
88
75
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Dragonfly
|
6
|
+
module Cache
|
7
|
+
module Mapper
|
8
|
+
class Yaml
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
attr_reader :root, :internal
|
12
|
+
delegate %i[[] key? value? keys values] => :internal
|
13
|
+
|
14
|
+
def initialize(config)
|
15
|
+
@root = config[:server_root]
|
16
|
+
@internal = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def store(key, value)
|
20
|
+
@internal[key] = value
|
21
|
+
save!
|
22
|
+
end
|
23
|
+
|
24
|
+
alias []= store
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def path
|
29
|
+
@path ||= File.join(root, 'map.yml')
|
30
|
+
end
|
31
|
+
|
32
|
+
def load!
|
33
|
+
@internal = File.size?(path) ? YAML.load_file(path) : {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def save!
|
37
|
+
File.open(path, 'wb') { |f| YAML.dump(@internal, f) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -17,12 +17,11 @@ module Dragonfly
|
|
17
17
|
|
18
18
|
attr_reader :config, :manager
|
19
19
|
|
20
|
-
delegate %i[
|
21
|
-
delegate %i[sha_size valid_uri? store] => :manager
|
20
|
+
delegate %i[cache valid? job_options] => :manager
|
22
21
|
|
23
22
|
def call(app, cache_servers_options = {})
|
24
|
-
@config
|
25
|
-
@manager
|
23
|
+
@config = Dragonfly::Cache::Config.new(cache_servers_options)
|
24
|
+
@manager = Dragonfly::Cache::Manager.new(self)
|
26
25
|
|
27
26
|
app.define_url do |app, job, opts|
|
28
27
|
url_for(app, job, opts)
|
@@ -32,41 +31,24 @@ module Dragonfly
|
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
35
|
-
protected
|
36
|
-
|
37
34
|
def url_for(app, job, opts)
|
38
|
-
|
39
|
-
# File are stored on url building instead of in a before_serve block to allow use of assets host
|
40
|
-
store(job, uri)
|
41
|
-
uri.to_s
|
35
|
+
cache(job) { build_url_for(app, job, opts) }
|
42
36
|
end
|
43
37
|
|
44
|
-
|
38
|
+
protected
|
39
|
+
|
40
|
+
def build_url_for(app, job, opts)
|
45
41
|
loop do
|
46
|
-
url = server_for(app).url_for(job,
|
47
|
-
|
48
|
-
|
49
|
-
uri.fragment = nil
|
50
|
-
return uri if valid_uri?(job, uri)
|
42
|
+
url = server_for(app).url_for(job, job_options(job).merge(opts))
|
43
|
+
path = URI.parse(url).path
|
44
|
+
return path if valid?(job, path)
|
51
45
|
end
|
52
46
|
end
|
53
47
|
|
54
|
-
def options_for(job)
|
55
|
-
basename = job.basename || job.signature
|
56
|
-
sanitized = basename.gsub(/[[:space:][:punct:][:cntrl:]]/, ' ').squeeze(' ').strip
|
57
|
-
transliterated = I18n.transliterate(sanitized, replacement: ' ').squeeze(' ').strip
|
58
|
-
downcased = (transliterated.empty? ? job.signature : transliterated).downcase.tr(' ', '-')
|
59
|
-
|
60
|
-
{
|
61
|
-
shaish: job.sha[0..(sha_size - 1)],
|
62
|
-
normalized_name: [downcased, job.ext].join('.')
|
63
|
-
}
|
64
|
-
end
|
65
|
-
|
66
48
|
def server_for(app)
|
67
49
|
@@servers[app.name] ||= begin
|
68
50
|
server = app.server.dup
|
69
|
-
servers_options.each do |name, value|
|
51
|
+
config.servers_options.each do |name, value|
|
70
52
|
server.send("#{name}=", value) if server.respond_to?("#{name}=")
|
71
53
|
end
|
72
54
|
server
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dragonfly
|
4
|
+
module Cache
|
5
|
+
module Storage
|
6
|
+
class Local
|
7
|
+
attr_reader :root, :format
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
@root = config[:server_root]
|
11
|
+
@format = config[:url_format]
|
12
|
+
end
|
13
|
+
|
14
|
+
def store(url, job)
|
15
|
+
job.to_file(path(url), mode: 0o644)
|
16
|
+
end
|
17
|
+
|
18
|
+
def sha_size
|
19
|
+
longest = Dir["#{base_dir}/*"].select { |p| File.directory?(p) }.max { |a, b| a <=> b }
|
20
|
+
(longest ? File.basename(longest).size : nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def path(url)
|
26
|
+
File.join(root, url)
|
27
|
+
end
|
28
|
+
|
29
|
+
def base_dir
|
30
|
+
@base_dir ||= begin
|
31
|
+
path_format = File.join(root, format)
|
32
|
+
path_format.split('/').take_while { |p| p != ':shaish' }.join('/')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dragonfly-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gaël-Ian Havard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dragonfly
|
@@ -113,8 +113,9 @@ files:
|
|
113
113
|
- lib/dragonfly/cache.rb
|
114
114
|
- lib/dragonfly/cache/config.rb
|
115
115
|
- lib/dragonfly/cache/manager.rb
|
116
|
+
- lib/dragonfly/cache/mapper/yaml.rb
|
116
117
|
- lib/dragonfly/cache/plugin.rb
|
117
|
-
- lib/dragonfly/cache/storage.rb
|
118
|
+
- lib/dragonfly/cache/storage/local.rb
|
118
119
|
- lib/dragonfly/cache/version.rb
|
119
120
|
homepage: https://github.com/notus-sh/dragonfly-cache
|
120
121
|
licenses:
|
@@ -1,68 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dragonfly
|
4
|
-
module Cache
|
5
|
-
class Storage
|
6
|
-
extend Forwardable
|
7
|
-
|
8
|
-
attr_reader :manager
|
9
|
-
|
10
|
-
delegate %i[servers_options] => :manager
|
11
|
-
|
12
|
-
def initialize(manager)
|
13
|
-
@manager = manager
|
14
|
-
check_directory!(base_dir)
|
15
|
-
end
|
16
|
-
|
17
|
-
def current_max_sha_size
|
18
|
-
longest = Dir["#{base_dir}/*"].select { |p| File.directory?(p) }.max { |a, b| a <=> b }
|
19
|
-
(longest ? File.basename(longest).size : nil)
|
20
|
-
end
|
21
|
-
|
22
|
-
def write(job, uri)
|
23
|
-
path = cache_path(uri)
|
24
|
-
check_directory!(File.dirname(path))
|
25
|
-
with_umask(0o022) do
|
26
|
-
job.to_file(path, mode: 0o644, mkdirs: false)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def writen?(_job, uri)
|
31
|
-
File.exist?(cache_path(uri))
|
32
|
-
end
|
33
|
-
|
34
|
-
def base_dir
|
35
|
-
@base_dir ||= begin
|
36
|
-
path_format = File.join(servers_options[:server_root], servers_options[:url_format])
|
37
|
-
path_format.split('/').take_while { |p| p != ':shaish' }.join('/')
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
protected
|
42
|
-
|
43
|
-
def check_directory!(directory)
|
44
|
-
return if File.exist?(directory) && File.directory?(directory) && File.writable?(directory)
|
45
|
-
with_umask(0o022) do
|
46
|
-
File.unlink(directory) if File.exist?(directory) && !File.directory?(directory)
|
47
|
-
FileUtils.mkdir_p(directory, mode: 0o755) unless File.exist?(directory)
|
48
|
-
File.chmod(0o755, directory) unless File.writable?(directory)
|
49
|
-
end
|
50
|
-
rescue ::StandardError => e
|
51
|
-
raise Dragonfly::Cache::Error, e.message
|
52
|
-
end
|
53
|
-
|
54
|
-
def with_umask(umask)
|
55
|
-
original_umask = File.umask(umask)
|
56
|
-
begin
|
57
|
-
yield
|
58
|
-
ensure
|
59
|
-
File.umask(original_umask)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def cache_path(uri)
|
64
|
-
File.join(servers_options[:server_root], uri.path)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|