+ /**
+ * Fetch and process parent posts for the given activity
+ *
+ * @param array $activity
+ * @param bool $in_background
+ *
+ * @return string
+ */
+ private static function fetchParent(array $activity, bool $in_background = false): string
+ {
+ if (self::isFetched($activity['reply-to-id'])) {
+ Logger::info('Id is already fetched', ['id' => $activity['reply-to-id']]);
+ return '';
+ }
+
+ self::addActivityId($activity['reply-to-id']);
+
+ if (!DI::config()->get('system', 'fetch_by_worker')) {
+ $in_background = false;
+ }
+
+ $recursion_depth = $activity['recursion-depth'] ?? 0;
+
+ if (!$in_background && ($recursion_depth < DI::config()->get('system', 'max_recursion_depth'))) {
+ Logger::notice('Parent not found. Try to refetch it.', ['parent' => $activity['reply-to-id'], 'recursion-depth' => $recursion_depth]);
+ $result = self::fetchMissingActivity($activity['reply-to-id'], $activity, '', Receiver::COMPLETION_AUTO);
+ if (empty($result) && self::isActivityGone($activity['reply-to-id'])) {
+ Logger::notice('The activity is gone, the queue entry will be deleted', ['parent' => $activity['reply-to-id']]);
+ if (!empty($activity['entry-id'])) {
+ Queue::deleteById($activity['entry-id']);
+ }
+ return '';
+ } elseif (!empty($result)) {
+ $exists = Post::exists(['uri' => [$result, $activity['reply-to-id']]]);
+ if ($exists) {
+ Logger::notice('The activity has been fetched and created.', ['parent' => $result]);
+ return $result;
+ } elseif (DI::config()->get('system', 'fetch_by_worker') || DI::config()->get('system', 'decoupled_receiver')) {
+ Logger::notice('The activity has been fetched and will hopefully be created later.', ['parent' => $result]);
+ } else {
+ Logger::notice('The activity exists but has not been created, the queue entry will be deleted.', ['parent' => $result]);
+ if (!empty($activity['entry-id'])) {
+ Queue::deleteById($activity['entry-id']);
+ }
+ }
+ return '';
+ }
+ if (empty($result) && !DI::config()->get('system', 'fetch_by_worker')) {
+ return '';
+ }
+ } elseif (self::isActivityGone($activity['reply-to-id'])) {
+ Logger::notice('The activity is gone. We will not spawn a worker. The queue entry will be deleted', ['parent' => $activity['reply-to-id']]);
+ if ($in_background) {
+ // fetching in background is done for all activities where we have got the conversation
+ // There we only delete the single activity and not the whole thread since we can store the
+ // other posts in the thread even with missing posts.
+ Queue::remove($activity);
+ } elseif (!empty($activity['entry-id'])) {
+ Queue::deleteById($activity['entry-id']);
+ }
+ return '';
+ } elseif ($in_background) {
+ Logger::notice('Fetching is done in the background.', ['parent' => $activity['reply-to-id']]);
+ } else {
+ Logger::notice('Recursion level is too high.', ['parent' => $activity['reply-to-id'], 'recursion-depth' => $recursion_depth]);
+ }
+
+ if (!Fetch::hasWorker($activity['reply-to-id'])) {
+ Logger::notice('Fetching is done by worker.', ['parent' => $activity['reply-to-id'], 'recursion-depth' => $recursion_depth]);
+ Fetch::add($activity['reply-to-id']);
+ $activity['recursion-depth'] = 0;
+ $wid = Worker::add(Worker::PRIORITY_HIGH, 'FetchMissingActivity', $activity['reply-to-id'], $activity, '', Receiver::COMPLETION_AUTO);
+ Fetch::setWorkerId($activity['reply-to-id'], $wid);
+ } else {
+ Logger::debug('Activity will already be fetched via a worker.', ['url' => $activity['reply-to-id']]);
+ }
+
+ return '';
+ }
+