Skip to content

Commit

Permalink
Add streaming methods to Service infra (#1155)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardm-stripe committed Jul 9, 2021
1 parent 8a5a311 commit 33317c9
Show file tree
Hide file tree
Showing 12 changed files with 258 additions and 46 deletions.
3 changes: 3 additions & 0 deletions init.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

// HttpClient
require __DIR__ . '/lib/HttpClient/ClientInterface.php';
require __DIR__ . '/lib/HttpClient/StreamingClientInterface.php';
require __DIR__ . '/lib/HttpClient/CurlClient.php';

// Exceptions
Expand Down Expand Up @@ -66,7 +67,9 @@
require __DIR__ . '/lib/Service/AbstractServiceFactory.php';

// StripeClient
require __DIR__ . '/lib/BaseStripeClientInterface.php';
require __DIR__ . '/lib/StripeClientInterface.php';
require __DIR__ . '/lib/StripeStreamingClientInterface.php';
require __DIR__ . '/lib/BaseStripeClient.php';
require __DIR__ . '/lib/StripeClient.php';

Expand Down
39 changes: 33 additions & 6 deletions lib/ApiRequestor.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class ApiRequestor
* @var HttpClient\ClientInterface
*/
private static $_httpClient;
/**
* @var HttpClient\StreamingClientInterface
*/
private static $_streamingHttpClient;

/**
* @var RequestTelemetry
Expand Down Expand Up @@ -126,20 +130,20 @@ public function request($method, $url, $params = null, $headers = null)
/**
* @param string $method
* @param string $url
* @param callable $readBodyChunk
* @param callable $readBodyChunkCallable
* @param null|array $params
* @param null|array $headers
*
* @throws Exception\ApiErrorException
*
* @return array tuple containing (ApiReponse, API key)
*/
public function requestStream($method, $url, $readBodyChunk, $params = null, $headers = null)
public function requestStream($method, $url, $readBodyChunkCallable, $params = null, $headers = null)
{
$params = $params ?: [];
$headers = $headers ?: [];
list($rbody, $rcode, $rheaders, $myApiKey) =
$this->_requestRawStreaming($method, $url, $params, $headers, $readBodyChunk);
$this->_requestRawStreaming($method, $url, $params, $headers, $readBodyChunkCallable);
if ($rcode >= 300) {
$this->_interpretResponse($rbody, $rcode, $rheaders);
}
Expand Down Expand Up @@ -473,25 +477,26 @@ private function _requestRaw($method, $url, $params, $headers)
* @param array $params
* @param array $headers
* @param callable $readBodyChunk
* @param mixed $readBodyChunkCallable
*
* @throws Exception\AuthenticationException
* @throws Exception\ApiConnectionException
*
* @return array
*/
private function _requestRawStreaming($method, $url, $params, $headers, $readBodyChunk)
private function _requestRawStreaming($method, $url, $params, $headers, $readBodyChunkCallable)
{
list($absUrl, $rawHeaders, $params, $hasFile, $myApiKey) = $this->_prepareRequest($method, $url, $params, $headers);

$requestStartMs = Util\Util::currentTimeMillis();

list($rbody, $rcode, $rheaders) = $this->httpClient()->requestStream(
list($rbody, $rcode, $rheaders) = $this->streamingHttpClient()->requestStream(
$method,
$absUrl,
$rawHeaders,
$params,
$hasFile,
$readBodyChunk
$readBodyChunkCallable
);

if (isset($rheaders['request-id'])
Expand Down Expand Up @@ -570,6 +575,16 @@ public static function setHttpClient($client)
self::$_httpClient = $client;
}

/**
* @static
*
* @param HttpClient\StreamingClientInterface $client
*/
public static function setStreamingHttpClient($client)
{
self::$_streamingHttpClient = $client;
}

/**
* @static
*
Expand All @@ -591,4 +606,16 @@ private function httpClient()

return self::$_httpClient;
}

/**
* @return HttpClient\StreamingClientInterface
*/
private function streamingHttpClient()
{
if (!self::$_streamingHttpClient) {
self::$_streamingHttpClient = HttpClient\CurlClient::instance();
}

return self::$_streamingHttpClient;
}
}
21 changes: 20 additions & 1 deletion lib/BaseStripeClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Stripe;

class BaseStripeClient implements StripeClientInterface
class BaseStripeClient implements StripeClientInterface, StripeStreamingClientInterface
{
/** @var string default base URL for Stripe's API */
const DEFAULT_API_BASE = 'https://api.stripe.com';
Expand Down Expand Up @@ -139,6 +139,25 @@ public function request($method, $path, $params, $opts)
return $obj;
}

/**
* Sends a request to Stripe's API, passing chunks of the streamed response
* into a user-provided $readBodyChunkCallable callback.
*
* @param string $method the HTTP method
* @param string $path the path of the request
* @param callable $readBodyChunkCallable a function that will be called
* @param array $params the parameters of the request
* @param array|\Stripe\Util\RequestOptions $opts the special modifiers of the request
* with chunks of bytes from the body if the request is successful
*/
public function requestStream($method, $path, $readBodyChunkCallable, $params, $opts)
{
$opts = $this->defaultOpts->merge($opts, true);
$baseUrl = $opts->apiBase ?: $this->getApiBase();
$requestor = new \Stripe\ApiRequestor($this->apiKeyForRequest($opts), $baseUrl);
list($response, $opts->apiKey) = $requestor->requestStream($method, $path, $readBodyChunkCallable, $params, $opts->headers);
}

/**
* Sends a request to Stripe's API.
*
Expand Down
44 changes: 44 additions & 0 deletions lib/BaseStripeClientInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Stripe;

/**
* Interface for a Stripe client.
*/
interface BaseStripeClientInterface
{
/**
* Gets the API key used by the client to send requests.
*
* @return null|string the API key used by the client to send requests
*/
public function getApiKey();

/**
* Gets the client ID used by the client in OAuth requests.
*
* @return null|string the client ID used by the client in OAuth requests
*/
public function getClientId();

/**
* Gets the base URL for Stripe's API.
*
* @return string the base URL for Stripe's API
*/
public function getApiBase();

/**
* Gets the base URL for Stripe's OAuth API.
*
* @return string the base URL for Stripe's OAuth API
*/
public function getConnectBase();

/**
* Gets the base URL for Stripe's Files API.
*
* @return string the base URL for Stripe's Files API
*/
public function getFilesBase();
}
2 changes: 1 addition & 1 deletion lib/HttpClient/CurlClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
\define('CURL_HTTP_VERSION_2TLS', 4);
}

class CurlClient implements ClientInterface
class CurlClient implements ClientInterface, StreamingClientInterface
{
protected static $instance;

Expand Down
23 changes: 23 additions & 0 deletions lib/HttpClient/StreamingClientInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Stripe\HttpClient;

interface StreamingClientInterface
{
/**
* @param string $method The HTTP method being used
* @param string $absUrl The URL being requested, including domain and protocol
* @param array $headers Headers to be used in the request (full strings, not KV pairs)
* @param array $params KV pairs for parameters. Can be nested for arrays and hashes
* @param bool $hasFile Whether or not $params references a file (via an @ prefix or
* CURLFile)
* @param callable $readBodyChunkCallable a function that will be called with chunks of bytes from the body if the request is successful
*
* @throws \Stripe\Exception\ApiConnectionException
* @throws \Stripe\Exception\UnexpectedValueException
*
* @return array an array whose first element is raw request body, second
* element is HTTP status code and third array of HTTP headers
*/
public function requestStream($method, $absUrl, $headers, $params, $hasFile, $readBodyChunkCallable);
}
21 changes: 21 additions & 0 deletions lib/Service/AbstractService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ abstract class AbstractService
*/
protected $client;

/**
* @var \Stripe\StripeStreamingClientInterface
*/
protected $streamingClient;

/**
* Initializes a new instance of the {@link AbstractService} class.
*
Expand All @@ -20,6 +25,7 @@ abstract class AbstractService
public function __construct($client)
{
$this->client = $client;
$this->streamingClient = $client;
}

/**
Expand All @@ -32,6 +38,16 @@ public function getClient()
return $this->client;
}

/**
* Gets the client used by this service to send requests.
*
* @return \Stripe\StripeStreamingClientInterface
*/
public function getStreamingClient()
{
return $this->streamingClient;
}

/**
* Translate null values to empty strings. For service methods,
* we interpret null as a request to unset the field, which
Expand Down Expand Up @@ -59,6 +75,11 @@ protected function request($method, $path, $params, $opts)
return $this->getClient()->request($method, $path, static::formatParams($params), $opts);
}

protected function requestStream($method, $path, $readBodyChunkCallable, $params, $opts)
{
return $this->getStreamingClient()->requestStream($method, $path, $readBodyChunkCallable, static::formatParams($params), $opts);
}

protected function requestCollection($method, $path, $params, $opts)
{
return $this->getClient()->requestCollection($method, $path, static::formatParams($params), $opts);
Expand Down
37 changes: 1 addition & 36 deletions lib/StripeClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,8 @@
/**
* Interface for a Stripe client.
*/
interface StripeClientInterface
interface StripeClientInterface extends BaseStripeClientInterface
{
/**
* Gets the API key used by the client to send requests.
*
* @return null|string the API key used by the client to send requests
*/
public function getApiKey();

/**
* Gets the client ID used by the client in OAuth requests.
*
* @return null|string the client ID used by the client in OAuth requests
*/
public function getClientId();

/**
* Gets the base URL for Stripe's API.
*
* @return string the base URL for Stripe's API
*/
public function getApiBase();

/**
* Gets the base URL for Stripe's OAuth API.
*
* @return string the base URL for Stripe's OAuth API
*/
public function getConnectBase();

/**
* Gets the base URL for Stripe's Files API.
*
* @return string the base URL for Stripe's Files API
*/
public function getFilesBase();

/**
* Sends a request to Stripe's API.
*
Expand Down
11 changes: 11 additions & 0 deletions lib/StripeStreamingClientInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Stripe;

/**
* Interface for a Stripe client.
*/
interface StripeStreamingClientInterface extends BaseStripeClientInterface
{
public function requestStream($method, $path, $readBodyChunkCallable, $params, $opts);
}
2 changes: 1 addition & 1 deletion lib/Util/RequestOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public function discardNonPersistentHeaders()
public static function parse($options, $strict = false)
{
if ($options instanceof self) {
return $options;
return clone $options;
}

if (null === $options) {
Expand Down
Loading

0 comments on commit 33317c9

Please sign in to comment.