boot(); } /** * Bootstraps the server by initializing the PSR-7 worker and router. * * This method sets up the PSR-7 worker and router instances, and registers * the routes for the server. It should be called in the constructor of * subclasses to ensure proper initialization. * * @return void */ private function boot(): void { $container = new Container(); Facade::setFacadeApplication($container); $this->worker = new PSR7Worker( Worker::create(), new Psr17Factory(), new Psr17Factory(), new Psr17Factory() ); $this->router = new Router(); $this->router->setStrategy(new JsonStrategy(new JsonResponseFactory())); $this->registerRoutes(); // $this->bootModelCapsule(); // no db } /** * Bootstraps the model capsule for database connections. * * This method sets up the database connection using the Eloquent ORM. * It retrieves the database configuration from the Config facade and * initializes the Eloquent capsule manager. * * @return void */ public function bootModelCapsule(): void { $capsule = new Manager(); $capsule->addConnection([ 'driver' => Config::get('db.driver'), 'host' => Config::get('db.host'), 'database' => Config::get('db.database'), 'username' => Config::get('db.username'), 'password' => Config::get('db.password'), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ]); $capsule->setAsGlobal(); $capsule->bootEloquent(); } /** * 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 */ protected function registerRoutes(): void { $this->router->addPatternMatcher('protocolEnums', 'http|tcp|udp'); $this->router->addPatternMatcher('protocolEnumsMiddleware', 'http|tcp'); $this->router->group('/{protocol:protocolEnums}/routes', function (RouteGroup $router) { $router->get('/', RoutesController::class . '::get'); $router->get('/{id}', RoutesController::class . '::get'); $router->post('/{id}', RoutesController::class . '::post'); $router->delete('/{id}', RoutesController::class . '::delete'); }); $this->router->group('/{protocol:protocolEnums}/services', function (RouteGroup $router) { $router->get('/', ServicesController::class . '::get'); $router->get('/{id}', ServicesController::class . '::get'); $router->post('/{id}', ServicesController::class . '::post'); $router->delete('/{id}', ServicesController::class . '::delete'); }); $this->router->group('/{protocol:protocolEnumsMiddleware}/middlewares', function (RouteGroup $router) { $router->get('/', MiddlewaresController::class . '::get'); $router->get('/{id}', MiddlewaresController::class . '::get'); $router->post('/{id}', MiddlewaresController::class . '::post'); $router->delete('/{id}', MiddlewaresController::class . '::delete'); }); $this->router->middleware(new CorsMiddleware()); } /** * 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'], 404 ) ); } 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, 500)); } } } }