Issue 10306: Improve local delivery
This commit is contained in:
parent
91b474ea6d
commit
785f8124ed
8 changed files with 131 additions and 99 deletions
|
@ -1941,7 +1941,7 @@ class Contact
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Contact::isLocal($ret['url'])) {
|
if (self::isLocal($ret['url'])) {
|
||||||
Logger::info('Local contacts are not updated here.');
|
Logger::info('Local contacts are not updated here.');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1018,6 +1018,30 @@ class Item
|
||||||
|
|
||||||
if (empty($item['event-id'])) {
|
if (empty($item['event-id'])) {
|
||||||
unset($item['event-id']);
|
unset($item['event-id']);
|
||||||
|
|
||||||
|
$ev = Event::fromBBCode($item['body']);
|
||||||
|
if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) {
|
||||||
|
Logger::info('Event found.');
|
||||||
|
$ev['cid'] = $item['contact-id'];
|
||||||
|
$ev['uid'] = $item['uid'];
|
||||||
|
$ev['uri'] = $item['uri'];
|
||||||
|
$ev['edited'] = $item['edited'];
|
||||||
|
$ev['private'] = $item['private'];
|
||||||
|
$ev['guid'] = $item['guid'];
|
||||||
|
$ev['plink'] = $item['plink'];
|
||||||
|
$ev['network'] = $item['network'];
|
||||||
|
$ev['protocol'] = $item['protocol'];
|
||||||
|
$ev['direction'] = $item['direction'];
|
||||||
|
$ev['source'] = $item['source'];
|
||||||
|
|
||||||
|
$event = DBA::selectFirst('event', ['id'], ['uri' => $item['uri'], 'uid' => $item['uid']]);
|
||||||
|
if (DBA::isResult($event)) {
|
||||||
|
$ev['id'] = $event['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$item['event-id'] = Event::store($ev);
|
||||||
|
Logger::info('Event was stored', ['id' => $item['event-id']]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($item['causer-id'])) {
|
if (empty($item['causer-id'])) {
|
||||||
|
@ -1325,16 +1349,23 @@ class Item
|
||||||
* @param integer $uri_id URI-ID of the given item
|
* @param integer $uri_id URI-ID of the given item
|
||||||
* @param integer $uid The user that will receive the item entry
|
* @param integer $uid The user that will receive the item entry
|
||||||
* @param array $fields Additional fields to be stored
|
* @param array $fields Additional fields to be stored
|
||||||
|
* @param integer $source_uid User id of the source post
|
||||||
* @return integer stored item id
|
* @return integer stored item id
|
||||||
*/
|
*/
|
||||||
public static function storeForUserByUriId(int $uri_id, int $uid, array $fields = [])
|
public static function storeForUserByUriId(int $uri_id, int $uid, array $fields = [], int $source_uid = 0)
|
||||||
{
|
{
|
||||||
$item = Post::selectFirst(self::ITEM_FIELDLIST, ['uri-id' => $uri_id, 'uid' => 0]);
|
if ($uid == $source_uid) {
|
||||||
if (!DBA::isResult($item)) {
|
Logger::warning('target UID must be be equal to the source UID', ['uri-id' => $uri_id, 'uid' => $uid]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($item['private'] == self::PRIVATE) || !in_array($item['network'], Protocol::FEDERATED)) {
|
$item = Post::selectFirst(self::ITEM_FIELDLIST, ['uri-id' => $uri_id, 'uid' => $source_uid]);
|
||||||
|
if (!DBA::isResult($item)) {
|
||||||
|
Logger::warning('Item could not be fetched', ['uri-id' => $uri_id, 'uid' => $source_uid]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($source_uid == 0) && (($item['private'] == self::PRIVATE) || !in_array($item['network'], Protocol::FEDERATED))) {
|
||||||
Logger::notice('Item is private or not from a federated network. It will not be stored for the user.', ['uri-id' => $uri_id, 'uid' => $uid, 'private' => $item['private'], 'network' => $item['network']]);
|
Logger::notice('Item is private or not from a federated network. It will not be stored for the user.', ['uri-id' => $uri_id, 'uid' => $uid, 'private' => $item['private'], 'network' => $item['network']]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1343,8 +1374,24 @@ class Item
|
||||||
|
|
||||||
$item = array_merge($item, $fields);
|
$item = array_merge($item, $fields);
|
||||||
|
|
||||||
|
$is_reshare = ($item['gravity'] == GRAVITY_ACTIVITY) && ($item['verb'] == Activity::ANNOUNCE);
|
||||||
|
|
||||||
|
if ((($item['gravity'] == GRAVITY_PARENT) || $is_reshare) &&
|
||||||
|
DI::pConfig()->get($uid, 'system', 'accept_only_sharer') &&
|
||||||
|
!Contact::isSharingByURL($item['author-link'], $uid) &&
|
||||||
|
!Contact::isSharingByURL($item['owner-link'], $uid)) {
|
||||||
|
Logger::info('Contact is not a follower, thread will not be stored', ['author' => $item['author-link'], 'uid' => $uid]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((($item['gravity'] == GRAVITY_COMMENT) || $is_reshare) && !Post::exists(['uri-id' => $item['thr-parent-id'], 'uid' => $uid])) {
|
||||||
|
// Only do an auto complete with the source uid "0" to prevent privavy problems
|
||||||
|
$result = self::storeForUserByUriId($item['thr-parent-id'], $uid);
|
||||||
|
Logger::info('Fetched thread parent', ['uri-id' => $item['thr-parent-id'], 'uid' => $uid, 'result' => $result]);
|
||||||
|
}
|
||||||
|
|
||||||
$stored = self::storeForUser($item, $uid);
|
$stored = self::storeForUser($item, $uid);
|
||||||
Logger::info('Public item stored for user', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'stored' => $stored]);
|
Logger::info('Item stored for user', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'source-uid' => $source_uid, 'stored' => $stored]);
|
||||||
return $stored;
|
return $stored;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1364,11 +1411,21 @@ class Item
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($item['id']);
|
unset($item['id']);
|
||||||
unset($item['parent']);
|
|
||||||
unset($item['mention']);
|
unset($item['mention']);
|
||||||
unset($item['starred']);
|
unset($item['starred']);
|
||||||
unset($item['unseen']);
|
unset($item['unseen']);
|
||||||
unset($item['psid']);
|
unset($item['psid']);
|
||||||
|
unset($item['pinned']);
|
||||||
|
unset($item['ignored']);
|
||||||
|
unset($item['pubmail']);
|
||||||
|
unset($item['forum_mode']);
|
||||||
|
|
||||||
|
//unset($item['post-reason']);
|
||||||
|
//unset($item['protocol']);
|
||||||
|
unset($item['event-id']);
|
||||||
|
unset($item['hidden']);
|
||||||
|
unset($item['notification-type']);
|
||||||
|
//unset($item['resource-id']);
|
||||||
|
|
||||||
$item['uid'] = $uid;
|
$item['uid'] = $uid;
|
||||||
$item['origin'] = 0;
|
$item['origin'] = 0;
|
||||||
|
@ -1394,8 +1451,6 @@ class Item
|
||||||
$item['contact-id'] = $self['id'];
|
$item['contact-id'] = $self['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @todo Handling of "event-id"
|
|
||||||
|
|
||||||
$notify = false;
|
$notify = false;
|
||||||
if ($item['gravity'] == GRAVITY_PARENT) {
|
if ($item['gravity'] == GRAVITY_PARENT) {
|
||||||
$contact = DBA::selectFirst('contact', [], ['id' => $item['contact-id'], 'self' => false]);
|
$contact = DBA::selectFirst('contact', [], ['id' => $item['contact-id'], 'self' => false]);
|
||||||
|
@ -1407,9 +1462,9 @@ class Item
|
||||||
$distributed = self::insert($item, $notify, true);
|
$distributed = self::insert($item, $notify, true);
|
||||||
|
|
||||||
if (!$distributed) {
|
if (!$distributed) {
|
||||||
Logger::info("Distributed public item wasn't stored", ['uri-id' => $item['uri-id'], 'user' => $uid]);
|
Logger::info("Distributed item wasn't stored", ['uri-id' => $item['uri-id'], 'user' => $uid]);
|
||||||
} else {
|
} else {
|
||||||
Logger::info('Distributed public item was stored', ['uri-id' => $item['uri-id'], 'user' => $uid, 'stored' => $distributed]);
|
Logger::info('Distributed item was stored', ['uri-id' => $item['uri-id'], 'user' => $uid, 'stored' => $distributed]);
|
||||||
}
|
}
|
||||||
return $distributed;
|
return $distributed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,15 +164,16 @@ class Post
|
||||||
* @param array $fields
|
* @param array $fields
|
||||||
* @param array $condition
|
* @param array $condition
|
||||||
* @param array $params
|
* @param array $params
|
||||||
|
* @param bool $user_mode true = post-user-view, false = post-view
|
||||||
* @return bool|array
|
* @return bool|array
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
* @see DBA::select
|
* @see DBA::select
|
||||||
*/
|
*/
|
||||||
public static function selectFirst(array $fields = [], array $condition = [], $params = [])
|
public static function selectFirst(array $fields = [], array $condition = [], $params = [], bool $user_mode = true)
|
||||||
{
|
{
|
||||||
$params['limit'] = 1;
|
$params['limit'] = 1;
|
||||||
|
|
||||||
$result = self::select($fields, $condition, $params);
|
$result = self::select($fields, $condition, $params, $user_mode);
|
||||||
|
|
||||||
if (is_bool($result)) {
|
if (is_bool($result)) {
|
||||||
return $result;
|
return $result;
|
||||||
|
|
|
@ -313,7 +313,7 @@ class User
|
||||||
public static function getIdForURL(string $url)
|
public static function getIdForURL(string $url)
|
||||||
{
|
{
|
||||||
// Avoid any database requests when the hostname isn't even part of the url.
|
// Avoid any database requests when the hostname isn't even part of the url.
|
||||||
if (!strpos($url, DI::baseUrl()->getHostname())) {
|
if (!Contact::isLocal($url)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -748,10 +748,6 @@ class Transmitter
|
||||||
|
|
||||||
$contacts = DBA::select('contact', ['id', 'url', 'network', 'protocol', 'gsid'], $condition);
|
$contacts = DBA::select('contact', ['id', 'url', 'network', 'protocol', 'gsid'], $condition);
|
||||||
while ($contact = DBA::fetch($contacts)) {
|
while ($contact = DBA::fetch($contacts)) {
|
||||||
if (Contact::isLocal($contact['url'])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!self::isAPContact($contact, $networks)) {
|
if (!self::isAPContact($contact, $networks)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -766,7 +762,7 @@ class Transmitter
|
||||||
|
|
||||||
$profile = APContact::getByURL($contact['url'], false);
|
$profile = APContact::getByURL($contact['url'], false);
|
||||||
if (!empty($profile)) {
|
if (!empty($profile)) {
|
||||||
if (empty($profile['sharedinbox']) || $personal) {
|
if (empty($profile['sharedinbox']) || $personal || Contact::isLocal($contact['url'])) {
|
||||||
$target = $profile['inbox'];
|
$target = $profile['inbox'];
|
||||||
} else {
|
} else {
|
||||||
$target = $profile['sharedinbox'];
|
$target = $profile['sharedinbox'];
|
||||||
|
@ -829,15 +825,11 @@ class Transmitter
|
||||||
if ($item_profile && ($receiver == $item_profile['followers']) && ($uid == $profile_uid)) {
|
if ($item_profile && ($receiver == $item_profile['followers']) && ($uid == $profile_uid)) {
|
||||||
$inboxes = array_merge($inboxes, self::fetchTargetInboxesforUser($uid, $personal, self::isAPPost($last_id)));
|
$inboxes = array_merge($inboxes, self::fetchTargetInboxesforUser($uid, $personal, self::isAPPost($last_id)));
|
||||||
} else {
|
} else {
|
||||||
if (Contact::isLocal($receiver)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$profile = APContact::getByURL($receiver, false);
|
$profile = APContact::getByURL($receiver, false);
|
||||||
if (!empty($profile)) {
|
if (!empty($profile)) {
|
||||||
$contact = Contact::getByURLForUser($receiver, $uid, false, ['id']);
|
$contact = Contact::getByURLForUser($receiver, $uid, false, ['id']);
|
||||||
|
|
||||||
if (empty($profile['sharedinbox']) || $personal || $blindcopy) {
|
if (empty($profile['sharedinbox']) || $personal || $blindcopy || Contact::isLocal($receiver)) {
|
||||||
$target = $profile['inbox'];
|
$target = $profile['inbox'];
|
||||||
} else {
|
} else {
|
||||||
$target = $profile['sharedinbox'];
|
$target = $profile['sharedinbox'];
|
||||||
|
|
|
@ -548,4 +548,15 @@ class Network
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given URL is a local link
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isLocalLink(string $url)
|
||||||
|
{
|
||||||
|
return (strpos(Strings::normaliseLink($url), Strings::normaliseLink(DI::baseUrl())) !== false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,11 @@ use Friendica\Protocol\DFRN;
|
||||||
use Friendica\Protocol\Diaspora;
|
use Friendica\Protocol\Diaspora;
|
||||||
use Friendica\Protocol\Email;
|
use Friendica\Protocol\Email;
|
||||||
use Friendica\Protocol\Activity;
|
use Friendica\Protocol\Activity;
|
||||||
use Friendica\Util\Strings;
|
|
||||||
use Friendica\Util\Network;
|
use Friendica\Util\Network;
|
||||||
use Friendica\Core\Worker;
|
use Friendica\Core\Worker;
|
||||||
use Friendica\Model\Conversation;
|
use Friendica\Model\Conversation;
|
||||||
use Friendica\Model\FContact;
|
use Friendica\Model\FContact;
|
||||||
use Friendica\Model\Item;
|
use Friendica\Model\Item;
|
||||||
use Friendica\Model\Post;
|
|
||||||
use Friendica\Protocol\Relay;
|
use Friendica\Protocol\Relay;
|
||||||
|
|
||||||
class Delivery
|
class Delivery
|
||||||
|
@ -216,11 +214,6 @@ class Delivery
|
||||||
$contact['network'] = Protocol::DIASPORA;
|
$contact['network'] = Protocol::DIASPORA;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that local contacts are delivered locally
|
|
||||||
if (Model\Contact::isLocal($contact['url'])) {
|
|
||||||
$contact['network'] = Protocol::DFRN;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::notice('Delivering', ['cmd' => $cmd, 'uri-id' => $post_uriid, 'followup' => $followup, 'network' => $contact['network']]);
|
Logger::notice('Delivering', ['cmd' => $cmd, 'uri-id' => $post_uriid, 'followup' => $followup, 'network' => $contact['network']]);
|
||||||
|
|
||||||
switch ($contact['network']) {
|
switch ($contact['network']) {
|
||||||
|
@ -316,40 +309,6 @@ class Delivery
|
||||||
|
|
||||||
Logger::debug('Notifier entry: ' . $contact["url"] . ' ' . (($target_item['guid'] ?? '') ?: $target_item['id']) . ' entry: ' . $atom);
|
Logger::debug('Notifier entry: ' . $contact["url"] . ' ' . (($target_item['guid'] ?? '') ?: $target_item['id']) . ' entry: ' . $atom);
|
||||||
|
|
||||||
// perform local delivery if we are on the same site
|
|
||||||
if (Model\Contact::isLocal($contact['url'])) {
|
|
||||||
$condition = ['nurl' => Strings::normaliseLink($contact['url']), 'self' => true];
|
|
||||||
$target_self = DBA::selectFirst('contact', ['uid'], $condition);
|
|
||||||
if (!DBA::isResult($target_self)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$target_uid = $target_self['uid'];
|
|
||||||
|
|
||||||
// Check if the user has got this contact
|
|
||||||
$cid = Model\Contact::getIdForURL($owner['url'], $target_uid);
|
|
||||||
if (!$cid) {
|
|
||||||
// Otherwise there should be a public contact
|
|
||||||
$cid = Model\Contact::getIdForURL($owner['url']);
|
|
||||||
if (!$cid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$target_importer = DFRN::getImporter($cid, $target_uid);
|
|
||||||
if (empty($target_importer)) {
|
|
||||||
// This should never happen
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFRN::import($atom, $target_importer, Conversation::PARCEL_LOCAL_DFRN, Conversation::PUSH);
|
|
||||||
|
|
||||||
if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
|
|
||||||
Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], Model\Post\DeliveryData::DFRN);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$protocol = Model\Post\DeliveryData::DFRN;
|
$protocol = Model\Post\DeliveryData::DFRN;
|
||||||
|
|
||||||
// We don't have a relationship with contacts on a public post.
|
// We don't have a relationship with contacts on a public post.
|
||||||
|
|
|
@ -41,6 +41,7 @@ use Friendica\Protocol\Diaspora;
|
||||||
use Friendica\Protocol\OStatus;
|
use Friendica\Protocol\OStatus;
|
||||||
use Friendica\Protocol\Relay;
|
use Friendica\Protocol\Relay;
|
||||||
use Friendica\Protocol\Salmon;
|
use Friendica\Protocol\Salmon;
|
||||||
|
use Friendica\Util\Network;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The notifier is typically called with:
|
* The notifier is typically called with:
|
||||||
|
@ -514,9 +515,12 @@ class Notifier
|
||||||
$delivery_queue_count = 0;
|
$delivery_queue_count = 0;
|
||||||
|
|
||||||
foreach ($contacts as $contact) {
|
foreach ($contacts as $contact) {
|
||||||
// Ensure that local contacts are delivered via DFRN
|
// Direct delivery of local contacts
|
||||||
if (Contact::isLocal($contact['url'])) {
|
if ($target_uid = User::getIdForURL($contact['url'])) {
|
||||||
$contact['network'] = Protocol::DFRN;
|
Logger::info('Direct delivery', ['uri-id' => $target_item['uri-id'], 'target' => $target_uid]);
|
||||||
|
$fields = ['protocol' => Conversation::PARCEL_LOCAL_DFRN, 'direction' => Conversation::PUSH];
|
||||||
|
Item::storeForUserByUriId($target_item['uri-id'], $target_uid, $fields, $target_item['uid']);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletions are always sent via DFRN as well.
|
// Deletions are always sent via DFRN as well.
|
||||||
|
@ -775,6 +779,16 @@ class Notifier
|
||||||
foreach ($inboxes as $inbox => $receivers) {
|
foreach ($inboxes as $inbox => $receivers) {
|
||||||
$contacts = array_merge($contacts, $receivers);
|
$contacts = array_merge($contacts, $receivers);
|
||||||
|
|
||||||
|
if ((count($receivers) == 1) && Network::isLocalLink($inbox)) {
|
||||||
|
$contact = Contact::getById($receivers[0], ['url']);
|
||||||
|
if ($target_uid = User::getIdForURL($contact['url'])) {
|
||||||
|
$fields = ['protocol' => Conversation::PARCEL_LOCAL_DFRN, 'direction' => Conversation::PUSH];
|
||||||
|
Item::storeForUserByUriId($target_item['uri-id'], $target_uid, $fields, $target_item['uid']);
|
||||||
|
Logger::info('Delivered locally', ['cmd' => $cmd, 'id' => $target_item['id'], 'inbox' => $inbox]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Logger::info('Delivery via ActivityPub', ['cmd' => $cmd, 'id' => $target_item['id'], 'inbox' => $inbox]);
|
Logger::info('Delivery via ActivityPub', ['cmd' => $cmd, 'id' => $target_item['id'], 'inbox' => $inbox]);
|
||||||
|
|
||||||
if (Worker::add(['priority' => $priority, 'created' => $created, 'dont_fork' => true],
|
if (Worker::add(['priority' => $priority, 'created' => $created, 'dont_fork' => true],
|
||||||
|
|
Loading…
Reference in a new issue