1 package Newslash::Plugin::JavaScriptLoader;
2 use Mojo::Base 'Mojolicious::Plugin';
5 use File::Basename qw(fileparse);
6 use Digest::MD5 qw(md5_hex);
10 use POSIX ":sys_wait_h";
11 use Mojo::Util qw(dumper);
14 use constant KVS_PREFIX => "JSL:";
15 use constant DEFAULT_MEM_EXPIRE => 60;
16 use constant DEFAULT_KVS_EXPIRE => 60;
19 return shift->{app}->kvs;
23 return shift->{app}->cache;
27 my ($self, $key, $value) = @_;
28 my $mem_expire = $self->{conf}->{mem_expire};
29 my $kvs_expire = $self->{conf}->{kvs_expire};
30 $mem_expire = DEFAULT_MEM_EXPIRE if !defined $mem_expire;
31 $kvs_expire = DEFAULT_KVS_EXPIRE if !defined $kvs_expire;
33 $self->_kvs->set(KVS_PREFIX . $key, $value, $kvs_expire);
34 $self->_cache->set(KVS_PREFIX . $key, $value, $mem_expire);
38 my ($self, $key) = @_;
39 my $expire = $self->{conf}->{mem_expire};
40 $expire = DEFAULT_MEM_EXPIRE if !defined $expire;
42 my $value = $self->_cache->get(KVS_PREFIX . $key);
43 return $value if defined $value;
45 $value = $self->_kvs->get(KVS_PREFIX . $key);
47 $self->_cache->set(KVS_PREFIX . $key, $value, $expire);
56 my ($self, $basename, $options) = @_;
57 my $content = $self->get_cache($basename);
58 return $content if defined $content;
60 $content = $self->_load_js($basename, $options);
61 if (defined $content) {
62 $self->set_cache($basename, $content);
63 $self->set_cache($content->{path}, $content);
74 my ($self, $basename, $options) = @_;
76 # check if file exists
77 my $abs_path = $self->_basename_to_absolute_path($basename);
78 return if (!-f $abs_path || !-r $abs_path);
81 open( my $fh, "<:utf8", $abs_path ) or return;
82 my $js_body = do { local($/); <$fh> } ;
86 if (utf8::is_utf8($js_body)) {
87 $md5 = md5_hex(Encode::encode('utf8', $js_body));
90 $md5 = md5_hex($js_body);
93 if ($self->{mode} eq "development") {
94 my $basedir = $self->{conf}->{source_directory};
95 $basedir =~ s/^public//g;
96 $path = "$basedir/$basename";
99 my ($base, $dir, $ext) = fileparse($basename, qw/\.[^.]*/);
100 $dir = "" if $dir eq "./";
101 my $basedir = $self->cached_basedir;
102 $path = "$basedir/$dir${base}.$md5$ext";
105 my $result = { md5 => $md5,
108 type => "text/javascript",
113 sub _basename_to_absolute_path {
114 my ($self, $basename) = @_;
115 my $base_dir = $self->{conf}->{base_directory};
117 $base_dir = $self->{app}->home;
119 if (!$base_dir) { # fallback
122 my $src_dir = $self->{conf}->{source_directory};
123 my $path = File::Spec->catdir($base_dir, $src_dir, $basename);
124 $path = File::Spec->rel2abs($path);
129 my ($self, $path) = @_;
130 if ($path =~ m/^(.+)\.([0-9a-f]+)(\.\w+)$/) {
131 return ($1 . $3, $2);
137 my ($self, $app, $conf) = @_;
139 my $c = $app->config->{JavaScriptLoader};
141 $app->log->error("JavaScriptLoader: no config settings found!");
145 $self->{conf} = {%$conf, %$c};
147 $self->{mode} = $self->{conf}->{mode} || $app->mode;
149 if (!$self->{conf}->{source_directory}) {
150 $app->log->warn("JavaScriptLoader: no source_directory given!");
153 $app->helper('load_js', sub {
155 my $content = $self->get_content($name);
157 return "<script src='$content->{path}'></script>";
159 $self->{app}->log->warn("JavaScriptLoader: cannot load $name");
163 my $r = $app->routes;
164 $r->any('/js_cache/*content_path' => sub {
166 my $path = $c->stash('content_path');
168 my $content = $self->get_cache($path);
170 # no cache, so try to generate
171 my ($basename, $md5) = $self->_split_md5($path);
172 $content = $self->get_content($basename);
175 if ($content && $content->{md5} ne $md5) {
180 $c->res->headers->content_type($content->{type});
181 $c->res->body(encode_utf8($content->{content}));
189 $app->helper(javascript_loader => sub { state $javascript_loader = $self; });