class.jetpack-sync-server.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. <?php
  2. require_once dirname( __FILE__ ) . '/class.jetpack-sync-json-deflate-array-codec.php';
  3. /**
  4. * Simple version of a Jetpack Sync Server - just receives arrays of events and
  5. * issues them locally with the 'jetpack_sync_remote_action' action.
  6. */
  7. class Jetpack_Sync_Server {
  8. private $codec;
  9. const MAX_TIME_PER_REQUEST_IN_SECONDS = 15;
  10. const BLOG_LOCK_TRANSIENT_PREFIX = 'jp_sync_req_lock_';
  11. const BLOG_LOCK_TRANSIENT_EXPIRY = 60; // seconds
  12. // this is necessary because you can't use "new" when you declare instance properties >:(
  13. function __construct() {
  14. $this->codec = new Jetpack_Sync_JSON_Deflate_Array_Codec();
  15. }
  16. function set_codec( iJetpack_Sync_Codec $codec ) {
  17. $this->codec = $codec;
  18. }
  19. function attempt_request_lock( $blog_id, $expiry = self::BLOG_LOCK_TRANSIENT_EXPIRY ) {
  20. $transient_name = $this->get_concurrent_request_transient_name( $blog_id );
  21. $locked_time = get_site_transient( $transient_name );
  22. if ( $locked_time ) {
  23. return false;
  24. }
  25. set_site_transient( $transient_name, microtime( true ), $expiry );
  26. return true;
  27. }
  28. private function get_concurrent_request_transient_name( $blog_id ) {
  29. return self::BLOG_LOCK_TRANSIENT_PREFIX . $blog_id;
  30. }
  31. function remove_request_lock( $blog_id ) {
  32. delete_site_transient( $this->get_concurrent_request_transient_name( $blog_id ) );
  33. }
  34. function receive( $data, $token = null, $sent_timestamp = null, $queue_id = null ) {
  35. $start_time = microtime( true );
  36. if ( ! is_array( $data ) ) {
  37. return new WP_Error( 'action_decoder_error', 'Events must be an array' );
  38. }
  39. if ( $token && ! $this->attempt_request_lock( $token->blog_id ) ) {
  40. /**
  41. * Fires when the server receives two concurrent requests from the same blog
  42. *
  43. * @since 4.2.0
  44. *
  45. * @param token The token object of the misbehaving site
  46. */
  47. do_action( 'jetpack_sync_multi_request_fail', $token );
  48. return new WP_Error( 'concurrent_request_error', 'There is another request running for the same blog ID' );
  49. }
  50. $events = wp_unslash( array_map( array( $this->codec, 'decode' ), $data ) );
  51. $events_processed = array();
  52. /**
  53. * Fires when an array of actions are received from a remote Jetpack site
  54. *
  55. * @since 4.2.0
  56. *
  57. * @param array Array of actions received from the remote site
  58. */
  59. do_action( 'jetpack_sync_remote_actions', $events, $token );
  60. foreach ( $events as $key => $event ) {
  61. list( $action_name, $args, $user_id, $timestamp, $silent ) = $event;
  62. /**
  63. * Fires when an action is received from a remote Jetpack site
  64. *
  65. * @since 4.2.0
  66. *
  67. * @param string $action_name The name of the action executed on the remote site
  68. * @param array $args The arguments passed to the action
  69. * @param int $user_id The external_user_id who did the action
  70. * @param bool $silent Whether the item was created via import
  71. * @param double $timestamp Timestamp (in seconds) when the action occurred
  72. * @param double $sent_timestamp Timestamp (in seconds) when the action was transmitted
  73. * @param string $queue_id ID of the queue from which the event was sent (sync or full_sync)
  74. * @param array $token The auth token used to invoke the API
  75. */
  76. do_action( 'jetpack_sync_remote_action', $action_name, $args, $user_id, $silent, $timestamp, $sent_timestamp, $queue_id, $token );
  77. $events_processed[] = $key;
  78. if ( microtime( true ) - $start_time > self::MAX_TIME_PER_REQUEST_IN_SECONDS ) {
  79. break;
  80. }
  81. }
  82. if ( $token ) {
  83. $this->remove_request_lock( $token->blog_id );
  84. }
  85. return $events_processed;
  86. }
  87. }