Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add streaming methods to Service infra #1155

Merged
merged 5 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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