PluginProbe
Media Cloud Sync / 1.3.11
Media Cloud Sync v1.3.11
1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 All 34 releases
media-cloud-sync / includes / sdk / s3 / Aws / Middleware.php

Middleware.php in Media Cloud Sync 1.3.11, at includes/sdk/s3/Aws/Middleware.php

343 lines 14.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Dudlewebs\WPMCS\s3\Aws;
4
5 use Dudlewebs\WPMCS\s3\Aws\Api\Service;
6 use Dudlewebs\WPMCS\s3\Aws\Api\Validator;
7 use Dudlewebs\WPMCS\s3\Aws\Credentials\CredentialsInterface;
8 use Dudlewebs\WPMCS\s3\Aws\EndpointV2\EndpointProviderV2;
9 use Dudlewebs\WPMCS\s3\Aws\Exception\AwsException;
10 use Dudlewebs\WPMCS\s3\Aws\Signature\S3ExpressSignature;
11 use Dudlewebs\WPMCS\s3\Aws\Token\TokenAuthorization;
12 use Dudlewebs\WPMCS\s3\Aws\Token\TokenInterface;
13 use Dudlewebs\WPMCS\s3\GuzzleHttp\Promise;
14 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7;
15 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7\LazyOpenStream;
16 use Dudlewebs\WPMCS\s3\Psr\Http\Message\RequestInterface;
17 final class Middleware
18 {
19 /**
20 * Middleware used to allow a command parameter (e.g., "SourceFile") to
21 * be used to specify the source of data for an upload operation.
22 *
23 * @param Service $api
24 * @param string $bodyParameter
25 * @param string $sourceParameter
26 *
27 * @return callable
28 */
29 public static function sourceFile(Service $api, $bodyParameter = 'Body', $sourceParameter = 'SourceFile')
30 {
31 return function (callable $handler) use($api, $bodyParameter, $sourceParameter) {
32 return function (CommandInterface $command, ?RequestInterface $request = null) use($handler, $api, $bodyParameter, $sourceParameter) {
33 $operation = $api->getOperation($command->getName());
34 $source = $command[$sourceParameter];
35 if ($source !== null && $operation->getInput()->hasMember($bodyParameter)) {
36 $lazyOpenStream = new LazyOpenStream($source, 'r');
37 $command[$bodyParameter] = $lazyOpenStream;
38 unset($command[$sourceParameter]);
39 $next = $handler($command, $request);
40 // To avoid failures in some tests cases
41 if ($next !== null && \method_exists($next, 'then')) {
42 return $next->then(function ($result) use($lazyOpenStream) {
43 // To make sure the resource is closed.
44 $lazyOpenStream->close();
45 return $result;
46 })->otherwise(function (\Throwable $e) use($lazyOpenStream) {
47 $lazyOpenStream->close();
48 throw $e;
49 });
50 }
51 return $next;
52 }
53 return $handler($command, $request);
54 };
55 };
56 }
57 /**
58 * Adds a middleware that uses client-side validation.
59 *
60 * @param Service $api API being accessed.
61 *
62 * @return callable
63 */
64 public static function validation(Service $api, ?Validator $validator = null)
65 {
66 $validator = $validator ?: new Validator();
67 return function (callable $handler) use($api, $validator) {
68 return function (CommandInterface $command, ?RequestInterface $request = null) use($api, $validator, $handler) {
69 if ($api->isModifiedModel()) {
70 $api = new Service($api->getDefinition(), $api->getProvider());
71 }
72 $operation = $api->getOperation($command->getName());
73 $validator->validate($command->getName(), $operation->getInput(), $command->toArray());
74 return $handler($command, $request);
75 };
76 };
77 }
78 /**
79 * Builds an HTTP request for a command.
80 *
81 * @param callable $serializer Function used to serialize a request for a
82 * command.
83 * @param EndpointProviderV2 | null $endpointProvider
84 * @param array $providerArgs
85 * @return callable
86 */
87 public static function requestBuilder($serializer)
88 {
89 return function (callable $handler) use($serializer) {
90 return function (CommandInterface $command, $endpoint = null) use($serializer, $handler) {
91 return $handler($command, $serializer($command, $endpoint));
92 };
93 };
94 }
95 /**
96 * Creates a middleware that signs requests for a command.
97 *
98 * @param callable $credProvider Credentials provider function that
99 * returns a promise that is resolved
100 * with a CredentialsInterface object.
101 * @param callable $signatureFunction Function that accepts a Command
102 * object and returns a
103 * SignatureInterface.
104 *
105 * @return callable
106 */
107 public static function signer(callable $credProvider, callable $signatureFunction, $tokenProvider = null, $config = [])
108 {
109 return function (callable $handler) use($signatureFunction, $credProvider, $tokenProvider, $config) {
110 return function (CommandInterface $command, RequestInterface $request) use($handler, $signatureFunction, $credProvider, $tokenProvider, $config) {
111 $signer = $signatureFunction($command);
112 if ($signer instanceof TokenAuthorization) {
113 return $tokenProvider()->then(function (TokenInterface $token) use($handler, $command, $signer, $request) {
114 $command->getMetricsBuilder()->identifyMetricByValueAndAppend('token', $token);
115 return $handler($command, $signer->authorizeRequest($request, $token));
116 });
117 }
118 if ($signer instanceof S3ExpressSignature) {
119 $credentialPromise = $config['s3_express_identity_provider']($command);
120 } else {
121 $credentialPromise = $credProvider();
122 }
123 return $credentialPromise->then(function (CredentialsInterface $creds) use($handler, $command, $signer, $request) {
124 // Capture credentials metric
125 $command->getMetricsBuilder()->identifyMetricByValueAndAppend('credentials', $creds);
126 return $handler($command, $signer->signRequest($request, $creds));
127 });
128 };
129 };
130 }
131 /**
132 * Creates a middleware that invokes a callback at a given step.
133 *
134 * The tap callback accepts a CommandInterface and RequestInterface as
135 * arguments but is not expected to return a new value or proxy to
136 * downstream middleware. It's simply a way to "tap" into the handler chain
137 * to debug or get an intermediate value.
138 *
139 * @param callable $fn Tap function
140 *
141 * @return callable
142 */
143 public static function tap(callable $fn)
144 {
145 return function (callable $handler) use($fn) {
146 return function (CommandInterface $command, ?RequestInterface $request = null) use($handler, $fn) {
147 $fn($command, $request);
148 return $handler($command, $request);
149 };
150 };
151 }
152 /**
153 * Middleware wrapper function that retries requests based on the boolean
154 * result of invoking the provided "decider" function.
155 *
156 * If no delay function is provided, a simple implementation of exponential
157 * backoff will be utilized.
158 *
159 * @param callable $decider Function that accepts the number of retries,
160 * a request, [result], and [exception] and
161 * returns true if the command is to be retried.
162 * @param callable $delay Function that accepts the number of retries and
163 * returns the number of milliseconds to delay.
164 * @param bool $stats Whether to collect statistics on retries and the
165 * associated delay.
166 *
167 * @return callable
168 */
169 public static function retry(?callable $decider = null, ?callable $delay = null, $stats = \false)
170 {
171 $decider = $decider ?: RetryMiddleware::createDefaultDecider();
172 $delay = $delay ?: [RetryMiddleware::class, 'exponentialDelay'];
173 return function (callable $handler) use($decider, $delay, $stats) {
174 return new RetryMiddleware($decider, $delay, $handler, $stats);
175 };
176 }
177 /**
178 * Middleware wrapper function that adds an invocation id header to
179 * requests, which is only applied after the build step.
180 *
181 * This is a uniquely generated UUID to identify initial and subsequent
182 * retries as part of a complete request lifecycle.
183 *
184 * @return callable
185 */
186 public static function invocationId()
187 {
188 return function (callable $handler) {
189 return function (CommandInterface $command, RequestInterface $request) use($handler) {
190 return $handler($command, $request->withHeader('aws-sdk-invocation-id', \md5(\uniqid(\gethostname(), \true))));
191 };
192 };
193 }
194 /**
195 * Middleware wrapper function that adds a Content-Type header to requests.
196 * This is only done when the Content-Type has not already been set, and the
197 * request body's URI is available. It then checks the file extension of the
198 * URI to determine the mime-type.
199 *
200 * @param array $operations Operations that Content-Type should be added to.
201 *
202 * @return callable
203 */
204 public static function contentType(array $operations)
205 {
206 return function (callable $handler) use($operations) {
207 return function (CommandInterface $command, ?RequestInterface $request = null) use($handler, $operations) {
208 if (!$request->hasHeader('Content-Type') && \in_array($command->getName(), $operations, \true) && ($uri = $request->getBody()->getMetadata('uri'))) {
209 $request = $request->withHeader('Content-Type', Psr7\MimeType::fromFilename($uri) ?: 'application/octet-stream');
210 }
211 return $handler($command, $request);
212 };
213 };
214 }
215 /**
216 * Middleware wrapper function that adds a trace id header to requests
217 * from clients instantiated in supported Lambda runtime environments.
218 *
219 * The purpose for this header is to track and stop Lambda functions
220 * from being recursively invoked due to misconfigured resources.
221 *
222 * @return callable
223 */
224 public static function recursionDetection()
225 {
226 return function (callable $handler) {
227 return function (CommandInterface $command, RequestInterface $request) use($handler) {
228 $isLambda = \getenv('AWS_LAMBDA_FUNCTION_NAME');
229 $traceId = \str_replace('\\e', '\\x1b', \getenv('_X_AMZN_TRACE_ID'));
230 if ($isLambda && $traceId) {
231 if (!$request->hasHeader('X-Amzn-Trace-Id')) {
232 $ignoreChars = ['=', ';', ':', '+', '&', '[', ']', '{', '}', '"', '\'', ','];
233 $traceIdEncoded = \rawurlencode(\stripcslashes($traceId));
234 foreach ($ignoreChars as $char) {
235 $encodedChar = \rawurlencode($char);
236 $traceIdEncoded = \str_replace($encodedChar, $char, $traceIdEncoded);
237 }
238 return $handler($command, $request->withHeader('X-Amzn-Trace-Id', $traceIdEncoded));
239 }
240 }
241 return $handler($command, $request);
242 };
243 };
244 }
245 /**
246 * Tracks command and request history using a history container.
247 *
248 * This is useful for testing.
249 *
250 * @param History $history History container to store entries.
251 *
252 * @return callable
253 */
254 public static function history(History $history)
255 {
256 return function (callable $handler) use($history) {
257 return function (CommandInterface $command, ?RequestInterface $request = null) use($handler, $history) {
258 $ticket = $history->start($command, $request);
259 return $handler($command, $request)->then(function ($result) use($history, $ticket) {
260 $history->finish($ticket, $result);
261 return $result;
262 }, function ($reason) use($history, $ticket) {
263 $history->finish($ticket, $reason);
264 return Promise\Create::rejectionFor($reason);
265 });
266 };
267 };
268 }
269 /**
270 * Creates a middleware that applies a map function to requests as they
271 * pass through the middleware.
272 *
273 * @param callable $f Map function that accepts a RequestInterface and
274 * returns a RequestInterface.
275 *
276 * @return callable
277 */
278 public static function mapRequest(callable $f)
279 {
280 return function (callable $handler) use($f) {
281 return function (CommandInterface $command, ?RequestInterface $request = null) use($handler, $f) {
282 return $handler($command, $f($request));
283 };
284 };
285 }
286 /**
287 * Creates a middleware that applies a map function to commands as they
288 * pass through the middleware.
289 *
290 * @param callable $f Map function that accepts a command and returns a
291 * command.
292 *
293 * @return callable
294 */
295 public static function mapCommand(callable $f)
296 {
297 return function (callable $handler) use($f) {
298 return function (CommandInterface $command, ?RequestInterface $request = null) use($handler, $f) {
299 return $handler($f($command), $request);
300 };
301 };
302 }
303 /**
304 * Creates a middleware that applies a map function to results.
305 *
306 * @param callable $f Map function that accepts an Aws\ResultInterface and
307 * returns an Aws\ResultInterface.
308 *
309 * @return callable
310 */
311 public static function mapResult(callable $f)
312 {
313 return function (callable $handler) use($f) {
314 return function (CommandInterface $command, ?RequestInterface $request = null) use($handler, $f) {
315 return $handler($command, $request)->then($f);
316 };
317 };
318 }
319 public static function timer()
320 {
321 return function (callable $handler) {
322 return function (CommandInterface $command, ?RequestInterface $request = null) use($handler) {
323 $start = \microtime(\true);
324 return $handler($command, $request)->then(function (ResultInterface $res) use($start) {
325 if (!isset($res['@metadata'])) {
326 $res['@metadata'] = [];
327 }
328 if (!isset($res['@metadata']['transferStats'])) {
329 $res['@metadata']['transferStats'] = [];
330 }
331 $res['@metadata']['transferStats']['total_time'] = \microtime(\true) - $start;
332 return $res;
333 }, function ($err) use($start) {
334 if ($err instanceof AwsException) {
335 $err->setTransferInfo(['total_time' => \microtime(\true) - $start] + $err->getTransferInfo());
336 }
337 return Promise\Create::rejectionFor($err);
338 });
339 };
340 };
341 }
342 }
343