diff --git a/src/Model/GServer.php b/src/Model/GServer.php index 14fe2011b..10c1a25e5 100644 --- a/src/Model/GServer.php +++ b/src/Model/GServer.php @@ -44,6 +44,7 @@ use Friendica\Util\Network; use Friendica\Util\Strings; use Friendica\Util\XML; use Friendica\Network\HTTPException; +use Friendica\Worker\UpdateGServer; use GuzzleHttp\Psr7\Uri; use Psr\Http\Message\UriInterface; @@ -100,11 +101,11 @@ class GServer */ public static function add(string $url, bool $only_nodeinfo = false) { - if (self::getID($url, false)) { + if (self::getID($url)) { return; } - Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $url, $only_nodeinfo); + UpdateGServer::add(Worker::PRIORITY_LOW, $url, $only_nodeinfo); } /** @@ -165,6 +166,60 @@ class GServer return DI::dba()->toArray($stmt); } + /** + * Checks if the given server array is unreachable for a long time now + * + * @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 + * + * @param integer $gsid + * @return boolean + */ + public static function isDefunctById(int $gsid): bool + { + $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()) { + UpdateGServer::add(Worker::PRIORITY_LOW, $gserver['url']); + } + + return self::isDefunct($gserver); + } + } + + /** + * 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()) { + UpdateGServer::add(Worker::PRIORITY_LOW, $gserver['url']); + } + + return !$gserver['failed'] && in_array($gserver['network'], Protocol::FEDERATED); + } + } + /** * Checks if the given server is reachable * @@ -201,7 +256,7 @@ class GServer } if (!empty($server) && (empty($gserver) || strtotime($gserver['next_contact']) < time())) { - Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $server, false); + UpdateGServer::add(Worker::PRIORITY_LOW, $server); } return $reachable; @@ -306,6 +361,47 @@ 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()) { + UpdateGServer::add(Worker::PRIORITY_LOW, $gserver['url']); + } + } + } + + /** + * 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()) { + UpdateGServer::add(Worker::PRIORITY_LOW, $gserver['url']); + } + } + } + /** * Set failed server status * diff --git a/src/Worker/UpdateGServer.php b/src/Worker/UpdateGServer.php index d180f34c4..a17fca81c 100644 --- a/src/Worker/UpdateGServer.php +++ b/src/Worker/UpdateGServer.php @@ -22,9 +22,14 @@ namespace Friendica\Worker; use Friendica\Core\Logger; +use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\GServer; +use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Util\Network; use Friendica\Util\Strings; +use GuzzleHttp\Psr7\Uri; +use Psr\Http\Message\UriInterface; class UpdateGServer { @@ -34,8 +39,9 @@ class UpdateGServer * @param string $server_url Server URL * @param boolean $only_nodeinfo Only use nodeinfo for server detection * @return void + * @throws \Exception */ - public static function execute(string $server_url, bool $only_nodeinfo = false) + public static function execute(string $server_url, bool $only_nodeinfo) { if (empty($server_url)) { return; @@ -47,6 +53,11 @@ class UpdateGServer return; } + // Silently dropping the worker task if the server domain is blocked + if (Network::isUrlBlocked($filtered)) { + return; + } + if (($filtered != $server_url) && DBA::exists('gserver', ['nurl' => Strings::normaliseLink($server_url)])) { GServer::setFailure($server_url); return; @@ -61,4 +72,23 @@ class UpdateGServer $ret = GServer::check($filtered, '', true, $only_nodeinfo); Logger::info('Updated gserver', ['url' => $filtered, 'result' => $ret]); } + + /** + * @param array|int $run_parameters Priority constant or array of options described in Worker::add + * @param string $serverUrl + * @param bool $onlyNodeInfo Only use NodeInfo for server detection + * @return int + * @throws InternalServerErrorException + */ + public static function add($run_parameters, string $serverUrl, bool $onlyNodeInfo = false): int + { + // Dropping the worker task if the server domain is blocked + if (Network::isUrlBlocked($serverUrl)) { + return 0; + } + + // We have to convert the Uri back to string because worker parameters are saved in JSON format which + // doesn't allow for structured objects. + return Worker::add($run_parameters, 'UpdateGServer', $serverUrl, $onlyNodeInfo); + } } diff --git a/src/Worker/UpdateGServers.php b/src/Worker/UpdateGServers.php index 25a2db16e..fca3bccb7 100644 --- a/src/Worker/UpdateGServers.php +++ b/src/Worker/UpdateGServers.php @@ -27,6 +27,7 @@ use Friendica\Database\DBA; use Friendica\DI; use Friendica\Util\DateTimeFormat; use Friendica\Util\Strings; +use GuzzleHttp\Psr7\Uri; class UpdateGServers { @@ -63,12 +64,12 @@ class UpdateGServers // There are duplicated "url" but not "nurl". So we check both addresses instead of just overwriting them, // since that would mean loosing data. if (!empty($gserver['url'])) { - if (Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $gserver['url'])) { + if (UpdateGServer::add(Worker::PRIORITY_LOW, $gserver['url'])) { $count++; } } if (!empty($gserver['nurl']) && ($gserver['nurl'] != Strings::normaliseLink($gserver['url']))) { - if (Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $gserver['nurl'])) { + if (UpdateGServer::add(Worker::PRIORITY_LOW, $gserver['nurl'])) { $count++; } }