diff --git a/database.sql b/database.sql index 87ea52aa5..1d4f335e4 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ --- Friendica 2020.12-rc (Red Hot Poker) --- DB_UPDATE_VERSION 1384 +-- Friendica 2021.03-dev (Red Hot Poker) +-- DB_UPDATE_VERSION 1385 -- ------------------------------------------ @@ -20,6 +20,7 @@ CREATE TABLE IF NOT EXISTS `gserver` ( `poco` varchar(255) NOT NULL DEFAULT '' COMMENT '', `noscrape` varchar(255) NOT NULL DEFAULT '' COMMENT '', `network` char(4) NOT NULL DEFAULT '' COMMENT '', + `protocol` tinyint unsigned COMMENT 'The protocol of the server', `platform` varchar(255) NOT NULL DEFAULT '' COMMENT '', `relay-subscribe` boolean NOT NULL DEFAULT '0' COMMENT 'Has the server subscribed to the relay system', `relay-scope` varchar(10) NOT NULL DEFAULT '' COMMENT 'The scope of messages that the server wants to get', diff --git a/src/Model/GServer.php b/src/Model/GServer.php index e91a946e0..ca939c176 100644 --- a/src/Model/GServer.php +++ b/src/Model/GServer.php @@ -23,6 +23,7 @@ namespace Friendica\Model; use DOMDocument; use DOMXPath; +use Exception; use Friendica\Core\Logger; use Friendica\Core\Protocol; use Friendica\Core\System; @@ -1734,4 +1735,86 @@ class GServer DI::config()->set('poco', 'last_federation_discovery', time()); } + + /** + * Set the protocol for the given server + * + * @param int $gsid Server id + * @param int $protocol Protocol id + * @return void + * @throws Exception + */ + public static function setProtocol(int $gsid, int $protocol) + { + if (empty($gsid)) { + return; + } + + $gserver = DBA::selectFirst('gserver', ['protocol', 'url'], ['id' => $gsid]); + if (!DBA::isResult($gserver)) { + return; + } + + $old = $gserver['protocol']; + + if (!is_null($old)) { + /* + The priority for the protocols is: + 1. ActivityPub + 2. DFRN via Diaspora + 3. Legacy DFRN + 4. Diaspora + 5. OStatus + */ + + // We don't need to change it when nothing is to be changed + if ($old == $protocol) { + return; + } + + // We don't want to mark a server as OStatus when it had been marked with any other protocol before + if ($protocol == Post\DeliveryData::OSTATUS) { + return; + } + + // If the server is marked as ActivityPub then we won't change it to anything different + if ($old == Post\DeliveryData::ACTIVITYPUB) { + return; + } + + // Don't change it to anything lower than DFRN if the new one wasn't ActivityPub + if (($old == Post\DeliveryData::DFRN) && ($protocol != Post\DeliveryData::ACTIVITYPUB)) { + return; + } + + // Don't change it to Diaspora when it is a legacy DFRN server + if (($old == Post\DeliveryData::LEGACY_DFRN) && ($protocol == Post\DeliveryData::DIASPORA)) { + return; + } + } + + Logger::info('Protocol for server', ['protocol' => $protocol, 'old' => $old, 'id' => $gsid, 'url' => $gserver['url']]); + DBA::update('gserver', ['protocol' => $protocol], ['id' => $gsid]); + } + + /** + * Fetch the protocol of the given server + * + * @param int $gsid Server id + * @return int + * @throws Exception + */ + public static function getProtocol(int $gsid) + { + if (empty($gsid)) { + return null; + } + + $gserver = DBA::selectFirst('gserver', ['protocol'], ['id' => $gsid]); + if (DBA::isResult($gserver)) { + return $gserver['protocol']; + } + + return null; + } } diff --git a/src/Model/PushSubscriber.php b/src/Model/PushSubscriber.php index 2a7be3c35..84d45c4c4 100644 --- a/src/Model/PushSubscriber.php +++ b/src/Model/PushSubscriber.php @@ -25,6 +25,7 @@ use Friendica\Core\Logger; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Network; class PushSubscriber { @@ -170,5 +171,13 @@ class PushSubscriber $fields = ['push' => 0, 'next_try' => DBA::NULL_DATETIME, 'last_update' => $last_update]; DBA::update('push_subscriber', $fields, ['id' => $id]); Logger::log('Subscriber ' . $subscriber['callback_url'] . ' for ' . $subscriber['nickname'] . ' is marked as vital', Logger::DEBUG); + + $parts = parse_url($subscriber['callback_url']); + unset($parts['path']); + $server_url = Network::unparseURL($parts); + $gsid = GServer::getID($server_url, true); + if (!empty($gsid)) { + GServer::setProtocol($gsid, Post\DeliveryData::OSTATUS); + } } } diff --git a/src/Worker/APDelivery.php b/src/Worker/APDelivery.php index 0c2c0ca9c..2bf869b4d 100644 --- a/src/Worker/APDelivery.php +++ b/src/Worker/APDelivery.php @@ -24,6 +24,7 @@ namespace Friendica\Worker; use Friendica\Core\Logger; use Friendica\Core\Worker; use Friendica\Model\Contact; +use Friendica\Model\GServer; use Friendica\Model\Item; use Friendica\Model\Post; use Friendica\Protocol\ActivityPub; @@ -82,6 +83,7 @@ class APDelivery // This should never fail and is temporariy (until the move to the "post" structure) $item = Item::selectFirst(['uri-id'], ['id' => $item_id]); $uriid = $item['uri-id'] ?? 0; + $gsid = null; foreach ($receivers as $receiver) { $contact = Contact::getById($receiver); @@ -89,6 +91,8 @@ class APDelivery continue; } + $gsid = $gsid ?: $contact['gsid']; + if ($success) { Contact::unmarkForArchival($contact); } else { @@ -96,6 +100,10 @@ class APDelivery } } + if (!empty($gsid)) { + GServer::setProtocol($gsid, Post\DeliveryData::ACTIVITYPUB); + } + if (!$success && !Worker::defer() && in_array($cmd, [Delivery::POST])) { Post\DeliveryData::incrementQueueFailed($uriid); } elseif ($success && in_array($cmd, [Delivery::POST])) { diff --git a/src/Worker/Delivery.php b/src/Worker/Delivery.php index 600243d50..bd97b2672 100644 --- a/src/Worker/Delivery.php +++ b/src/Worker/Delivery.php @@ -202,6 +202,8 @@ class Delivery return; } + $protocol = Model\GServer::getProtocol($contact['gsid'] ?? 0); + // Transmit via Diaspora if the thread had started as Diaspora post. // Also transmit via Diaspora if this is a direct answer to a Diaspora comment. // This is done since the uri wouldn't match (Diaspora doesn't transmit it) @@ -219,7 +221,7 @@ class Delivery switch ($contact['network']) { case Protocol::DFRN: - self::deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup); + self::deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup, $protocol); break; case Protocol::DIASPORA: @@ -255,18 +257,19 @@ class Delivery /** * Deliver content via DFRN * - * @param string $cmd Command - * @param array $contact Contact record of the receiver - * @param array $owner Owner record of the sender - * @param array $items Item record of the content and the parent - * @param array $target_item Item record of the content - * @param boolean $public_message Is the content public? - * @param boolean $top_level Is it a thread starter? - * @param boolean $followup Is it an answer to a remote post? + * @param string $cmd Command + * @param array $contact Contact record of the receiver + * @param array $owner Owner record of the sender + * @param array $items Item record of the content and the parent + * @param array $target_item Item record of the content + * @param boolean $public_message Is the content public? + * @param boolean $top_level Is it a thread starter? + * @param boolean $followup Is it an answer to a remote post? + * @param int $server_protocol The protocol of the server * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup) + private static function deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup, $server_protocol) { // Transmit Diaspora reshares via Diaspora if the Friendica contact support Diaspora if (Diaspora::isReshare($target_item['body']) && !empty(FContact::getByURL($contact['addr'], false))) { @@ -360,6 +363,8 @@ class Delivery if (in_array($cmd, [Delivery::POST, Delivery::POKE])) { if (($deliver_status >= 200) && ($deliver_status <= 299)) { Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], $protocol); + + Model\GServer::setProtocol($contact['gsid'] ?? 0, $protocol); } else { Model\Post\DeliveryData::incrementQueueFailed($target_item['uri-id']); } @@ -367,7 +372,7 @@ class Delivery return; } - if (($deliver_status < 200) || ($deliver_status > 299)) { + if ((($deliver_status < 200) || ($deliver_status > 299)) && (empty($server_protocol) || ($server_protocol == Model\Post\DeliveryData::LEGACY_DFRN))) { // Transmit via Diaspora if not possible via Friendica self::deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup); return; @@ -375,7 +380,7 @@ class Delivery } elseif ($cmd != self::RELOCATION) { // DFRN payload over Diaspora transport layer $deliver_status = DFRN::transmit($owner, $contact, $atom); - if ($deliver_status < 200) { + if (($deliver_status < 200) && (empty($server_protocol) || ($server_protocol == Model\Post\DeliveryData::LEGACY_DFRN))) { // Legacy DFRN $deliver_status = DFRN::deliver($owner, $contact, $atom); $protocol = Model\Post\DeliveryData::LEGACY_DFRN; @@ -391,6 +396,8 @@ class Delivery // We successfully delivered a message, the contact is alive Model\Contact::unmarkForArchival($contact); + Model\GServer::setProtocol($contact['gsid'] ?? 0, $protocol); + if (in_array($cmd, [Delivery::POST, Delivery::POKE])) { Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], $protocol); } @@ -476,6 +483,8 @@ class Delivery // We successfully delivered a message, the contact is alive Model\Contact::unmarkForArchival($contact); + Model\GServer::setProtocol($contact['gsid'] ?? 0, Model\Post\DeliveryData::DIASPORA); + if (in_array($cmd, [Delivery::POST, Delivery::POKE])) { Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], Model\Post\DeliveryData::DIASPORA); } diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index f03f90bcb..b12ac56b2 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1384); + define('DB_UPDATE_VERSION', 1385); } return [ @@ -75,6 +75,7 @@ return [ "poco" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "noscrape" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""], + "protocol" => ["type" => "tinyint unsigned", "comment" => "The protocol of the server"], "platform" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "relay-subscribe" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Has the server subscribed to the relay system"], "relay-scope" => ["type" => "varchar(10)", "not null" => "1", "default" => "", "comment" => "The scope of messages that the server wants to get"],