aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCôme Chilliet <come.chilliet@nextcloud.com>2025-05-06 17:19:30 +0200
committerCôme Chilliet <come.chilliet@nextcloud.com>2025-06-05 17:58:46 +0200
commitee3abdd81bc75aa6b373dcc6eec0bdd6aeda0c5a (patch)
tree4c9db7f3902bc003125245b07f980bcaacb611e9
parent5488f7e8b1e2676352edfcd0cf445144b8134db2 (diff)
downloadnextcloud-server-ee3abdd81bc75aa6b373dcc6eec0bdd6aeda0c5a.tar.gz
nextcloud-server-ee3abdd81bc75aa6b373dcc6eec0bdd6aeda0c5a.zip
feat(router): Cache routes in local cache if possible
This is not ideal because serializing the routecollection is not easy. It seems Symfony has its own way of doing things by dumping routes to a PHP file, maybe that would be better, but it would mean pulling a new symfony dependency and maybe refactor our Router. Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
-rw-r--r--lib/private/Route/CachingRouter.php59
1 files changed, 59 insertions, 0 deletions
diff --git a/lib/private/Route/CachingRouter.php b/lib/private/Route/CachingRouter.php
index 7dd26827d3c..9ceb08b61e2 100644
--- a/lib/private/Route/CachingRouter.php
+++ b/lib/private/Route/CachingRouter.php
@@ -15,6 +15,7 @@ use OCP\IConfig;
use OCP\IRequest;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
+use Symfony\Component\Routing\RouteCollection;
class CachingRouter extends Router {
protected ICache $cache;
@@ -54,4 +55,62 @@ class CachingRouter extends Router {
return $url;
}
}
+
+ private function serializeRouteCollection(RouteCollection $collection): array {
+ return array_map(
+ fn (Route $route) => [$route->getPath(), $route->getDefaults(), $route->getRequirements(), $route->getOptions(), $route->getHost(), $route->getSchemes(), $route->getMethods(), $route->getCondition()],
+ $collection->all(),
+ );
+ }
+
+ private function unserializeRouteCollection(array $data): RouteCollection {
+ $collection = new RouteCollection();
+ foreach ($data as $name => $details) {
+ $route = new Route(...$details);
+ $collection->add($name, $route);
+ }
+ return $collection;
+ }
+
+ /**
+ * Loads the routes
+ *
+ * @param null|string $app
+ */
+ public function loadRoutes($app = null): void {
+ $this->eventLogger->start('cacheroute:load:' . $app, 'Loading Routes (using cache) for ' . $app);
+ if (is_string($app)) {
+ $app = $this->appManager->cleanAppId($app);
+ }
+
+ $requestedApp = $app;
+ if ($this->loaded) {
+ $this->eventLogger->end('cacheroute:load:' . $app);
+ return;
+ }
+ if (is_null($app)) {
+ $cachedRoutes = $this->cache->get('root:');
+ if ($cachedRoutes) {
+ $this->root = $this->unserializeRouteCollection($cachedRoutes);
+ $this->loaded = true;
+ $this->eventLogger->end('cacheroute:load:' . $app);
+ return;
+ }
+ } else {
+ if (isset($this->loadedApps[$app])) {
+ $this->eventLogger->end('cacheroute:load:' . $app);
+ return;
+ }
+ $cachedRoutes = $this->cache->get('root:' . $requestedApp);
+ if ($cachedRoutes) {
+ $this->root = $this->unserializeRouteCollection($cachedRoutes);
+ $this->loadedApps[$app] = true;
+ $this->eventLogger->end('cacheroute:load:' . $app);
+ return;
+ }
+ }
+ parent::loadRoutes($app);
+ $this->cache->set('root:' . $requestedApp, $this->serializeRouteCollection($this->root), 3600);
+ $this->eventLogger->end('cacheroute:load:' . $app);
+ }
}