Browse Source
This patch is a proof-of-concept of Koha as a Mojolicious application This has several benefits: - Development setup is easier. No need for apache or nginx. Just run `morbo bin/intranet` or `morbo bin/opac` and go to http://localhost:3000 (URL rewrites and static files are handled by the app) - apache2/nginx configuration is simpler too (an example of nginx configuration is included in the patch) - starman and plack middlewares can still be used for debug or gzip compression for instance (see app.psgi) - Using Test::Mojo we can test the whole application, as we do with the REST API (which is a Mojolicious application too) - It opens a way for converting CGI scripts into Mojolicious controllers and actions (even if that's not possible at the moment because of the authentication code) It uses the same mechanism as Plack::App::CGIBin to deal with CGI scripts, so it should be equivalent in terms of performance How to test ? - Run `morbo bin/intranet`, then go to http://localhost:3000/ and try to find bugs. Check the REST API at http://localhost:3000/api/v1 - Run `morbo bin/opac`, then go to http://localhost:3000/ and try to find bugs. Check the REST API at http://localhost:3000/api/v1 - Run `starman -l :5000 -l :5001` and verify that intranet (http://localhost:5000) and opac (http://localhost:5001) work normally - Read the code (and the comments), it's not very long Signed-off-by: Jerome Charaoui <jcharaoui@cmaisonneuve.qc.ca> Signed-off-by: Victor Grousset/tuxayo <victor@tuxayo.net> Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com> Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>20.11.x
8 changed files with 457 additions and 0 deletions
@ -0,0 +1,85 @@ |
|||
package Koha::App::Intranet; |
|||
|
|||
# Copyright 2020 BibLibre |
|||
# |
|||
# This file is part of Koha. |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use Mojo::Base 'Mojolicious'; |
|||
|
|||
use Koha::Caches; |
|||
use Koha::Cache::Memory::Lite; |
|||
|
|||
sub startup { |
|||
my ($self) = @_; |
|||
|
|||
push @{$self->plugins->namespaces}, 'Koha::App::Plugin'; |
|||
push @{$self->static->paths}, $self->home->rel_file('koha-tmpl'); |
|||
|
|||
# Create route for all CGI scripts, need to be loaded first because of |
|||
# CGI::Compile |
|||
$self->plugin('CGIBinKoha'); |
|||
|
|||
# Create routes for API |
|||
# FIXME This generates routes like this: /api/api/v1/... |
|||
$self->plugin('RESTV1'); |
|||
|
|||
$self->hook(before_dispatch => \&_before_dispatch); |
|||
$self->hook(around_action => \&_around_action); |
|||
|
|||
my $r = $self->routes; |
|||
|
|||
$r->any('/')->to(cb => sub { shift->redirect_to('/cgi-bin/koha/mainpage.pl') }); |
|||
} |
|||
|
|||
sub _before_dispatch { |
|||
my $c = shift; |
|||
|
|||
my $path = $c->req->url->path->to_string; |
|||
|
|||
# Remove Koha version from URL |
|||
$path =~ s/_\d{2}\.\d{7}\.(js|css)/.$1/; |
|||
|
|||
# See FIXME above |
|||
if ($path =~ m|^/api/v|) { |
|||
$path = '/api' . $path; |
|||
} |
|||
|
|||
$c->req->url->path->parse($path); |
|||
} |
|||
|
|||
sub _around_action { |
|||
my ($next, $c, $action, $last) = @_; |
|||
|
|||
# Flush memory caches before every request |
|||
my $caches = $Koha::Caches::singleton_caches; |
|||
if ($caches) { |
|||
foreach my $key (keys %$caches) { |
|||
my $cache = $caches->{$key}; |
|||
if (ref $cache->{cache} eq 'Cache::Memory') { |
|||
$cache->flush_all; |
|||
} |
|||
$cache->flush_L1_cache; |
|||
} |
|||
} |
|||
$Koha::Caches::singleton_caches = {}; |
|||
Koha::Cache::Memory::Lite->flush(); |
|||
|
|||
return $next->(); |
|||
} |
|||
|
|||
1; |
@ -0,0 +1,85 @@ |
|||
package Koha::App::Opac; |
|||
|
|||
# Copyright 2020 BibLibre |
|||
# |
|||
# This file is part of Koha. |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use Mojo::Base 'Mojolicious'; |
|||
|
|||
use Koha::Caches; |
|||
use Koha::Cache::Memory::Lite; |
|||
|
|||
sub startup { |
|||
my ($self) = @_; |
|||
|
|||
push @{$self->plugins->namespaces}, 'Koha::App::Plugin'; |
|||
push @{$self->static->paths}, $self->home->rel_file('koha-tmpl'); |
|||
|
|||
# Create route for all CGI scripts, need to be loaded first because of |
|||
# CGI::Compile |
|||
$self->plugin('CGIBinKoha', opac => 1); |
|||
|
|||
# Create routes for API |
|||
# FIXME This generates routes like this: /api/api/v1/... |
|||
$self->plugin('RESTV1'); |
|||
|
|||
$self->hook(before_dispatch => \&_before_dispatch); |
|||
$self->hook(around_action => \&_around_action); |
|||
|
|||
my $r = $self->routes; |
|||
|
|||
$r->any('/')->to(cb => sub { shift->redirect_to('/cgi-bin/koha/opac-main.pl') }); |
|||
} |
|||
|
|||
sub _before_dispatch { |
|||
my $c = shift; |
|||
|
|||
my $path = $c->req->url->path->to_string; |
|||
|
|||
# Remove Koha version from URL |
|||
$path =~ s/_\d{2}\.\d{7}\.(js|css)/.$1/; |
|||
|
|||
# See FIXME above |
|||
if ($path =~ m|^/api/v|) { |
|||
$path = '/api' . $path; |
|||
} |
|||
|
|||
$c->req->url->path->parse($path); |
|||
} |
|||
|
|||
sub _around_action { |
|||
my ($next, $c, $action, $last) = @_; |
|||
|
|||
# Flush memory caches before every request |
|||
my $caches = $Koha::Caches::singleton_caches; |
|||
if ($caches) { |
|||
foreach my $key (keys %$caches) { |
|||
my $cache = $caches->{$key}; |
|||
if (ref $cache->{cache} eq 'Cache::Memory') { |
|||
$cache->flush_all; |
|||
} |
|||
$cache->flush_L1_cache; |
|||
} |
|||
} |
|||
$Koha::Caches::singleton_caches = {}; |
|||
Koha::Cache::Memory::Lite->flush(); |
|||
|
|||
return $next->(); |
|||
} |
|||
|
|||
1; |
@ -0,0 +1,100 @@ |
|||
package Koha::App::Plugin::CGIBinKoha; |
|||
|
|||
# Copyright 2020 BibLibre |
|||
# |
|||
# This file is part of Koha. |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use Mojo::Base 'Mojolicious::Plugin'; |
|||
|
|||
use CGI::Compile; |
|||
use CGI::Emulate::PSGI; |
|||
use IO::Scalar; |
|||
|
|||
sub register { |
|||
my ($self, $app, $conf) = @_; |
|||
|
|||
my $opac = $conf->{opac}; |
|||
|
|||
my $r = $app->routes; |
|||
|
|||
$r->any('/cgi-bin/koha/*script' => sub { |
|||
my ($c) = @_; |
|||
|
|||
my $script = $c->stash('script'); |
|||
|
|||
# Special case for installer which can takes a long time |
|||
$c->inactivity_timeout(300) if $script eq 'installer/install.pl'; |
|||
|
|||
# Remove trailing slash, if any (e.g. .../svc/config/systempreferences/) |
|||
$script =~ s|/$||; |
|||
|
|||
if ($opac) { |
|||
$script = "opac/$script"; |
|||
} |
|||
|
|||
unless (-e $c->app->home->rel_file($script)) { |
|||
return $c->reply->not_found; |
|||
} |
|||
|
|||
my $sub = CGI::Compile->compile($script); |
|||
my $app = CGI::Emulate::PSGI->handler($sub); |
|||
my $response = $app->($self->_psgi_env($c)); |
|||
|
|||
$c->res->code($response->[0]); |
|||
$c->res->headers->from_hash({ @{ $response->[1] } }); |
|||
$c->res->body(join('', @{$response->[2]})); |
|||
$c->rendered; |
|||
})->name('cgi'); |
|||
} |
|||
|
|||
sub _psgi_env { |
|||
my ($self, $c) = @_; |
|||
|
|||
my $env = $c->req->env; |
|||
|
|||
my $body = $c->req->build_body; |
|||
$env = { |
|||
%$env, |
|||
'psgi.input' => IO::Scalar->new(\$body), |
|||
'psgi.errors' => *STDERR, |
|||
REQUEST_METHOD => $c->req->method, |
|||
QUERY_STRING => $c->req->url->query->to_string, |
|||
SERVER_NAME => $c->req->url->to_abs->host, |
|||
SERVER_PORT => $c->req->url->to_abs->port, |
|||
SERVER_PROTOCOL => 'HTTP/1.1', |
|||
CONTENT_LENGTH => $c->req->headers->content_length, |
|||
CONTENT_TYPE => $c->req->headers->content_type, |
|||
REMOTE_ADDR => $c->tx->remote_address, |
|||
SCRIPT_NAME => $c->req->url->path->to_string, |
|||
}; |
|||
|
|||
# Starman sets PATH_INFO to the same value of SCRIPT_NAME, which confuses |
|||
# CGI and causes the redirect after OPAC login to fail |
|||
delete $env->{PATH_INFO} if ($env->{PATH_INFO} eq $env->{SCRIPT_NAME}); |
|||
|
|||
for my $name (@{ $c->req->headers->names }) { |
|||
my $value = $c->req->headers->header($name); |
|||
$name =~ s/-/_/g; |
|||
$name = 'HTTP_' . uc($name); |
|||
$env->{$name} = $value; |
|||
} |
|||
|
|||
return $env; |
|||
} |
|||
|
|||
1; |
@ -0,0 +1,32 @@ |
|||
package Koha::App::Plugin::RESTV1; |
|||
|
|||
# Copyright 2020 BibLibre |
|||
# |
|||
# This file is part of Koha. |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use Mojo::Base 'Mojolicious::Plugin'; |
|||
|
|||
use Koha::REST::V1; |
|||
|
|||
sub register { |
|||
my ($self, $app) = @_; |
|||
|
|||
$app->routes->any('/api')->detour(app => Koha::REST::V1->new); |
|||
} |
|||
|
|||
1; |
@ -0,0 +1,52 @@ |
|||
# Copyright 2020 BibLibre |
|||
# |
|||
# This file is part of Koha. |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use FindBin; |
|||
use Plack::Builder; |
|||
use Mojo::Server::PSGI; |
|||
|
|||
sub psgi_app { |
|||
my ($script) = @_; |
|||
|
|||
my $server = Mojo::Server::PSGI->new; |
|||
$server->load_app("$FindBin::Bin/$script"); |
|||
|
|||
return $server->to_psgi_app; |
|||
} |
|||
|
|||
my $opac = psgi_app('bin/opac'); |
|||
my $intranet = psgi_app('bin/intranet'); |
|||
|
|||
my $opac_port = $ENV{KOHA_OPAC_PORT} || 5001; |
|||
my $intranet_port = $ENV{KOHA_INTRANET_PORT} || 5000; |
|||
my $port2app = { |
|||
$opac_port => $opac, |
|||
$intranet_port => $intranet, |
|||
}; |
|||
|
|||
builder { |
|||
enable 'ReverseProxy'; |
|||
enable '+Koha::Middleware::SetEnv'; |
|||
enable '+Koha::Middleware::RealIP'; |
|||
sub { |
|||
my $env = shift; |
|||
my $app = $port2app->{$env->{SERVER_PORT}} || $intranet; |
|||
$app->($env); |
|||
}; |
|||
} |
@ -0,0 +1,43 @@ |
|||
#!/usr/bin/env perl |
|||
|
|||
# Copyright 2020 BibLibre |
|||
# |
|||
# This file is part of Koha. |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
# Copyright 2020 BibLibre |
|||
# |
|||
# This file is part of Koha. |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use FindBin; |
|||
use lib "$FindBin::Bin/.."; |
|||
|
|||
use Mojolicious::Commands; |
|||
|
|||
Mojolicious::Commands->start_app('Koha::App::Intranet'); |
@ -0,0 +1,27 @@ |
|||
#!/usr/bin/env perl |
|||
|
|||
# Copyright 2020 BibLibre |
|||
# |
|||
# This file is part of Koha. |
|||
# |
|||
# Koha is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# Koha is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
|||
|
|||
use Modern::Perl; |
|||
|
|||
use FindBin; |
|||
use lib "$FindBin::Bin/.."; |
|||
|
|||
use Mojolicious::Commands; |
|||
|
|||
Mojolicious::Commands->start_app('Koha::App::Opac'); |
@ -0,0 +1,33 @@ |
|||
# This config file assume you are using starman with the app.psgi that can be |
|||
# found in the root directory of Koha, and that it listens on ports 5000-5001 |
|||
|
|||
upstream intranet { |
|||
server 127.0.0.1:5000; |
|||
} |
|||
upstream opac { |
|||
server 127.0.0.1:5001; |
|||
} |
|||
|
|||
server { |
|||
listen 80; |
|||
listen [::]:80; |
|||
|
|||
server_name intranet.koha-dev; # CHANGEME |
|||
|
|||
location / { |
|||
include proxy_params; |
|||
proxy_pass http://intranet; |
|||
} |
|||
} |
|||
|
|||
server { |
|||
listen 80; |
|||
listen [::]:80; |
|||
|
|||
server_name opac.koha-dev; # CHANGEME |
|||
|
|||
location / { |
|||
include proxy_params; |
|||
proxy_pass http://opac; |
|||
} |
|||
} |
Loading…
Reference in new issue