Multiple app directories with Dancer perl
Is there a way to have one app in dancer but with multiple appdirs.
Or could I do something like this:
My project is in dir 'foo'. And let's say that I have a dir 'bar' (not inside 'foo') which has开发者_JAVA百科 a directory called 'public'. I what my app 'foo' to use this public as its own public and if it searches for let's say '/css/style.css' and it is not in '/bar/public/' it should search the '/foo/public/'. How can I do that?
OK, here is the good way to do it. It can of course be a plugin.
You should never do this kind of things by hacking inside Dancer's core, you should rather always consider implementing a route handler to do the job:
#!/usr/bin/env perl
use Dancer;
use File::Spec;
use Dancer::FileUtils 'read_file_content';
use Dancer::MIME;
use HTTP::Date;
# your routes here
# then the catchall route for
# serving static files
# better in config
my @public_dirs = qw(/tmp/test/foo /tmp/test/bar /tmp/test/baz);
get '/**' => sub {
my $path = request->path;
my $mime = Dancer::MIME->instance;
# security checks
return send_error("unauthrorized request", 403) if $path =~ /\0/;
return send_error("unauthrorized request", 403) if $path =~ /\.\./;
# decompose the path_info into a file path
my @path = split '/', $path;
for my $location (@public_dirs) {
my $file_path = File::Spec->catfile($location, @path);
next if ! -f $file_path;
my $content = read_file_content($file_path);
my $content_type = $mime->for_file($file_path);
my @stat = stat $file_path;
header 'Content-Type', $content_type;
header 'Content-Length', $stat[7];
header 'Last-Modified', HTTP::Date::time2str($stat[9]);
return $content;
}
pass;
};
start;
An example of this app running:
$ mkdir -p /tmp/test/foo /tmp/test/bar /tmp/test/baz
$ echo 1 > /tmp/test/foo/foo.txt
$ echo 2 > /tmp/test/bar/bar.txt
$ echo 3 > /tmp/test/baz/baz.txt
$ ./bin/app.pl
$ curl -I http://0:3000/baz.txt
HTTP/1.0 200 OK
Content-Length: 2
Content-Type: text/plain
Last-Modified: Fri, 14 Oct 2011 11:28:03 GMT
X-Powered-By: Perl Dancer 1.3051
One of the ways if to write a plugin that renders static (and replaces some functionality). You can use Dancer::Plugin::Thumbnail as an example.
Other way I see is to monkey-patch get_file_response()
at Dancer::Renderer which is not really such a good idea.
Following code looks for static files in each dir from @dirs
array. It's dirty, ugly and unsafe.
This can be broken in future version and may cause problems with other parts of Dancer framework I'm not familiar with. You're warned.
#!/usr/bin/env perl
use Dancer;
use Dancer::Renderer;
use MyWeb::App;
my $get_file_response_original = \&Dancer::Renderer::get_file_response;
my @dirs = ('foo');
*Dancer::Renderer::get_file_response = sub {
my $app = Dancer::App->current;
my $result;
# Try to find static in default dir
if ($result = $get_file_response_original->(@_)) {
return $result;
}
# Save current settings
my $path_backup = $app->setting('public');
# Go through additional dirs
foreach my $dir (@dirs) {
$app->setting(public => $dir);
if ($result = $get_file_response_original->(@_)) {
last;
}
}
# Restore public
$app->setting('public' => $path_backup);
return $result
};
dance;
Third ways is to let nginx just do this work for you by writing proper nginx config for your application.
May be this module will help to you? https://github.com/Perlover/Dancer-Plugin-Hosts You can setup virtual sites in Dancer with own appdir & other directory settings I uploaded this module today to github Soon will be in CPAN
精彩评论