Archive inboxes after 5 days of delivery failures
authorMichael <heluecht@pirati.ca>
Mon, 25 Mar 2019 21:51:32 +0000 (21:51 +0000)
committerMichael <heluecht@pirati.ca>
Mon, 25 Mar 2019 21:51:32 +0000 (21:51 +0000)
config/dbstructure.config.php
database.sql
src/Protocol/ActivityPub/Transmitter.php
src/Util/HTTPSignature.php

index f03132a..b2f451b 100644 (file)
@@ -34,7 +34,7 @@
 use Friendica\Database\DBA;
 
 if (!defined('DB_UPDATE_VERSION')) {
-       define('DB_UPDATE_VERSION', 1304);
+       define('DB_UPDATE_VERSION', 1305);
 }
 
 return [
@@ -529,6 +529,20 @@ return [
                        "hook_file_function" => ["UNIQUE", "hook", "file", "function"],
                ]
        ],
+       "inbox-status" => [
+               "comment" => "Status of ActivityPub inboxes",
+               "fields" => [
+                       "url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "URL of the inbox"],
+                       "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Creation date of this entry"],
+                       "success" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last successful delivery"],
+                       "failure" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last failed delivery"],
+                       "previous" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Previous delivery date"],
+                       "archive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Is the inbox archived?"]
+               ],
+               "indexes" => [
+                       "PRIMARY" => ["url"]
+               ]
+       ],
        "intro" => [
                "comment" => "",
                "fields" => [
index 10a428f..5b415b6 100644 (file)
@@ -1,6 +1,6 @@
 -- ------------------------------------------
--- Friendica 2019.03-dev (The Tazmans Flax-lily)
--- DB_UPDATE_VERSION 1300
+-- Friendica 2019.03 (Dalmatian Bellflower)
+-- DB_UPDATE_VERSION 1305
 -- ------------------------------------------
 
 
@@ -470,6 +470,19 @@ CREATE TABLE IF NOT EXISTS `hook` (
         UNIQUE INDEX `hook_file_function` (`hook`,`file`,`function`)
 ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='addon hook registry';
 
+--
+-- TABLE inbox-status
+--
+CREATE TABLE IF NOT EXISTS `inbox-status` (
+       `url` varbinary(255) NOT NULL COMMENT 'URL of the inbox',
+       `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation date of this entry',
+       `success` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last successful delivery',
+       `failure` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last failed delivery',
+       `previous` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Previous delivery date',
+       `archive` boolean NOT NULL DEFAULT '0' COMMENT 'Is the inbox archived?',
+        PRIMARY KEY(`url`)
+) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Status of ActivityPub inboxes';
+
 --
 -- TABLE intro
 --
@@ -879,7 +892,7 @@ CREATE TABLE IF NOT EXISTS `photo` (
        `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups',
        `backend-class` tinytext COMMENT 'Storage backend class',
        `backend-ref` text COMMENT 'Storage backend data reference',
-       `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'edited timestamp',
+       `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
         PRIMARY KEY(`id`),
         INDEX `contactid` (`contact-id`),
         INDEX `uid_contactid` (`uid`,`contact-id`),
@@ -1270,13 +1283,12 @@ CREATE TABLE IF NOT EXISTS `workerqueue` (
        `retrial` tinyint NOT NULL DEFAULT 0 COMMENT 'Retrial counter',
        `done` boolean NOT NULL DEFAULT '0' COMMENT 'Marked 1 when the task was done - will be deleted later',
         PRIMARY KEY(`id`),
-        INDEX `pid` (`pid`),
-        INDEX `parameter` (`parameter`(64)),
-        INDEX `priority_created_next_try` (`priority`,`created`,`next_try`),
-        INDEX `done_priority_executed_next_try` (`done`,`priority`,`executed`,`next_try`),
-        INDEX `done_executed_next_try` (`done`,`executed`,`next_try`),
+        INDEX `done_parameter` (`done`,`parameter`(64)),
+        INDEX `done_executed` (`done`,`executed`),
+        INDEX `done_priority_created` (`done`,`priority`,`created`),
         INDEX `done_priority_next_try` (`done`,`priority`,`next_try`),
-        INDEX `done_next_try` (`done`,`next_try`)
+        INDEX `done_pid_next_try` (`done`,`pid`,`next_try`),
+        INDEX `done_pid_priority_created` (`done`,`pid`,`priority`,`created`)
 ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Background tasks queue entries';
 
 --
index ce23e6d..eb1da09 100644 (file)
@@ -465,6 +465,18 @@ class Transmitter
                return $receivers;
        }
 
+       /**
+        * Check if an inbox is archived
+        *
+        * @param string $url Inbox url
+        *
+        * @return boolean "true" if inbox is archived
+        */
+       private static function archivedInbox($url)
+       {
+               return DBA::exists('inbox-status', ['url' => $url, 'archive' => true]);
+       }
+
        /**
         * Fetches a list of inboxes of followers of a given user
         *
@@ -506,7 +518,9 @@ class Transmitter
                                } else {
                                        $target = $profile['sharedinbox'];
                                }
-                               $inboxes[$target] = $target;
+                               if (!self::archivedInbox($target)) {
+                                       $inboxes[$target] = $target;
+                               }
                        }
                }
                DBA::close($contacts);
@@ -563,7 +577,9 @@ class Transmitter
                                                } else {
                                                        $target = $profile['sharedinbox'];
                                                }
-                                               $inboxes[$target] = $target;
+                                               if (!self::archivedInbox($target)) {
+                                                       $inboxes[$target] = $target;
+                                               }
                                        }
                                }
                        }
index d5e1732..e002d59 100644 (file)
@@ -5,6 +5,7 @@
  */
 namespace Friendica\Util;
 
+use Friendica\Database\DBA;
 use Friendica\Core\Config;
 use Friendica\Core\Logger;
 use Friendica\Model\User;
@@ -314,7 +315,66 @@ class HTTPSignature
 
                Logger::log('Transmit to ' . $target . ' returned ' . $return_code, Logger::DEBUG);
 
-               return ($return_code >= 200) && ($return_code <= 299);
+               $success = ($return_code >= 200) && ($return_code <= 299);
+
+               self::setInboxStatus($target, $success);
+
+               return $success;
+       }
+
+       /**
+        * @brief Set the delivery status for a given inbox
+        *
+        * @param string  $url     The URL of the inbox
+        * @param boolean $success Transmission status
+        */
+       static private function setInboxStatus($url, $success)
+       {
+               $now = DateTimeFormat::utcNow();
+
+               $status = DBA::selectFirst('inbox-status', [], ['url' => $url]);
+               if (!DBA::isResult($status)) {
+                       DBA::insert('inbox-status', ['url' => $url, 'created' => $now]);
+                       $status = DBA::selectFirst('inbox-status', [], ['url' => $url]);
+               }
+
+               if ($success) {
+                       $fields = ['success' => $now];
+               } else {
+                       $fields = ['failure' => $now];
+               }
+
+               if ($status['failure'] > DBA::NULL_DATETIME) {
+                       $new_previous_stamp = strtotime($status['failure']);
+                       $old_previous_stamp = strtotime($status['previous']);
+
+                       // Only set "previous" with at least one day difference.
+                       // We use this to assure to not accidentally archive too soon.
+                       if (($new_previous_stamp - $old_previous_stamp) >= 86400) {
+                               $fields['previous'] = $status['failure'];
+                       }
+               }
+
+               if (!$success) {
+                       if ($status['success'] <= DBA::NULL_DATETIME) {
+                               $stamp1 = strtotime($status['created']);
+                       } else {
+                               $stamp1 = strtotime($status['success']);
+                       }
+
+                       $stamp2 = strtotime($now);
+                       $previous_stamp = strtotime($status['previous']);
+
+                       // Archive the inbox when there had been failures for five days.
+                       // Additionally ensure that at least one previous attempt has to be in between.
+                       if ((($stamp2 - $stamp1) >= 86400 * 5) && ($previous_stamp > $stamp1)) {
+                               $fields['archive'] = true;
+                       }
+               } else {
+                       $fields['archive'] = false;
+               }
+
+               DBA::update('inbox-status', $fields, ['url' => $url]);
        }
 
        /**