X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FRelay.php;h=f50b73b7d707de5c6a20bd3d7023d7582770700c;hb=3b19ccc3519b929b9ac6d79aca6b8b424597c9c2;hp=3184528cc56213f4627f4f6d8a992e80e33bdb1e;hpb=427881c437f1d782540ac510fe97a1a2e50d752b;p=friendica.git diff --git a/src/Protocol/Relay.php b/src/Protocol/Relay.php index 3184528cc5..f50b73b7d7 100644 --- a/src/Protocol/Relay.php +++ b/src/Protocol/Relay.php @@ -1,6 +1,6 @@ get('system', 'relay_subscribe', false); - if ($subscribe) { - $scope = $config->get('system', 'relay_scope', SR_SCOPE_ALL); - } else { - $scope = SR_SCOPE_NONE; - } + $scope = $config->get('system', 'relay_scope'); - if ($scope == SR_SCOPE_NONE) { + if ($scope == self::SCOPE_NONE) { Logger::info('Server does not accept relay posts - rejected', ['network' => $network, 'url' => $url]); return false; } + if (Contact::isBlocked($authorid)) { + Logger::info('Author is blocked - rejected', ['author' => $authorid, 'network' => $network, 'url' => $url]); + return false; + } + + if (Contact::isHidden($authorid)) { + Logger::info('Author is hidden - rejected', ['author' => $authorid, 'network' => $network, 'url' => $url]); + return false; + } + $systemTags = []; $userTags = []; $denyTags = []; - if ($scope == SR_SCOPE_TAGS) { + if ($scope == self::SCOPE_TAGS) { $server_tags = $config->get('system', 'relay_server_tags'); $tagitems = explode(',', mb_strtolower($server_tags)); - foreach ($tagitems AS $tag) { + foreach ($tagitems as $tag) { $systemTags[] = trim($tag, '# '); } @@ -75,7 +96,7 @@ class Relay $deny_tags = $config->get('system', 'relay_deny_tags'); $tagitems = explode(',', mb_strtolower($deny_tags)); - foreach ($tagitems AS $tag) { + foreach ($tagitems as $tag) { $tag = trim($tag, '# '); $denyTags[] = $tag; } @@ -104,7 +125,7 @@ class Relay } } - if ($scope == SR_SCOPE_ALL) { + if ($scope == self::SCOPE_ALL) { Logger::info('Server accept all posts - accepted', ['network' => $network, 'url' => $url]); return true; } @@ -112,4 +133,212 @@ class Relay Logger::info('No matching hashtags found - rejected', ['network' => $network, 'url' => $url]); return false; } + + /** + * Update or insert a relay contact + * + * @param array $gserver Global server record + * @param array $fields Optional network specific fields + * @throws \Exception + */ + public static function updateContact(array $gserver, array $fields = []) + { + if (in_array($gserver['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN])) { + $system = APContact::getByURL($gserver['url'] . '/friendica'); + if (!empty($system['sharedinbox'])) { + Logger::info('Sucessfully probed for relay contact', ['server' => $gserver['url']]); + $id = Contact::updateFromProbeByURL($system['url']); + Logger::info('Updated relay contact', ['server' => $gserver['url'], 'id' => $id]); + return; + } + } + + $condition = ['uid' => 0, 'gsid' => $gserver['id'], 'contact-type' => Contact::TYPE_RELAY]; + $old = DBA::selectFirst('contact', [], $condition); + if (!DBA::isResult($old)) { + $condition = ['uid' => 0, 'nurl' => Strings::normaliseLink($gserver['url'])]; + $old = DBA::selectFirst('contact', [], $condition); + if (DBA::isResult($old)) { + $fields['gsid'] = $gserver['id']; + $fields['contact-type'] = Contact::TYPE_RELAY; + Logger::info('Assigning missing data for relay contact', ['server' => $gserver['url'], 'id' => $old['id']]); + } + } elseif (empty($fields)) { + Logger::info('No content to update, quitting', ['server' => $gserver['url']]); + return; + } + + if (DBA::isResult($old)) { + $fields['updated'] = DateTimeFormat::utcNow(); + + Logger::info('Update relay contact', ['server' => $gserver['url'], 'id' => $old['id'], 'fields' => $fields]); + Contact::update($fields, ['id' => $old['id']], $old); + } else { + $default = ['created' => DateTimeFormat::utcNow(), + 'name' => 'relay', 'nick' => 'relay', 'url' => $gserver['url'], + 'nurl' => Strings::normaliseLink($gserver['url']), + 'network' => Protocol::DIASPORA, 'uid' => 0, + 'batch' => $gserver['url'] . '/receive/public', + 'rel' => Contact::FOLLOWER, 'blocked' => false, + 'pending' => false, 'writable' => true, + 'gsid' => $gserver['id'], + 'baseurl' => $gserver['url'], 'contact-type' => Contact::TYPE_RELAY]; + + $fields = array_merge($default, $fields); + + Logger::info('Create relay contact', ['server' => $gserver['url'], 'fields' => $fields]); + Contact::insert($fields); + } + } + + /** + * Mark the relay contact of the given contact for archival + * This is called whenever there is a communication issue with the server. + * It avoids sending stuff to servers who don't exist anymore. + * The relay contact is a technical contact entry that exists once per server. + * + * @param array $contact of the relay contact + */ + public static function markForArchival(array $contact) + { + if (!empty($contact['contact-type']) && ($contact['contact-type'] == Contact::TYPE_RELAY)) { + // This is already the relay contact, we don't need to fetch it + $relay_contact = $contact; + } elseif (empty($contact['baseurl'])) { + if (!empty($contact['batch'])) { + $condition = ['uid' => 0, 'network' => Protocol::FEDERATED, 'batch' => $contact['batch'], 'contact-type' => Contact::TYPE_RELAY]; + $relay_contact = DBA::selectFirst('contact', [], $condition); + } else { + return; + } + } else { + $gserver = ['id' => $contact['gsid'] ?: GServer::getID($contact['baseurl'], true), + 'url' => $contact['baseurl'], 'network' => $contact['network']]; + $relay_contact = self::getContact($gserver, []); + } + + if (!empty($relay_contact)) { + Logger::info('Relay contact will be marked for archival', ['id' => $relay_contact['id'], 'url' => $relay_contact['url']]); + Contact::markForArchival($relay_contact); + } + } + + /** + * Return a list of servers that we serve via the direct relay + * + * @param integer $item_id id of the item that is sent + * @param array $contacts Previously fetched contacts + * @param array $networks Networks of the relay servers + * + * @return array of relay servers + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + public static function getDirectRelayList(int $item_id) + { + $serverlist = []; + + if (!DI::config()->get("system", "relay_directly", false)) { + return []; + } + + // We distribute our stuff based on the parent to ensure that the thread will be complete + $parent = Post::selectFirst(['uri-id'], ['id' => $item_id]); + if (!DBA::isResult($parent)) { + return []; + } + + // Servers that want to get all content + $servers = DBA::select('gserver', ['id', 'url', 'network'], ['relay-subscribe' => true, 'relay-scope' => 'all']); + while ($server = DBA::fetch($servers)) { + $serverlist[$server['id']] = $server; + } + DBA::close($servers); + + // All tags of the current post + $tags = DBA::select('tag-view', ['name'], ['uri-id' => $parent['uri-id'], 'type' => Tag::HASHTAG]); + $taglist = []; + while ($tag = DBA::fetch($tags)) { + $taglist[] = $tag['name']; + } + DBA::close($tags); + + // All servers who wants content with this tag + $tagserverlist = []; + if (!empty($taglist)) { + $tagserver = DBA::select('gserver-tag', ['gserver-id'], ['tag' => $taglist]); + while ($server = DBA::fetch($tagserver)) { + $tagserverlist[] = $server['gserver-id']; + } + DBA::close($tagserver); + } + + // All adresses with the given id + if (!empty($tagserverlist)) { + $servers = DBA::select('gserver', ['id', 'url', 'network'], ['relay-subscribe' => true, 'relay-scope' => 'tags', 'id' => $tagserverlist]); + while ($server = DBA::fetch($servers)) { + $serverlist[$server['id']] = $server; + } + DBA::close($servers); + } + + $contacts = []; + + // Now we are collecting all relay contacts + foreach ($serverlist as $gserver) { + // We don't send messages to ourselves + if (Strings::compareLink($gserver['url'], DI::baseUrl())) { + continue; + } + $contact = self::getContact($gserver); + if (empty($contact)) { + continue; + } + } + + return $contacts; + } + + /** + * Return a list of relay servers + * + * @param array $fields Field list + * @return array + * @throws Exception + */ + public static function getList($fields = []):array + { + return DBA::selectToArray('apcontact', $fields, + ["`type` = ? AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` = ?)", 'Application', 0, Contact::FRIEND]); + } + + /** + * Return a contact for a given server address or creates a dummy entry + * + * @param array $gserver Global server record + * @param array $fields Fieldlist + * @return array with the contact + * @throws \Exception + */ + private static function getContact(array $gserver, array $fields = ['batch', 'id', 'url', 'name', 'network', 'protocol', 'archive', 'blocked']) + { + // Fetch the relay contact + $condition = ['uid' => 0, 'gsid' => $gserver['id'], 'contact-type' => Contact::TYPE_RELAY]; + $contact = DBA::selectFirst('contact', $fields, $condition); + if (DBA::isResult($contact)) { + if ($contact['archive'] || $contact['blocked']) { + return false; + } + return $contact; + } else { + self::updateContact($gserver); + + $contact = DBA::selectFirst('contact', $fields, $condition); + if (DBA::isResult($contact)) { + return $contact; + } + } + + // It should never happen that we arrive here + return []; + } }