From 96ecf3e568a24afa81977a1e6ca62088572bc712 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Sun, 17 Mar 2024 18:05:11 +0100 Subject: [PATCH] Implement a cache for the router --- .../files/lib/action/ApiAction.class.php | 19 +++++----- .../builder/ApiEndpointCacheBuilder.class.php | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 wcfsetup/install/files/lib/system/cache/builder/ApiEndpointCacheBuilder.class.php diff --git a/wcfsetup/install/files/lib/action/ApiAction.class.php b/wcfsetup/install/files/lib/action/ApiAction.class.php index 3cb7348507..a31a1e223b 100644 --- a/wcfsetup/install/files/lib/action/ApiAction.class.php +++ b/wcfsetup/install/files/lib/action/ApiAction.class.php @@ -3,14 +3,15 @@ namespace wcf\action; use CuyZ\Valinor\Mapper\MappingError; +use FastRoute\ConfigureRoutes; use FastRoute\Dispatcher\Result\MethodNotAllowed; use FastRoute\Dispatcher\Result\NotMatched; -use FastRoute\RouteCollector; use Laminas\Diactoros\Response\JsonResponse; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Server\RequestHandlerInterface; use wcf\http\attribute\AllowHttpMethod; +use wcf\system\cache\builder\ApiEndpointCacheBuilder; use wcf\system\endpoint\event\ControllerCollecting; use wcf\system\endpoint\IController; use wcf\system\endpoint\RequestFailure; @@ -20,7 +21,7 @@ use wcf\system\exception\PermissionDeniedException; use wcf\system\exception\UserInputException; use wcf\system\request\RouteHandler; -use function FastRoute\simpleDispatcher; +use function FastRoute\cachedDispatcher; /** * Resolves and forwards API requests to the responsible controllers, exposing @@ -51,13 +52,11 @@ final class ApiAction implements RequestHandlerInterface return $this->toErrorResponse(RequestFailure::UnknownEndpoint, 'missing_endpoint'); } - // TODO: This is currently very inefficient and should be cached in some - // way, maybe even use a combined cache for both? - $event = new ControllerCollecting(); - EventHandler::getInstance()->fire($event); + $dispatcher = cachedDispatcher( + static function (ConfigureRoutes $r) { + $event = new ControllerCollecting(); + EventHandler::getInstance()->fire($event); - $dispatcher = simpleDispatcher( - static function (RouteCollector $r) use ($event) { foreach ($event->getControllers() as $controller) { $reflectionClass = new \ReflectionClass($controller); $attribute = current($reflectionClass->getAttributes(RequestType::class, \ReflectionAttribute::IS_INSTANCEOF)); @@ -69,8 +68,8 @@ final class ApiAction implements RequestHandlerInterface } }, [ - // TODO: debug only - 'cacheDisabled' => true, + 'cacheKey' => self::class, + 'cacheDriver' => ApiEndpointCacheBuilder::getInstance(), ] ); diff --git a/wcfsetup/install/files/lib/system/cache/builder/ApiEndpointCacheBuilder.class.php b/wcfsetup/install/files/lib/system/cache/builder/ApiEndpointCacheBuilder.class.php new file mode 100644 index 0000000000..2ebc631cd1 --- /dev/null +++ b/wcfsetup/install/files/lib/system/cache/builder/ApiEndpointCacheBuilder.class.php @@ -0,0 +1,38 @@ + + * @since 6.1 + */ +final class ApiEndpointCacheBuilder extends AbstractCacheBuilder implements Cache +{ + private \Closure $loader; + + #[\Override] + public function get(string $key, callable $loader): array + { + $this->loader = \Closure::fromCallable($loader); + + return $this->getData(['key' => $key]); + } + + #[\Override] + public function rebuild(array $parameters) + { + if (!isset($this->loader)) { + throw new \RuntimeException('You may not access the API endpoint cache builder directly.'); + } + + $callable = $this->loader; + + return $callable(); + } +} -- 2.20.1