From 21d1ee9915438edd0304025d5853801821526dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Sat, 4 Jan 2025 10:39:12 +0100 Subject: [PATCH] Refactor outbox parsing and add some debug logs --- .../activitypub/model/class-event-source.php | 1 + .../activitypub/transmogrifier/class-base.php | 71 ++++++--- includes/class-debug.php | 38 +++++ includes/class-outbox-parser.php | 143 ++++++++++-------- includes/class-setup.php | 3 + 5 files changed, 165 insertions(+), 91 deletions(-) create mode 100644 includes/class-debug.php diff --git a/includes/activitypub/model/class-event-source.php b/includes/activitypub/model/class-event-source.php index b2249a2..ff2a4f5 100644 --- a/includes/activitypub/model/class-event-source.php +++ b/includes/activitypub/model/class-event-source.php @@ -94,6 +94,7 @@ class Event_Source extends Actor { $actor = \json_decode( $actor_json, true ); if ( ! isset( $actor['outbox'] ) ) { + \do_action( 'event_bridge_for_activitypub_write_log', array( "[ACTIVITYPUB] Did not find outbox URL for actor {$actor}" ) ); return null; } diff --git a/includes/activitypub/transmogrifier/class-base.php b/includes/activitypub/transmogrifier/class-base.php index 35bfd34..6307d0b 100644 --- a/includes/activitypub/transmogrifier/class-base.php +++ b/includes/activitypub/transmogrifier/class-base.php @@ -57,10 +57,56 @@ abstract class Base { $post_id = $this->save_event(); + $event_id = $activitypub_event['id']; + if ( $post_id ) { + \do_action( + 'event_bridge_for_activitypub_write_log', + array( "[ACTIVITYPUB] Processed incoming event {$event_id} from {$actor}" ) + ); update_post_meta( $post_id, '_event_bridge_for_activitypub_is_remote_cached', true ); update_post_meta( $post_id, '_event_bridge_for_activitypub_event_source', sanitize_url( $actor ) ); update_post_meta( $post_id, 'activitypub_content_visibility', constant( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL' ) ?? '' ); + } else { + \do_action( + 'event_bridge_for_activitypub_write_log', + array( "[ACTIVITYPUB] Failed processing incoming event {$event_id} from {$actor}" ) + ); + } + } + + /** + * Delete a local event in WordPress that is a cached remote one. + * + * @param int $activitypub_event_id The ActivityPub events ID. + */ + public function delete( $activitypub_event_id ) { + $post_id = self::get_post_id_from_activitypub_id( $activitypub_event_id ); + + if ( ! $post_id ) { + \do_action( + 'event_bridge_for_activitypub_write_log', + array( "[ACTIVITYPUB] Received delete for event that is not cached locally {$activitypub_event_id}" ) + ); + return new WP_Error( + 'event_bridge_for_activitypub_remote_event_not_found', + \__( 'Remote event not found in cache', 'event-bridge-for-activitypub' ), + array( 'status' => 404 ) + ); + } + + $thumbnail_id = get_post_thumbnail_id( $post_id ); + + if ( $thumbnail_id && ! Event_Sources::is_attachment_featured_image( $thumbnail_id ) ) { + wp_delete_attachment( $thumbnail_id, true ); + } + + $result = wp_delete_post( $post_id, true ); + + if ( $result ) { + \do_action( 'event_bridge_for_activitypub_write_log', array( "[ACTIVITYPUB] Deleted cached event {$activitypub_event_id}" ) ); + } else { + \do_action( 'event_bridge_for_activitypub_write_log', array( "[ACTIVITYPUB] Failed deleting cached event {$activitypub_event_id}" ) ); } } @@ -276,31 +322,6 @@ abstract class Base { return ''; } - /** - * Delete a local event in WordPress that is a cached remote one. - * - * @param int $activitypub_event_id The ActivityPub events ID. - */ - public function delete( $activitypub_event_id ) { - $post_id = self::get_post_id_from_activitypub_id( $activitypub_event_id ); - - if ( ! $post_id ) { - return new WP_Error( - 'event_bridge_for_activitypub_remote_event_not_found', - \__( 'Remote event not found in cache', 'event-bridge-for-activitypub' ), - array( 'status' => 404 ) - ); - } - - $thumbnail_id = get_post_thumbnail_id( $post_id ); - - if ( $thumbnail_id && ! Event_Sources::is_attachment_featured_image( $thumbnail_id ) ) { - wp_delete_attachment( $thumbnail_id, true ); - } - - wp_delete_post( $post_id, true ); - } - /** * Return the number of revisions to keep. * diff --git a/includes/class-debug.php b/includes/class-debug.php new file mode 100644 index 0000000..9640640 --- /dev/null +++ b/includes/class-debug.php @@ -0,0 +1,38 @@ +get_outbox(); + + if ( ! $outbox_url ) { + return; + } + + // Schedule the import of events via the outbox. + return self::queue_importing_from_outbox( $outbox_url, $actor, 0 ); + } + + /** + * Import events from an outbox: OrderedCollection or OrderedCollectionPage. + * + * @param string $url The url of the current page or outbox. + * @param string $actor The ActivityPub ID/URL of the actor that owns the outbox. + * @return void + */ + public static function import_events_from_outbox( $url, $actor ) { + $outbox = self::fetch_outbox( $url ); + + if ( ! $outbox ) { + return; + } + + $current_count = self::get_import_count( $actor ); + + if ( $current_count >= self::MAX_EVENTS_TO_IMPORT ) { + return; + } + + // Process orderedItems if they exist (non-paginated outbox). + if ( isset( $outbox['orderedItems'] ) && is_array( $outbox['orderedItems'] ) ) { + $current_count += self::import_events_from_items( + $outbox['orderedItems'], + $actor, + self::MAX_EVENTS_TO_IMPORT - $current_count + ); + } + + self::update_import_count( $actor, $current_count ); + + // If the count is already exceeded abort here. + if ( $current_count >= self::MAX_EVENTS_TO_IMPORT ) { + return; + } + + // Get next page and if it exists schedule the import of next page. + $pagination_url = self::get_pagination_url( $outbox ); + + if ( $pagination_url ) { + self::queue_importing_from_outbox( $pagination_url, $actor ); + } + } + /** * Check if an Activity is of type Update or Create. * * @param array $activity The Activity as associative array. * @return bool */ - public static function is_create_or_update_activity( $activity ) { + private static function is_create_or_update_activity( $activity ) { if ( ! isset( $activity['type'] ) ) { return false; } @@ -95,7 +169,7 @@ class Outbox_Parser { * @param int $limit The limit of how many events to save locally. * @return int The number of saved events (at least attempted). */ - public static function import_events_from_items( $items, $actor, $limit = -1 ) { + private static function import_events_from_items( $items, $actor, $limit = -1 ) { $events = self::parse_items_for_events( $items, $limit ); $transmogrifier = Setup::get_transmogrifier(); @@ -125,7 +199,7 @@ class Outbox_Parser { * @param int $delay The delay of the current time in seconds. * @return void */ - public static function queue_importing_from_outbox( $url, $actor, $delay = 10 ) { + private static function queue_importing_from_outbox( $url, $actor, $delay = 10 ) { $hook = 'event_bridge_for_activitypub_import_events_from_outbox'; $args = array( $url, $actor ); @@ -136,24 +210,6 @@ class Outbox_Parser { return \wp_schedule_single_event( \time() + $delay, $hook, $args ); } - /** - * Initialize the backfilling of events via the outbox of an ActivityPub actor. - * - * @param string $actor The ActivityPub ID of the actor which owns the outbox. - * @return bool|WP_Error - */ - public static function backfill_events( $actor ) { - // Initiate parsing of outbox collection. - $outbox_url = Event_Source::get_by_id( $actor )->get_outbox(); - - if ( ! $outbox_url ) { - return; - } - - // Schedule the import of events via the outbox. - return self::queue_importing_from_outbox( $outbox_url, $actor, 0 ); - } - /** * Get the current import count for the actor. * @@ -213,49 +269,4 @@ class Outbox_Parser { return null; } - - - /** - * Import events from an outbox: OrderedCollection or OrderedCollectionPage. - * - * @param string $url The url of the current page or outbox. - * @param string $actor The ActivityPub ID/URL of the actor that owns the outbox. - * @return void - */ - public static function import_events_from_outbox( $url, $actor ) { - $outbox = self::fetch_outbox( $url ); - - if ( ! $outbox ) { - return; - } - - $current_count = self::get_import_count( $actor ); - - if ( $current_count >= self::MAX_EVENTS_TO_IMPORT ) { - return; - } - - // Process orderedItems if they exist (non-paginated outbox). - if ( isset( $outbox['orderedItems'] ) && is_array( $outbox['orderedItems'] ) ) { - $current_count += self::import_events_from_items( - $outbox['orderedItems'], - $actor, - self::MAX_EVENTS_TO_IMPORT - $current_count - ); - } - - self::update_import_count( $actor, $current_count ); - - // If the count is already exceeded abort here. - if ( $current_count >= self::MAX_EVENTS_TO_IMPORT ) { - return; - } - - // Get next page and if it exists schedule the import of next page. - $pagination_url = self::get_pagination_url( $outbox ); - - if ( $pagination_url ) { - self::queue_importing_from_outbox( $pagination_url, $actor ); - } - } } diff --git a/includes/class-setup.php b/includes/class-setup.php index 4aa8c90..8e74cd0 100644 --- a/includes/class-setup.php +++ b/includes/class-setup.php @@ -269,6 +269,9 @@ class Setup { Event_Sources::init(); } + // Initialize writing of debug logs. + Debug::init(); + // Lastly but most importantly: register the ActivityPub transformers for events to the ActivityPub plugin. add_filter( 'activitypub_transformer', array( $this, 'register_activitypub_event_transformer' ), 10, 3 ); }