]> git.mxchange.org Git - friendica.git/blobdiff - src/App/Router.php
Tests ...
[friendica.git] / src / App / Router.php
index dfe890fb968809fc0fc429aadf48576fd073a088..181f5368d51de5668a9f5d77bb419166330c7ade 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @copyright Copyright (C) 2020, Friendica
+ * @copyright Copyright (C) 2010-2021, the Friendica project
  *
  * @license GNU AGPL version 3 or any later version
  *
@@ -26,10 +26,11 @@ use FastRoute\DataGenerator\GroupCountBased;
 use FastRoute\Dispatcher;
 use FastRoute\RouteCollector;
 use FastRoute\RouteParser\Std;
-use Friendica\Core\Cache\Duration;
-use Friendica\Core\Cache\ICache;
+use Friendica\Core\Cache\Enum\Duration;
+use Friendica\Core\Cache\Capability\ICanCache;
 use Friendica\Core\Hook;
 use Friendica\Core\L10n;
+use Friendica\Core\Lock\Capability\ICanLock;
 use Friendica\Network\HTTPException;
 
 /**
@@ -44,12 +45,20 @@ use Friendica\Network\HTTPException;
  */
 class Router
 {
-       const POST = 'POST';
-       const GET  = 'GET';
+       const DELETE  = 'DELETE';
+       const GET     = 'GET';
+       const PATCH   = 'PATCH';
+       const POST    = 'POST';
+       const PUT     = 'PUT';
+       const OPTIONS = 'OPTIONS';
 
        const ALLOWED_METHODS = [
-               self::POST,
+               self::DELETE,
                self::GET,
+               self::PATCH,
+               self::POST,
+               self::PUT,
+               self::OPTIONS
        ];
 
        /** @var RouteCollector */
@@ -68,9 +77,12 @@ class Router
        /** @var L10n */
        private $l10n;
 
-       /** @var ICache */
+       /** @var ICanCache */
        private $cache;
 
+       /** @var ICanLock */
+       private $lock;
+
        /** @var string */
        private $baseRoutesFilepath;
 
@@ -78,14 +90,15 @@ class Router
         * @param array               $server             The $_SERVER variable
         * @param string              $baseRoutesFilepath The path to a base routes file to leverage cache, can be empty
         * @param L10n                $l10n
-        * @param ICache              $cache
+        * @param ICanCache           $cache
         * @param RouteCollector|null $routeCollector
         */
-       public function __construct(array $server, string $baseRoutesFilepath, L10n $l10n, ICache $cache, RouteCollector $routeCollector = null)
+       public function __construct(array $server, string $baseRoutesFilepath, L10n $l10n, ICanCache $cache, ICanLock $lock, RouteCollector $routeCollector = null)
        {
                $this->baseRoutesFilepath = $baseRoutesFilepath;
                $this->l10n = $l10n;
                $this->cache = $cache;
+               $this->lock = $lock;
 
                $httpMethod = $server['REQUEST_METHOD'] ?? self::GET;
                $this->httpMethod = in_array($httpMethod, self::ALLOWED_METHODS) ? $httpMethod : self::GET;
@@ -93,6 +106,10 @@ class Router
                $this->routeCollector = isset($routeCollector) ?
                        $routeCollector :
                        new RouteCollector(new Std(), new GroupCountBased());
+
+               if ($this->baseRoutesFilepath && !file_exists($this->baseRoutesFilepath)) {
+                       throw new HTTPException\InternalServerErrorException('Routes file path does\'n exist.');
+               }
        }
 
        /**
@@ -249,7 +266,7 @@ class Router
        {
                $dispatchData = [];
 
-               if ($this->baseRoutesFilepath && file_exists($this->baseRoutesFilepath)) {
+               if ($this->baseRoutesFilepath) {
                        $dispatchData = require $this->baseRoutesFilepath;
                        if (!is_array($dispatchData)) {
                                throw new HTTPException\InternalServerErrorException('Invalid base routes file');
@@ -268,20 +285,42 @@ class Router
         * The cached "routerDispatchData" lasts for a day, and must be cleared manually when there
         * is any changes in the enabled addons list.
         *
+        * Additionally, we check for the base routes file last modification time to automatically
+        * trigger re-computing the dispatch data.
+        *
         * @return array|mixed
         * @throws HTTPException\InternalServerErrorException
         */
        private function getCachedDispatchData()
        {
                $routerDispatchData = $this->cache->get('routerDispatchData');
+               $lastRoutesFileModifiedTime = $this->cache->get('lastRoutesFileModifiedTime');
+               $forceRecompute = false;
 
-               if ($routerDispatchData) {
+               if ($this->baseRoutesFilepath) {
+                       $routesFileModifiedTime = filemtime($this->baseRoutesFilepath);
+                       $forceRecompute = $lastRoutesFileModifiedTime != $routesFileModifiedTime;
+               }
+
+               if (!$forceRecompute && $routerDispatchData) {
                        return $routerDispatchData;
                }
 
+               if (!$this->lock->acquire('getCachedDispatchData', 0)) {
+                       // Immediately return uncached data when we can't aquire a lock
+                       return $this->getDispatchData();
+               }
+
                $routerDispatchData = $this->getDispatchData();
 
                $this->cache->set('routerDispatchData', $routerDispatchData, Duration::DAY);
+               if (!empty($routesFileModifiedTime)) {
+                       $this->cache->set('lastRoutesFileModifiedTime', $routesFileModifiedTime, Duration::MONTH);
+               }
+
+               if ($this->lock->isLocked('getCachedDispatchData')) {
+                       $this->lock->release('getCachedDispatchData');
+               }
 
                return $routerDispatchData;
        }