registerRoutes(); } /** * Registers the routes for the server. * * This method is responsible for defining the routes that the server will handle. * It should be implemented in subclasses to provide specific route definitions. * * @return void */ public function registerRoutes(): void { $this->worker = new PSR7Worker( Worker::create(), new Psr17Factory(), new Psr17Factory(), new Psr17Factory() ); $this->router = new Router(); $this->router->get('/', IndexController::class . '::get'); $this->router->post('/', IndexController::class . '::post'); $this->router->get('/healthz', HealthcheckController::class . '::get'); $this->router->group('/.well-known', function (RouteGroup $router) { $router->get('/swagger.yaml', OpenApiController::class . '::get'); $router->get('/swagger.json', OpenApiController::class . '::get'); }); $this->router->middleware(new CorsMiddleware()); $this->router->middleware(new JwtMiddleware()); $this->router->middleware(new ScopeMiddleware()); } /** * Starts the server and handles incoming requests. * * This method enters an infinite loop to continuously handle incoming HTTP requests. * It decodes the request body, routes the request, and sends the response. It also handles * exceptions and ensures proper cleanup after each request. * * @throws \JsonException If there is an error decoding the JSON request body. */ public function startServer(): void { Logger::info(sprintf('Server started: %s', microtime(true))); Logger::info(sprintf('Server PID: %s', getmypid())); Logger::info(sprintf('Server Listening on: 0.0.0.0:%s', Config::get('server.port'))); while (true) { try { $request = $this->worker->waitRequest(); if ($request === null) { break; } $request = $request->withParsedBody(json_decode($request->getBody()->getContents(), true)); $response = $this->router->handle($request); $this->worker->respond($response); } catch (MethodNotAllowedException | NotFoundException) { $this->worker->respond( JsonResponseFactory::createJsonResponse( ['status_code' => 404, 'reason_phrase' => 'Not Found'], CodesEnum::NOT_FOUND ) ); } catch (\Throwable $e) { Logger::error($e->getMessage()); Logger::error($e->getTraceAsString()); $json = ['status_code' => 500, 'reason_phrase' => 'Server Error']; if (Config::get("server.dev_mode")) { $json = [ 'status_code' => 500, 'reason_phrase' => 'Server Error', 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]; } $this->worker->respond( JsonResponseFactory::createJsonResponse($json, CodesEnum::INTERNAL_SERVER_ERROR) ); } } } }