Merge pull request #265 from pfefferle/optimize-publish

optimize publishing
This commit is contained in:
Matthias Pfefferle 2023-04-20 15:04:34 +02:00 committed by GitHub
commit cf426ab8ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 115 additions and 73 deletions

View file

@ -13,7 +13,10 @@ class Activity_Dispatcher {
* Initialize the class, registering WordPress hooks. * Initialize the class, registering WordPress hooks.
*/ */
public static function init() { public static function init() {
\add_action( 'activitypub_send_post_activity', array( '\Activitypub\Activity_Dispatcher', 'send_post_activity' ) ); // legacy
\add_action( 'activitypub_send_post_activity', array( '\Activitypub\Activity_Dispatcher', 'send_create_activity' ) );
\add_action( 'activitypub_send_create_activity', array( '\Activitypub\Activity_Dispatcher', 'send_create_activity' ) );
\add_action( 'activitypub_send_update_activity', array( '\Activitypub\Activity_Dispatcher', 'send_update_activity' ) ); \add_action( 'activitypub_send_update_activity', array( '\Activitypub\Activity_Dispatcher', 'send_update_activity' ) );
\add_action( 'activitypub_send_delete_activity', array( '\Activitypub\Activity_Dispatcher', 'send_delete_activity' ) ); \add_action( 'activitypub_send_delete_activity', array( '\Activitypub\Activity_Dispatcher', 'send_delete_activity' ) );
} }
@ -23,38 +26,8 @@ class Activity_Dispatcher {
* *
* @param \Activitypub\Model\Post $activitypub_post * @param \Activitypub\Model\Post $activitypub_post
*/ */
public static function send_post_activity( Model\Post $activitypub_post ) { public static function send_create_activity( Model\Post $activitypub_post ) {
// get latest version of post self::send_activity( $activitypub_post, 'Create' );
$user_id = $activitypub_post->get_post_author();
$activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL );
$activitypub_activity->from_post( $activitypub_post );
$inboxes = \Activitypub\get_follower_inboxes( $user_id );
$followers_url = \get_rest_url( null, '/activitypub/1.0/users/' . intval( $user_id ) . '/followers' );
foreach ( $activitypub_activity->get_cc() as $cc ) {
if ( $cc === $followers_url ) {
continue;
}
$inbox = \Activitypub\get_inbox_by_actor( $cc );
if ( ! $inbox || \is_wp_error( $inbox ) ) {
continue;
}
// init array if empty
if ( ! isset( $inboxes[ $inbox ] ) ) {
$inboxes[ $inbox ] = array();
}
$inboxes[ $inbox ][] = $cc;
}
foreach ( $inboxes as $inbox => $to ) {
$to = array_values( array_unique( $to ) );
$activitypub_activity->set_to( $to );
$activity = $activitypub_activity->to_json();
\Activitypub\safe_remote_post( $inbox, $activity, $user_id );
}
} }
/** /**
@ -62,19 +35,8 @@ class Activity_Dispatcher {
* *
* @param \Activitypub\Model\Post $activitypub_post * @param \Activitypub\Model\Post $activitypub_post
*/ */
public static function send_update_activity( $activitypub_post ) { public static function send_update_activity( Model\Post $activitypub_post ) {
// get latest version of post self::send_activity( $activitypub_post, 'Update' );
$user_id = $activitypub_post->get_post_author();
$activitypub_activity = new \Activitypub\Model\Activity( 'Update', \Activitypub\Model\Activity::TYPE_FULL );
$activitypub_activity->from_post( $activitypub_post );
foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) {
$activitypub_activity->set_to( $to );
$activity = $activitypub_activity->to_json(); // phpcs:ignore
\Activitypub\safe_remote_post( $inbox, $activity, $user_id );
}
} }
/** /**
@ -82,16 +44,30 @@ class Activity_Dispatcher {
* *
* @param \Activitypub\Model\Post $activitypub_post * @param \Activitypub\Model\Post $activitypub_post
*/ */
public static function send_delete_activity( $activitypub_post ) { public static function send_delete_activity( Model\Post $activitypub_post ) {
self::send_activity( $activitypub_post, 'Delete' );
}
/**
* Undocumented function
*
* @param [type] $activitypub_post
* @param [type] $activity_type
* @return void
*/
public static function send_activity( Model\Post $activitypub_post, $activity_type ) {
// get latest version of post // get latest version of post
$user_id = $activitypub_post->get_post_author(); $user_id = $activitypub_post->get_post_author();
$activitypub_activity = new \Activitypub\Model\Activity( 'Delete', \Activitypub\Model\Activity::TYPE_FULL ); $activitypub_activity = new \Activitypub\Model\Activity( $activity_type );
$activitypub_activity->from_post( $activitypub_post ); $activitypub_activity->from_post( $activitypub_post );
foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) { $inboxes = \Activitypub\get_follower_inboxes( $user_id, $activitypub_activity->get_cc() );
$activitypub_activity->set_to( $to );
$activity = $activitypub_activity->to_json(); // phpcs:ignore foreach ( $inboxes as $inbox => $cc ) {
$cc = array_values( array_unique( $cc ) );
$activitypub_activity->add_cc( $cc );
$activity = $activitypub_activity->to_json();
\Activitypub\safe_remote_post( $inbox, $activity, $user_id ); \Activitypub\safe_remote_post( $inbox, $activity, $user_id );
} }

View file

@ -117,7 +117,7 @@ class Activitypub {
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = new \Activitypub\Model\Post( $post );
if ( 'publish' === $new_status && 'publish' !== $old_status ) { if ( 'publish' === $new_status && 'publish' !== $old_status ) {
\wp_schedule_single_event( \time(), 'activitypub_send_post_activity', array( $activitypub_post ) ); \wp_schedule_single_event( \time(), 'activitypub_send_create_activity', array( $activitypub_post ) );
} elseif ( 'publish' === $new_status ) { } elseif ( 'publish' === $new_status ) {
\wp_schedule_single_event( \time(), 'activitypub_send_update_activity', array( $activitypub_post ) ); \wp_schedule_single_event( \time(), 'activitypub_send_update_activity', array( $activitypub_post ) );
} elseif ( 'trash' === $new_status ) { } elseif ( 'trash' === $new_status ) {

View file

@ -219,8 +219,11 @@ function get_publickey_by_actor( $actor, $key_id ) {
return new \WP_Error( 'activitypub_no_public_key', \__( 'No "Public-Key" found', 'activitypub' ), $metadata ); return new \WP_Error( 'activitypub_no_public_key', \__( 'No "Public-Key" found', 'activitypub' ), $metadata );
} }
function get_follower_inboxes( $user_id ) { function get_follower_inboxes( $user_id, $cc = array() ) {
$followers = \Activitypub\Peer\Followers::get_followers( $user_id ); $followers = \Activitypub\Peer\Followers::get_followers( $user_id );
$followers = array_merge( $followers, $cc );
$followers = array_unique( $followers );
$inboxes = array(); $inboxes = array();
foreach ( $followers as $follower ) { foreach ( $followers as $follower ) {

View file

@ -9,24 +9,38 @@ namespace Activitypub\Model;
* @see https://www.w3.org/TR/activitypub/ * @see https://www.w3.org/TR/activitypub/
*/ */
class Activity { class Activity {
private $context = array( 'https://www.w3.org/ns/activitystreams' ); private $context = array(
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
array(
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'PropertyValue' => 'schema:PropertyValue',
'schema' => 'http://schema.org#',
'pt' => 'https://joinpeertube.org/ns#',
'toot' => 'http://joinmastodon.org/ns#',
'value' => 'schema:value',
'Hashtag' => 'as:Hashtag',
'featured' => array(
'@id' => 'toot:featured',
'@type' => '@id',
),
'featuredTags' => array(
'@id' => 'toot:featuredTags',
'@type' => '@id',
),
),
);
private $published = ''; private $published = '';
private $id = ''; private $id = '';
private $type = 'Create'; private $type = 'Create';
private $actor = ''; private $actor = '';
private $to = array( 'https://www.w3.org/ns/activitystreams#Public' ); private $to = array( 'https://www.w3.org/ns/activitystreams#Public' );
private $cc = array( 'https://www.w3.org/ns/activitystreams#Public' ); private $cc = array();
private $object = null; private $object = null;
const TYPE_SIMPLE = 'simple'; public function __construct( $type = 'Create', $context = true ) {
const TYPE_FULL = 'full'; if ( true !== $context ) {
const TYPE_NONE = 'none';
public function __construct( $type = 'Create', $context = self::TYPE_SIMPLE ) {
if ( 'none' === $context ) {
$this->context = null; $this->context = null;
} elseif ( 'full' === $context ) {
$this->context = \Activitypub\get_context();
} }
$this->type = \ucfirst( $type ); $this->type = \ucfirst( $type );
@ -43,6 +57,20 @@ class Activity {
if ( \strncasecmp( $method, 'set', 3 ) === 0 ) { if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
$this->$var = $params[0]; $this->$var = $params[0];
} }
if ( \strncasecmp( $method, 'add', 3 ) === 0 ) {
if ( ! is_array( $this->$var ) ) {
$this->$var = $params[0];
}
if ( is_array( $params[0] ) ) {
$this->$var = array_merge( $this->$var, $params[0] );
} else {
array_push( $this->$var, $params[0] );
}
$this->$var = array_unique( $this->$var );
}
} }
public function from_post( Post $post ) { public function from_post( Post $post ) {
@ -51,7 +79,8 @@ class Activity {
if ( isset( $object['published'] ) ) { if ( isset( $object['published'] ) ) {
$this->published = $object['published']; $this->published = $object['published'];
} }
$this->cc = array( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $post->get_post_author() ) . '/followers' ) );
$this->add_to( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $post->get_post_author() ) . '/followers' ) );
if ( isset( $this->object['attributedTo'] ) ) { if ( isset( $this->object['attributedTo'] ) ) {
$this->actor = $this->object['attributedTo']; $this->actor = $this->object['attributedTo'];
@ -59,7 +88,7 @@ class Activity {
foreach ( $post->get_tags() as $tag ) { foreach ( $post->get_tags() as $tag ) {
if ( 'Mention' === $tag['type'] ) { if ( 'Mention' === $tag['type'] ) {
$this->cc[] = $tag['href']; $this->add_cc( $tag['href'] );
} }
} }

View file

@ -104,6 +104,24 @@ class Post {
'cite' => array(), 'cite' => array(),
); );
/**
* List of audience
*
* Also used for visibility
*
* @var array
*/
private $to = array( 'https://www.w3.org/ns/activitystreams#Public' );
/**
* List of audience
*
* Also used for visibility
*
* @var array
*/
private $cc = array();
/** /**
* Constructor * Constructor
* *
@ -111,6 +129,7 @@ class Post {
*/ */
public function __construct( $post ) { public function __construct( $post ) {
$this->post = \get_post( $post ); $this->post = \get_post( $post );
$this->add_to( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $this->get_post_author() ) . '/followers' ) );
} }
/** /**
@ -134,6 +153,20 @@ class Post {
if ( \strncasecmp( $method, 'set', 3 ) === 0 ) { if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
$this->$var = $params[0]; $this->$var = $params[0];
} }
if ( \strncasecmp( $method, 'add', 3 ) === 0 ) {
if ( ! is_array( $this->$var ) ) {
$this->$var = $params[0];
}
if ( is_array( $params[0] ) ) {
$this->$var = array_merge( $this->$var, $params[0] );
} else {
array_push( $this->$var, $params[0] );
}
$this->$var = array_unique( $this->$var );
}
} }
/** /**
@ -155,8 +188,8 @@ class Post {
'contentMap' => array( 'contentMap' => array(
\strstr( \get_locale(), '_', true ) => $this->get_content(), \strstr( \get_locale(), '_', true ) => $this->get_content(),
), ),
'to' => array( 'https://www.w3.org/ns/activitystreams#Public' ), 'to' => $this->get_to(),
'cc' => array( 'https://www.w3.org/ns/activitystreams#Public' ), 'cc' => $this->get_cc(),
'attachment' => $this->get_attachments(), 'attachment' => $this->get_attachments(),
'tag' => $this->get_tags(), 'tag' => $this->get_tags(),
); );

View file

@ -356,7 +356,7 @@ class Inbox {
$inbox = \Activitypub\get_inbox_by_actor( $object['actor'] ); $inbox = \Activitypub\get_inbox_by_actor( $object['actor'] );
// send "Accept" activity // send "Accept" activity
$activity = new \Activitypub\Model\Activity( 'Accept', \Activitypub\Model\Activity::TYPE_SIMPLE ); $activity = new \Activitypub\Model\Activity( 'Accept' );
$activity->set_object( $object ); $activity->set_object( $object );
$activity->set_actor( \get_author_posts_url( $user_id ) ); $activity->set_actor( \get_author_posts_url( $user_id ) );
$activity->set_to( $object['actor'] ); $activity->set_to( $object['actor'] );

View file

@ -102,7 +102,8 @@ class Outbox {
foreach ( $posts as $post ) { foreach ( $posts as $post ) {
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = new \Activitypub\Model\Post( $post );
$activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_NONE ); $activitypub_activity = new \Activitypub\Model\Activity( 'Create', false );
$activitypub_activity->from_post( $activitypub_post ); $activitypub_activity->from_post( $activitypub_post );
$json->orderedItems[] = $activitypub_activity->to_array(); // phpcs:ignore $json->orderedItems[] = $activitypub_activity->to_array(); // phpcs:ignore
} }

View file

@ -28,7 +28,7 @@ class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HT
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = new \Activitypub\Model\Post( $post );
\Activitypub\Activity_Dispatcher::send_post_activity( $activitypub_post ); \Activitypub\Activity_Dispatcher::send_create_activity( $activitypub_post );
$this->assertNotEmpty( $activitypub_post->get_content() ); $this->assertNotEmpty( $activitypub_post->get_content() );
@ -69,7 +69,7 @@ class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HT
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = new \Activitypub\Model\Post( $post );
\Activitypub\Activity_Dispatcher::send_post_activity( $activitypub_post ); \Activitypub\Activity_Dispatcher::send_create_activity( $activitypub_post );
$this->assertNotEmpty( $activitypub_post->get_content() ); $this->assertNotEmpty( $activitypub_post->get_content() );

View file

@ -19,10 +19,10 @@ class Test_Activitypub_Activity extends WP_UnitTestCase {
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = new \Activitypub\Model\Post( $post );
$activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL ); $activitypub_activity = new \Activitypub\Model\Activity( 'Create' );
$activitypub_activity->from_post( $activitypub_post ); $activitypub_activity->from_post( $activitypub_post );
$this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_cc() ); $this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_to() );
$this->assertContains( 'https://example.com/alex', $activitypub_activity->get_cc() ); $this->assertContains( 'https://example.com/alex', $activitypub_activity->get_cc() );
remove_all_filters( 'activitypub_extract_mentions' ); remove_all_filters( 'activitypub_extract_mentions' );