PAGI-Server
view release on metacpan or search on metacpan
lib/PAGI/Server/Runner.pm view on Meta::CPAN
}
# If Future::IO::Impl::IOAsync not installed, that's fine - user just
# won't have Future::IO integration. Apps that need it will get a
# helpful error message from PAGI::SSE->every() or similar.
}
sub _is_module_name {
my ($self, $spec) = @_;
return $spec =~ /::/;
}
sub _is_file_path {
my ($self, $spec) = @_;
return $spec =~ m{/} || $spec =~ /\.(?:pl|psgi)$/i;
}
sub _load_module {
my ($self, $module, %args) = @_;
# Validate module name (basic security check)
die "Invalid module name: $module\n"
unless $module =~ /^[A-Za-z_][A-Za-z0-9_]*(?:::[A-Za-z_][A-Za-z0-9_]*)*$/;
# Try to load the module
my $file = $module;
$file =~ s{::}{/}g;
$file .= '.pm';
eval { require $file };
if ($@) {
die "Cannot find module '$module': $@\n";
}
die "Module '$module' does not have a new() method\n"
unless $module->can('new');
# Get the module's actual file path for correct home directory detection
my $module_file = $INC{$file};
# Instantiate, then normalize the resulting value. Discovery may produce
# either a native PAGI coderef or an application-provider object.
my $instance = eval { $module->new(%args, _caller_file => $module_file) };
die "Error constructing module '$module': $@\n" if $@;
return PAGI::Server::AppNormalizer::normalize_app(
$instance,
"Module '$module' constructor",
);
}
sub _load_file {
my ($self, $file) = @_;
# Convert to absolute path
$file = File::Spec->rel2abs($file);
die "App file not found: $file\n" unless -f $file;
# Match plackup behavior so FindBin::Bin resolves to the app file directory
local $0 = $file;
local @ARGV = ($file);
if (exists $INC{'FindBin.pm'}) {
FindBin::again();
}
my $app = do $file;
if ($@) {
die "Error loading $file: $@\n";
}
if (!defined $app && $!) {
die "Error reading $file: $!\n";
}
return PAGI::Server::AppNormalizer::normalize_app($app, 'App file');
}
sub _parse_app_args {
my ($self, @args) = @_;
my %result;
for my $arg (@args) {
if ($arg =~ /^([^=]+)=(.*)$/) {
$result{$1} = $2;
}
else {
$self->_log(warn => "Ignoring argument without '=': $arg");
}
}
return %result;
}
sub _show_help {
my ($self) = @_;
print <<'HELP';
Usage: pagi-server [options] [app] [key=value ...]
Common Options (handled by Runner):
-I, --lib PATH Add PATH to @INC (repeatable, like perl -I)
-a, --app FILE Load app from file (legacy option)
-o, --host HOST Bind address (default: 127.0.0.1)
-p, --port PORT Bind port (default: 5000)
-s, --server CLASS Server class (default: PAGI::Server)
-E, --env MODE Environment mode (development, production, none)
-l, --loop BACKEND Event loop backend (EV, Epoll, UV, Poll)
--access-log FILE Access log file (default: STDERR)
--no-access-log Disable access logging
--error-log FILE Diagnostic log file (default: STDERR)
-D, --daemonize Run as background daemon
--pid FILE Write PID to file
--user USER Run as specified user (after binding)
--group GROUP Run as specified group (after binding)
-q, --quiet Report errors only (shorthand for --log-level error)
--no-default-middleware Disable mode-based middleware
-v, --version Show version info
--help Show this help
Environment Modes:
development Auto-enable Lint middleware if PAGI-Tools installed (default if TTY)
production No auto-middleware (default if no TTY)
none Explicit opt-out of all auto-middleware
( run in 0.806 second using v1.01-cache-2.11-cpan-d80b1682f3f )