PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-sync / src / class-server.php

class-server.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.7, at jetpack_vendor/automattic/jetpack-sync/src/class-server.php

197 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Sync server.
4 *
5 * @package automattic/jetpack-sync
6 */
7
8 namespace Automattic\Jetpack\Sync;
9
10 use WP_Error;
11
12 /**
13 * Simple version of a Jetpack Sync Server - just receives arrays of events and
14 * issues them locally with the 'jetpack_sync_remote_action' action.
15 */
16 class Server {
17 /**
18 * Codec used to decode sync events.
19 *
20 * @access private
21 *
22 * @var \Automattic\Jetpack\Sync\Codec_Interface
23 */
24 private $codec;
25
26 /**
27 * Maximum time for processing sync actions.
28 *
29 * @access public
30 *
31 * @var int
32 */
33 const MAX_TIME_PER_REQUEST_IN_SECONDS = 15;
34
35 /**
36 * Prefix of the blog lock transient.
37 *
38 * @access public
39 *
40 * @var string
41 */
42 const BLOG_LOCK_TRANSIENT_PREFIX = 'jp_sync_req_lock_';
43
44 /**
45 * Lifetime of the blog lock transient.
46 *
47 * @access public
48 *
49 * @var int
50 */
51 const BLOG_LOCK_TRANSIENT_EXPIRY = 60; // Seconds.
52
53 /**
54 * Constructor.
55 *
56 * This is necessary because you can't use "new" when you declare instance properties >:(
57 *
58 * @access public
59 */
60 public function __construct() {
61 $this->codec = new JSON_Deflate_Array_Codec();
62 }
63
64 /**
65 * Set the codec instance.
66 *
67 * @access public
68 *
69 * @param Automattic\Jetpack\Sync\Codec_Interface $codec Codec instance.
70 */
71 public function set_codec( Codec_Interface $codec ) {
72 $this->codec = $codec;
73 }
74
75 /**
76 * Attempt to lock the request when the server receives concurrent requests from the same blog.
77 *
78 * @access public
79 *
80 * @param int $blog_id ID of the blog.
81 * @param int $expiry Blog lock transient lifetime.
82 * @return boolean True if succeeded, false otherwise.
83 */
84 public function attempt_request_lock( $blog_id, $expiry = self::BLOG_LOCK_TRANSIENT_EXPIRY ) {
85 $transient_name = $this->get_concurrent_request_transient_name( $blog_id );
86 $locked_time = get_site_transient( $transient_name );
87 if ( $locked_time ) {
88 return false;
89 }
90 set_site_transient( $transient_name, microtime( true ), $expiry );
91
92 return true;
93 }
94
95 /**
96 * Retrieve the blog lock transient name for a particular blog.
97 *
98 * @access public
99 *
100 * @param int $blog_id ID of the blog.
101 * @return string Name of the blog lock transient.
102 */
103 private function get_concurrent_request_transient_name( $blog_id ) {
104 return self::BLOG_LOCK_TRANSIENT_PREFIX . $blog_id;
105 }
106
107 /**
108 * Remove the request lock from a particular blog ID.
109 *
110 * @access public
111 *
112 * @param int $blog_id ID of the blog.
113 */
114 public function remove_request_lock( $blog_id ) {
115 delete_site_transient( $this->get_concurrent_request_transient_name( $blog_id ) );
116 }
117
118 /**
119 * Receive and process sync events.
120 *
121 * @access public
122 *
123 * @param array $data Sync events.
124 * @param object $token The auth token used to invoke the API.
125 * @param int $sent_timestamp Timestamp (in seconds) when the actions were transmitted.
126 * @param string $queue_id ID of the queue from which the event was sent (`sync` or `full_sync`).
127 * @return array Processed sync events.
128 */
129 public function receive( $data, $token = null, $sent_timestamp = null, $queue_id = null ) {
130 $start_time = microtime( true );
131 if ( ! is_array( $data ) ) {
132 return new WP_Error( 'action_decoder_error', 'Events must be an array' );
133 }
134
135 if ( $token && ! $this->attempt_request_lock( $token->blog_id ) ) {
136 /**
137 * Fires when the server receives two concurrent requests from the same blog
138 *
139 * @since 1.6.3
140 * @since-jetpack 4.2.0
141 *
142 * @param object|null $token The token object of the misbehaving site
143 */
144 do_action( 'jetpack_sync_multi_request_fail', $token );
145
146 return new WP_Error( 'concurrent_request_error', 'There is another request running for the same blog ID' );
147 }
148
149 $events = wp_unslash( array_map( array( $this->codec, 'decode' ), $data ) );
150 $events_processed = array();
151
152 /**
153 * Fires when an array of actions are received from a remote Jetpack site
154 *
155 * @since 1.6.3
156 * @since-jetpack 4.2.0
157 *
158 * @param array $events Array of actions received from the remote site
159 * @param object|null $token The auth token used to invoke the API
160 */
161 do_action( 'jetpack_sync_remote_actions', $events, $token );
162
163 foreach ( $events as $key => $event ) {
164 list( $action_name, $args, $user_id, $timestamp, $silent ) = $event;
165
166 /**
167 * Fires when an action is received from a remote Jetpack site
168 *
169 * @since 1.6.3
170 * @since-jetpack 4.2.0
171 *
172 * @param string $action_name The name of the action executed on the remote site
173 * @param array $args The arguments passed to the action
174 * @param int $user_id The external_user_id who did the action
175 * @param bool $silent Whether the item was created via import
176 * @param double $timestamp Timestamp (in seconds) when the action occurred
177 * @param double $sent_timestamp Timestamp (in seconds) when the action was transmitted
178 * @param string $queue_id ID of the queue from which the event was sent (sync or full_sync)
179 * @param object|null $token The auth token used to invoke the API
180 */
181 do_action( 'jetpack_sync_remote_action', $action_name, $args, $user_id, $silent, $timestamp, $sent_timestamp, $queue_id, $token );
182
183 $events_processed[] = $key;
184
185 if ( microtime( true ) - $start_time > self::MAX_TIME_PER_REQUEST_IN_SECONDS ) {
186 break;
187 }
188 }
189
190 if ( $token ) {
191 $this->remove_request_lock( $token->blog_id );
192 }
193
194 return $events_processed;
195 }
196 }
197