]> git.mxchange.org Git - friendica.git/blobdiff - src/Model/GServer.php
Merge pull request #12589 from MrPetovan/bug/warnings
[friendica.git] / src / Model / GServer.php
index f68851af6826b945cdc25f392a7381a5636c7db8..1878befa9f2282440c44a3b0ad19351555cb047c 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @copyright Copyright (C) 2010-2022, the Friendica project
+ * @copyright Copyright (C) 2010-2023, the Friendica project
  *
  * @license GNU AGPL version 3 or any later version
  *
@@ -165,33 +165,97 @@ class GServer
        }
 
        /**
-        * Checks if the given server is reachable
+        * Checks if the given server array is unreachable for a long time now
         *
-        * @param string  $profile URL of the given profile
-        * @param string  $server  URL of the given server (If empty, taken from profile)
-        * @param string  $network Network value that is used, when detection failed
-        * @param boolean $force   Force an update.
+        * @param integer $gsid
+        * @return boolean
+        */
+       private static function isDefunct(array $gserver): bool
+       {
+               return ($gserver['failed'] || in_array($gserver['network'], Protocol::FEDERATED)) &&
+                       ($gserver['last_contact'] >= $gserver['created']) &&
+                       ($gserver['last_contact'] < $gserver['last_failure']) &&
+                       ($gserver['last_contact'] < DateTimeFormat::utc('now - 90 days'));
+       }
+
+       /**
+        * Checks if the given server id is unreachable for a long time now
         *
-        * @return boolean 'true' if server seems vital
+        * @param integer $gsid
+        * @return boolean
         */
-       public static function reachable(string $profile, string $server = '', string $network = '', bool $force = false): bool
+       public static function isDefunctById(int $gsid): bool
        {
-               if ($server == '') {
-                       $contact = Contact::getByURL($profile, null, ['baseurl', 'network']);
-                       if (!empty($contact['baseurl'])) {
-                               $server = $contact['baseurl'];
-                       } elseif ($contact['network'] == Protocol::DIASPORA) {
-                               $parts = parse_url($profile);
-                               unset($parts['path']);
-                               $server =  (string)Uri::fromParts($parts);
+               $gserver = DBA::selectFirst('gserver', ['url', 'next_contact', 'last_contact', 'last_failure', 'created', 'failed', 'network'], ['id' => $gsid]);
+               if (empty($gserver)) {
+                       return false;
+               } else {
+                       if (strtotime($gserver['next_contact']) < time()) {
+                               Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $gserver['url'], false);
                        }
+                       return self::isDefunct($gserver);
                }
+       }
 
-               if ($server == '') {
+       /**
+        * Checks if the given server id is reachable
+        *
+        * @param integer $gsid
+        * @return boolean
+        */
+       public static function isReachableById(int $gsid): bool
+       {
+               $gserver = DBA::selectFirst('gserver', ['url', 'next_contact', 'failed', 'network'], ['id' => $gsid]);
+               if (empty($gserver)) {
                        return true;
+               } else {
+                       if (strtotime($gserver['next_contact']) < time()) {
+                               Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $gserver['url'], false);
+                       }
+                       return !$gserver['failed'] && in_array($gserver['network'], Protocol::FEDERATED);
+               }
+       }
+
+       /**
+        * Checks if the given server is reachable
+        *
+        * @param array $contact Contact that should be checked
+        *
+        * @return boolean 'true' if server seems vital
+        */
+       public static function reachable(array $contact): bool
+       {
+               if (!empty($contact['gsid'])) {
+                       $gsid = $contact['gsid'];
+               } elseif (!empty($contact['baseurl'])) {
+                       $server = $contact['baseurl'];
+               } elseif ($contact['network'] == Protocol::DIASPORA) {
+                       $parts = parse_url($contact['url']);
+                       unset($parts['path']);
+                       $server = (string)Uri::fromParts($parts);
+               } else {
+                       return true;
+               }
+
+               if (!empty($gsid)) {
+                       $condition = ['id' => $gsid];
+               } else {
+                       $condition = ['nurl' => Strings::normaliseLink($server)];
                }
 
-               return self::check($server, $network, $force);
+               $gserver = DBA::selectFirst('gserver', ['url', 'next_contact', 'failed', 'network'], $condition);
+               if (empty($gserver)) {
+                       $reachable = true;
+               } else {
+                       $reachable = !$gserver['failed'] && in_array($gserver['network'], Protocol::FEDERATED);
+                       $server    = $gserver['url'];
+               }
+
+               if (!empty($server) && (empty($gserver) || strtotime($gserver['next_contact']) < time())) {
+                       Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $server, false);
+               }
+
+               return $reachable;
        }
 
        /**
@@ -293,12 +357,53 @@ class GServer
                return self::detect($server_url, $network, $only_nodeinfo);
        }
 
+       /**
+        * Reset failed server status by gserver id
+        *
+        * @param int    $gsid
+        * @param string $network
+        */
+       public static function setReachableById(int $gsid, string $network)
+       {
+               $gserver = DBA::selectFirst('gserver', ['url', 'failed', 'next_contact', 'network'], ['id' => $gsid]);
+               if (DBA::isResult($gserver) && $gserver['failed']) {
+                       $fields = ['failed' => false, 'last_contact' => DateTimeFormat::utcNow()];
+                       if (!empty($network) && !in_array($gserver['network'], Protocol::FEDERATED)) {
+                               $fields['network'] = $network;
+                       }
+                       self::update($fields, ['id' => $gsid]);
+                       Logger::info('Reset failed status for server', ['url' => $gserver['url']]);
+
+                       if (strtotime($gserver['next_contact']) < time()) {
+                               Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $gserver['url'], false);
+                       }
+               }
+       }
+
+       /**
+        * Set failed server status by gserver id
+        *
+        * @param int $gsid
+        */
+       public static function setFailureById(int $gsid)
+       {
+               $gserver = DBA::selectFirst('gserver', ['url', 'failed', 'next_contact'], ['id' => $gsid]);
+               if (DBA::isResult($gserver) && !$gserver['failed']) {
+                       self::update(['failed' => true, 'last_failure' => DateTimeFormat::utcNow()], ['id' => $gsid]);
+                       Logger::info('Set failed status for server', ['url' => $gserver['url']]);
+
+                       if (strtotime($gserver['next_contact']) < time()) {
+                               Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $gserver['url'], false);
+                       }
+               }
+       }
+
        /**
         * Set failed server status
         *
         * @param string $url
         */
-       public static function setFailure(string $url)
+       public static function setFailureByUrl(string $url)
        {
                $gserver = DBA::selectFirst('gserver', [], ['nurl' => Strings::normaliseLink($url)]);
                if (DBA::isResult($gserver)) {
@@ -307,6 +412,9 @@ class GServer
                        'next_contact' => $next_update, 'network' => Protocol::PHANTOM, 'detection-method' => null],
                        ['nurl' => Strings::normaliseLink($url)]);
                        Logger::info('Set failed status for existing server', ['url' => $url]);
+                       if (self::isDefunct($gserver)) {
+                               self::archiveContacts($gserver['id']);
+                       }
                        return;
                }
                self::insert(['url' => $url, 'nurl' => Strings::normaliseLink($url),
@@ -315,6 +423,18 @@ class GServer
                Logger::info('Set failed status for new server', ['url' => $url]);
        }
 
+       /**
+        * Archive server related contacts and inboxes
+        *
+        * @param integer $gsid
+        * @return void
+        */
+       private static function archiveContacts(int $gsid)
+       {
+               Contact::update(['archive' => true], ['gsid' => $gsid]);
+               DBA::update('inbox-status', ['archive' => true], ['gsid' => $gsid]);
+       }
+
        /**
         * Remove unwanted content from the given URL
         *
@@ -359,7 +479,7 @@ class GServer
 
                // If the URL missmatches, then we mark the old entry as failure
                if (!Strings::compareLink($url, $original_url)) {
-                       self::setFailure($original_url);
+                       self::setFailureByUrl($original_url);
                        if (!self::getID($url, true)) {
                                self::detect($url, $network, $only_nodeinfo);
                        }
@@ -368,7 +488,7 @@ class GServer
 
                $valid_url = Network::isUrlValid($url);
                if (!$valid_url) {
-                       self::setFailure($url);
+                       self::setFailureByUrl($url);
                        return false;
                } else {
                        $valid_url = rtrim($valid_url, '/');
@@ -380,7 +500,7 @@ class GServer
                        if (((parse_url($url, PHP_URL_HOST) != parse_url($valid_url, PHP_URL_HOST)) && (parse_url($url, PHP_URL_PATH) == parse_url($valid_url, PHP_URL_PATH))) ||
                                (((parse_url($url, PHP_URL_HOST) != parse_url($valid_url, PHP_URL_HOST)) || (parse_url($url, PHP_URL_PATH) != parse_url($valid_url, PHP_URL_PATH))) && empty(parse_url($valid_url, PHP_URL_PATH)))) {
                                Logger::debug('Found redirect. Mark old entry as failure', ['old' => $url, 'new' => $valid_url]);
-                               self::setFailure($url);
+                               self::setFailureByUrl($url);
                                if (!self::getID($valid_url, true)) {
                                        self::detect($valid_url, $network, $only_nodeinfo);
                                }
@@ -394,7 +514,7 @@ class GServer
                                unset($parts['path']);
                                $valid_url = (string)Uri::fromParts($parts);
 
-                               self::setFailure($url);
+                               self::setFailureByUrl($url);
                                if (!self::getID($valid_url, true)) {
                                        self::detect($valid_url, $network, $only_nodeinfo);
                                }
@@ -414,7 +534,7 @@ class GServer
                // When a nodeinfo is present, we don't need to dig further
                $curlResult = DI::httpClient()->get($url . '/.well-known/x-nodeinfo2', HttpClientAccept::JSON);
                if ($curlResult->isTimeout()) {
-                       self::setFailure($url);
+                       self::setFailureByUrl($url);
                        return false;
                }
 
@@ -426,7 +546,7 @@ class GServer
 
                if ($only_nodeinfo && empty($serverdata)) {
                        Logger::info('Invalid nodeinfo in nodeinfo-mode, server is marked as failure', ['url' => $url]);
-                       self::setFailure($url);
+                       self::setFailureByUrl($url);
                        return false;
                } elseif (empty($serverdata)) {
                        $serverdata = ['detection-method' => self::DETECT_MANUAL, 'network' => Protocol::PHANTOM, 'platform' => '', 'version' => '', 'site_name' => '', 'info' => ''];
@@ -465,7 +585,7 @@ class GServer
                                }
 
                                if (!$curlResult->isSuccess() || empty($curlResult->getBody())) {
-                                       self::setFailure($url);
+                                       self::setFailureByUrl($url);
                                        return false;
                                }
 
@@ -534,7 +654,7 @@ class GServer
 
                // Most servers aren't installed in a subdirectory, so we declare this entry as failed
                if (($serverdata['network'] == Protocol::PHANTOM) && !empty(parse_url($url, PHP_URL_PATH)) && in_array($serverdata['detection-method'], [self::DETECT_MANUAL])) {
-                       self::setFailure($url);
+                       self::setFailureByUrl($url);
                        return false;
                }
 
@@ -550,6 +670,11 @@ class GServer
                        $serverdata = self::detectNetworkViaContacts($url, $serverdata);
                }
 
+               if (($serverdata['network'] == Protocol::PHANTOM) && in_array($serverdata['detection-method'], [self::DETECT_MANUAL, self::DETECT_BODY])) {
+                       self::setFailureByUrl($url);
+                       return false;
+               }
+
                // Detect the directory type
                $serverdata['directory-type'] = self::DT_NONE;
 
@@ -2133,7 +2258,7 @@ class GServer
         */
        private static function discoverFederation()
        {
-               $last = DI::config()->get('poco', 'last_federation_discovery');
+               $last = DI::keyValue()->get('poco_last_federation_discovery');
 
                if ($last) {
                        $next = $last + (24 * 60 * 60);
@@ -2177,7 +2302,7 @@ class GServer
                        }
                }
 
-               DI::config()->set('poco', 'last_federation_discovery', time());
+               DI::keyValue()->set('poco_last_federation_discovery', time());
        }
 
        /**