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>
This commit is contained in:
Côme Chilliet 2025-05-06 17:19:30 +02:00
parent 5488f7e8b1
commit ee3abdd81b
No known key found for this signature in database
GPG key ID: A3E2F658B28C760A

View file

@ -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);
}
}