start method
Implementation
Future<void> start({int port = 8080, String? host}) async {
final handler = HttpRequestProcessor(
router: _router,
globalMiddleware: _middleware.pipeline,
staticHandler: _static.staticHandler,
);
_server = await HttpServer.bind(
host != null ? InternetAddress(host) : InternetAddress.anyIPv4,
port,
shared: true,
);
final server = _server!;
// Enable compression and set idle timeout
server.autoCompress = autoCompress;
server.idleTimeout = idleTimeout;
Log.info('🟢 HTTP Server started on http://${host ?? 'localhost'}:$port');
// Handle graceful shutdown
_signalSubscription = ProcessSignal.sigint.watch().listen((signal) {
Log.info('🛑 Received signal $signal. Shutting down...');
stop().then((_) {
Log.info('👋 Server closed.');
exit(0);
});
});
try {
await for (final raw in server) {
final req = Request(raw);
final res = Response(raw);
Zone.current.fork(
zoneValues: {
ServerContext.zoneKey: ServerContext(
request: req,
response: res,
),
},
).run(() async {
try {
// Execute global middleware pipeline with the request processor as the final handler
// This uses the optimized static execute method to avoid allocations
await MiddlewarePipeline.execute(
_middleware.pipeline.middleware,
req,
res,
(request, response) {
if (response is! Response) {
throw StateError(
'HTTP server lifecycle requires a concrete Response instance.',
);
}
return handler.handle(request, response);
},
);
} catch (e, stackTrace) {
final exceptionHandler = resolve<ExceptionHandlerContract>();
final result = await exceptionHandler.handle(e, stackTrace);
if (!res.sent) {
res.status(result.statusCode).problem(
title: result.title,
status: result.statusCode,
detail: result.message,
type: result.type,
instance: result.instance,
extensions: {
if (result.details != null) 'details': result.details,
if (result.stackTrace != null)
'stack_trace': result.stackTrace.toString(),
...result.extensions,
},
);
}
} finally {
// Clean up request resources (e.g. temporary files)
await req.cleanup();
}
});
}
} finally {
await _signalSubscription?.cancel();
}
}