Hypersonic
view release on metacpan or search on metacpan
lib/Hypersonic.pm view on Meta::CPAN
push @ws_handlers, $route->{handler};
push @ws_paths, $route->{path};
# Check for Room usage in route options
if ($route->{opts}{rooms}) {
$self->{route_analysis}{needs_websocket_rooms} = 1;
}
}
$self->{_websocket_handlers} = \@ws_handlers;
$self->{_websocket_paths} = \@ws_paths;
$self->{route_analysis}{needs_websocket} = 1;
# Handler is needed if we have websocket routes
$self->{route_analysis}{needs_websocket_handler} = 1;
# WebSocket uses Stream for connection handling
$self->{route_analysis}{needs_streaming} = 1;
}
# JIT: Explicit opt-in for Room support (can also be set in new())
if ($self->{websocket_rooms}) {
$self->{route_analysis}{needs_websocket_rooms} = 1;
}
# JIT: Build per-route middleware arrays (only if route middleware is present)
my $analysis = $self->{route_analysis};
if ($analysis->{has_route_middleware}) {
my @route_before_mw;
my @route_after_mw;
for my $route (@{$self->{routes}}) {
next unless $route->{dynamic};
# Store arrays of middleware handlers per route (by handler_idx)
push @route_before_mw, $route->{before};
push @route_after_mw, $route->{after};
}
$self->{_route_before_mw} = \@route_before_mw;
$self->{_route_after_mw} = \@route_after_mw;
}
# JIT: Store Perl-only middleware for runtime call_sv dispatch
# Builder middleware is handled at compile time (inline C), not runtime
if ($analysis->{has_global_before} || $analysis->{has_global_after}) {
$self->{_perl_before_mw} = $analysis->{perl_before};
$self->{_perl_after_mw} = $analysis->{perl_after};
}
# Generate C code with pure C event loop
my $c_code = $self->_generate_server_code(\@full_responses);
# Compile via XS::JIT
#
# Derive a STABLE module id from a hash of the generated C source
# (plus this dist's $VERSION and the target perl's archname/version
# so a cache built for one perl is never loaded into another).
#
# Pre-0.18 we used 'Hypersonic::_Server_' . int(rand(100000)) which
# gave a different module name on every fresh perl process; because
# XS::JIT's on-disk cache lives at
# <cache_dir>/lib/auto/<safe_name>/<safe_name>.<dlext>
# (see XS-JIT/lib/XS/JIT/xs_jit.c xs_jit_cache_path()), a different
# $name on every run forced a full gcc/cc re-invocation EVERY time
# the test suite or a user re-ran their server. On slow CPAN smoker
# boxes that gcc invocation takes 30-60+ seconds per server, which
# is what caused the SIGKILL cascade in CPAN tester reports for
# 0.17 (t/0035-e2e-streaming.t, t/2012..t/2017, t/2102).
#
# Using a content hash means: identical route+option configurations
# produce the same module name -> warm cache hit -> dlopen() of a
# 100ms .so instead of a 30s gcc rebuild. The random fallback id is
# retained for the degenerate case where Digest::MD5 isn't available.
my $module_id;
{
my $hash_input = join("\0",
$c_code,
$VERSION,
(defined $Config::Config{archname}
? $Config::Config{archname} : ''),
$] || '',
);
if (eval { require Digest::MD5; 1 }) {
# 16 hex chars (64 bits) is plenty of namespace for one
# process and short enough to keep the on-disk file names
# readable. md5_hex is core since perl 5.7.3.
$module_id = substr(Digest::MD5::md5_hex($hash_input), 0, 16);
} else {
# No Digest::MD5? Fall back to the legacy random id. Cache
# won't be reused across runs but at least nothing breaks.
$module_id = $self->{id};
}
}
my $module_name = 'Hypersonic::_Server_' . $module_id;
# Build compile options - add TLS flags if enabled
my %functions = (
"${module_name}::run_event_loop" => {
source => 'hypersonic_run_event_loop',
is_xs_native => 1,
},
"${module_name}::dispatch" => {
source => 'hypersonic_dispatch',
is_xs_native => 1,
},
);
# Add Stream and SSE XS functions if streaming is enabled
if ($self->{route_analysis}{needs_streaming}) {
%functions = (%functions, %{Hypersonic::Stream->get_xs_functions()});
%functions = (%functions, %{Hypersonic::SSE->get_xs_functions()});
}
# Add WebSocket XS functions if WebSocket routes are registered
if ($self->{route_analysis}{needs_websocket}) {
require Hypersonic::WebSocket;
%functions = (%functions, %{Hypersonic::WebSocket->get_xs_functions()});
}
# Add WebSocket Handler XS functions
if ($self->{route_analysis}{needs_websocket_handler}) {
require Hypersonic::WebSocket::Handler;
%functions = (%functions, %{Hypersonic::WebSocket::Handler->get_xs_functions()});
}
# Add WebSocket Room XS functions
if ($self->{route_analysis}{needs_websocket_rooms}) {
( run in 1.123 second using v1.01-cache-2.11-cpan-9581c071862 )