mirror of
https://github.com/guzzle/guzzle.git
synced 2025-02-24 10:03:27 +01:00
WIP work on on_stats
This commit is contained in:
parent
2e92238902
commit
ec1f1a8b56
@ -7,6 +7,7 @@ use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\LazyOpenStream;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
@ -94,6 +95,10 @@ class CurlFactory implements CurlFactoryInterface
|
||||
EasyHandle $easy,
|
||||
CurlFactoryInterface $factory
|
||||
) {
|
||||
if (isset($easy->options['on_stats'])) {
|
||||
self::invokeStats($easy);
|
||||
}
|
||||
|
||||
if (!$easy->response || $easy->errno) {
|
||||
return self::finishError($handler, $easy, $factory);
|
||||
}
|
||||
@ -110,6 +115,19 @@ class CurlFactory implements CurlFactoryInterface
|
||||
return new FulfilledPromise($easy->response);
|
||||
}
|
||||
|
||||
private static function invokeStats(EasyHandle $easy)
|
||||
{
|
||||
$curlStats = curl_getinfo($easy->handle);
|
||||
$stats = new TransferStats(
|
||||
$easy->request,
|
||||
$easy->response,
|
||||
$curlStats['total_time'],
|
||||
$easy->errno,
|
||||
$curlStats
|
||||
);
|
||||
call_user_func($easy->options['on_stats'], $stats);
|
||||
}
|
||||
|
||||
private static function finishError(
|
||||
callable $handler,
|
||||
EasyHandle $easy,
|
||||
|
@ -4,6 +4,7 @@ namespace GuzzleHttp\Handler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
@ -80,18 +81,16 @@ class MockHandler implements \Countable
|
||||
? new RejectedPromise($response)
|
||||
: \GuzzleHttp\Promise\promise_for($response);
|
||||
|
||||
if (!$this->onFulfilled && !$this->onRejected) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $response->then(
|
||||
function ($value) {
|
||||
function ($value) use ($request, $options) {
|
||||
$this->invokeStats($request, $options, $value);
|
||||
if ($this->onFulfilled) {
|
||||
call_user_func($this->onFulfilled, $value);
|
||||
}
|
||||
return $value;
|
||||
},
|
||||
function ($reason) {
|
||||
function ($reason) use ($request, $options) {
|
||||
$this->invokeStats($request, $options, null, $reason);
|
||||
if ($this->onRejected) {
|
||||
call_user_func($this->onRejected, $reason);
|
||||
}
|
||||
@ -149,4 +148,16 @@ class MockHandler implements \Countable
|
||||
{
|
||||
return count($this->queue);
|
||||
}
|
||||
|
||||
private function invokeStats(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
ResponseInterface $response = null,
|
||||
$reason = null
|
||||
) {
|
||||
if (isset($options['on_stats'])) {
|
||||
$stats = new TransferStats($request, $response, 0, $reason);
|
||||
call_user_func($options['on_stats'], $stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
@ -32,6 +34,8 @@ class StreamHandler
|
||||
usleep($options['delay'] * 1000);
|
||||
}
|
||||
|
||||
$startTime = isset($options['on_stats']) ? microtime(true) : null;
|
||||
|
||||
try {
|
||||
// Does not support the expect header.
|
||||
$request = $request->withoutHeader('Expect');
|
||||
@ -42,8 +46,12 @@ class StreamHandler
|
||||
$request = $request->withHeader('Content-Length', 0);
|
||||
}
|
||||
|
||||
$stream = $this->createStream($request, $options);
|
||||
return $this->createResponse($request, $options, $stream);
|
||||
return $this->createResponse(
|
||||
$request,
|
||||
$options,
|
||||
$this->createStream($request, $options),
|
||||
$startTime
|
||||
);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw $e;
|
||||
} catch (\Exception $e) {
|
||||
@ -56,16 +64,37 @@ class StreamHandler
|
||||
) {
|
||||
$e = new ConnectException($e->getMessage(), $request, $e);
|
||||
}
|
||||
return new RejectedPromise(
|
||||
RequestException::wrapException($request, $e)
|
||||
$e = RequestException::wrapException($request, $e);
|
||||
$this->invokeStatsFunction($options, $request, $startTime, null, $e);
|
||||
|
||||
return new RejectedPromise($e);
|
||||
}
|
||||
}
|
||||
|
||||
private function invokeStatsFunction(
|
||||
array $options,
|
||||
RequestInterface $request,
|
||||
$startTime,
|
||||
ResponseInterface $response = null,
|
||||
$error = null
|
||||
) {
|
||||
if (isset($options['on_stats'])) {
|
||||
$stats = new TransferStats(
|
||||
$request,
|
||||
$response,
|
||||
microtime(true) - $startTime,
|
||||
$error,
|
||||
[]
|
||||
);
|
||||
call_user_func($options['on_stats'], $stats);
|
||||
}
|
||||
}
|
||||
|
||||
private function createResponse(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
$stream
|
||||
$stream,
|
||||
$startTime
|
||||
) {
|
||||
$hdrs = $this->lastHeaders;
|
||||
$this->lastHeaders = [];
|
||||
@ -93,6 +122,8 @@ class StreamHandler
|
||||
$this->drain($stream, $sink);
|
||||
}
|
||||
|
||||
$this->invokeStatsFunction($options, $request, $startTime, $response, null);
|
||||
|
||||
return new FulfilledPromise($response);
|
||||
}
|
||||
|
||||
|
118
src/TransferStats.php
Normal file
118
src/TransferStats.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Represents data at the point after it was transferred either successfully
|
||||
* or after a network error.
|
||||
*/
|
||||
final class TransferStats
|
||||
{
|
||||
private $request;
|
||||
private $response;
|
||||
private $transferTime;
|
||||
private $handlerStats;
|
||||
private $handlerErrorData;
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request Request that was sent.
|
||||
* @param ResponseInterface $response Response received (if any)
|
||||
* @param null $transferTime Total handler transfer time.
|
||||
* @param mixed $handlerErrorData Handler error data.
|
||||
* @param array $handlerStats Handler specific stats.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
$transferTime = null,
|
||||
$handlerErrorData = null,
|
||||
$handlerStats = []
|
||||
) {
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
$this->transferTime = $transferTime;
|
||||
$this->handlerErrorData = $handlerErrorData;
|
||||
$this->handlerStats = $handlerStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResponseInterface|null
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasResponse()
|
||||
{
|
||||
return $this->response !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets handler specific error data.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getHandlerErrorData()
|
||||
{
|
||||
return $this->handlerErrorData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the effective URI the request was sent to
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
public function getEffectiveUri()
|
||||
{
|
||||
return $this->request->getUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the estimated time the request was being transferred by the handler.
|
||||
*
|
||||
* @return float Time in seconds.
|
||||
*/
|
||||
public function getTransferTime()
|
||||
{
|
||||
return $this->transferTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of handler stat data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHandlerStats()
|
||||
{
|
||||
return $this->handlerStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific handler stat from the handler by name.
|
||||
*
|
||||
* @param string $stat Handler specific transfer stat to retrieve.
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getHandlerStat($stat)
|
||||
{
|
||||
return isset($this->handlerStats[$stat])
|
||||
? $this->handlerStats[$stat]
|
||||
: null;
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\TransferStats;
|
||||
|
||||
/**
|
||||
* @covers \GuzzleHttp\Handler\MockHandler
|
||||
@ -43,7 +44,6 @@ class MockHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$mock = new MockHandler([$e]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$p = $mock($request, []);
|
||||
$this->assertEquals(PromiseInterface::REJECTED, $p->getState());
|
||||
try {
|
||||
$p->wait();
|
||||
$this->fail();
|
||||
@ -113,4 +113,35 @@ class MockHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$mock($request, ['http_errors' => true])->wait();
|
||||
}
|
||||
|
||||
public function testInvokesOnStatsFunctionForResponse()
|
||||
{
|
||||
$res = new Response();
|
||||
$mock = new MockHandler([$res]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$stats = null;
|
||||
$onStats = function (TransferStats $s) use (&$stats) {
|
||||
$stats = $s;
|
||||
};
|
||||
$p = $mock($request, ['on_stats' => $onStats]);
|
||||
$p->wait();
|
||||
$this->assertSame($res, $stats->getResponse());
|
||||
$this->assertSame($request, $stats->getRequest());
|
||||
}
|
||||
|
||||
public function testInvokesOnStatsFunctionForError()
|
||||
{
|
||||
$e = new \Exception('a');
|
||||
$c = null;
|
||||
$mock = new MockHandler([$e], null, function ($v) use (&$c) { $c = $v; });
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$stats = null;
|
||||
$onStats = function (TransferStats $s) use (&$stats) {
|
||||
$stats = $s;
|
||||
};
|
||||
$mock($request, ['on_stats' => $onStats])->wait(false);
|
||||
$this->assertSame($e, $stats->getHandlerErrorData());
|
||||
$this->assertSame(null, $stats->getResponse());
|
||||
$this->assertSame($request, $stats->getRequest());
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ class MiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
}));
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com'), []);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\PromiseInterface', $p);
|
||||
}
|
||||
|
||||
public function testMapsResponse()
|
||||
|
@ -25,7 +25,7 @@ class PrepareBodyMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
$stack->push($m);
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com', [], '123'), []);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\PromiseInterface', $p);
|
||||
$response = $p->wait();
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
@ -47,7 +47,7 @@ class PrepareBodyMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
$stack->push($m);
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com', [], $body), []);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\PromiseInterface', $p);
|
||||
$response = $p->wait();
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
@ -67,7 +67,7 @@ class PrepareBodyMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
$stack->push($m);
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com', [], $bd), []);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\PromiseInterface', $p);
|
||||
$response = $p->wait();
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
@ -103,7 +103,7 @@ class PrepareBodyMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com', [], $bd), [
|
||||
'expect' => $value
|
||||
]);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\PromiseInterface', $p);
|
||||
$response = $p->wait();
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
@ -126,7 +126,7 @@ class PrepareBodyMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
new Request('PUT', 'http://www.google.com', ['Expect' => 'Foo'], $bd),
|
||||
['expect' => true]
|
||||
);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\PromiseInterface', $p);
|
||||
$response = $p->wait();
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user