WordPress / blueprints-library

32 stars 7 forks source link

Asynchronous HTTP Client Library #72

Closed adamziel closed 8 months ago

adamziel commented 8 months ago

Asynchronous HTTP Client Library

An asynchronous HTTP client library designed for WordPress. Main features:

Streaming support

Enqueuing a request returns a PHP resource that can be read by PHP functions like fopen() and stream_get_contents()

 $client = new AsyncHttpClient();
 $fp = $client->enqueue(
      new Request( "https://downloads.wordpress.org/plugin/gutenberg.17.7.0.zip" ),
 );
 // Read some data
 $first_4_kilobytes = fread($fp, 4096);
 // We've only waited for the first four kilobytes. The download
 // is still in progress at this point, and yet we're free to do
 // other work.

Delayed execution and concurrent downloads

The actual socket are not open until the first time the stream is read from:

 $client = new AsyncHttpClient();
 // Enqueuing the requests does not start the data transmission yet.
 $batch = $client->enqueue( [
     new Request( "https://downloads.wordpress.org/plugin/gutenberg.17.7.0.zip" ),
     new Request( "https://downloads.wordpress.org/theme/pendant.zip" ),
 ] );
 // Even though stream_get_contents() will return just the response body for
 // one request, it also opens the network sockets and starts streaming
 // both enqueued requests. The response data for $batch[1] is buffered.
 $gutenberg_zip = stream_get_contents( $batch[0] )

 // At least a chunk of the pendant.zip have already been downloaded, let's
 // wait for the rest of the data:
 $pendant_zip = stream_get_contents( $batch[1] )

Concurrency limits

The AsyncHttpClient will only keep up to $concurrency connections open. When one of the requests finishes, it will automatically start the next one.

For example:

 $client = new AsyncHttpClient();
 // Process at most 10 concurrent request at a time.
 $client->set_concurrency_limit( 10 );

Progress monitoring

A developer-provided callback (AsyncHttpClient->set_progress_callback()) receives progress information about every HTTP request.

 $client = new AsyncHttpClient();
 $client->set_progress_callback( function ( Request $request, $downloaded, $total ) {
      // $total is computed based on the Content-Length response header and
      // null if it's missing.
      echo "$request->url – Downloaded: $downloaded / $total\n";
 } );

HTTPS support

TLS connections work out of the box.

Non-blocking sockets

The act of opening each socket connection is non-blocking and happens nearly instantly. The streams themselves are also set to non-blocking mode via stream_set_blocking($fp, 0);

Asynchronous downloads

Start downloading now, do other work in your code, only block once you need the data.

PHP 7.0 support and no dependencies

AsyncHttpClient works on any WordPress installation with vanilla PHP only. It does not require any PHP extensions, CURL, or any external PHP libraries.

Supports custom request headers and body

Implementation details

Related issues

adamziel commented 8 months ago

Merged in https://github.com/WordPress/blueprints-library/commit/a9f10c13d27d92f9f343031c81486d7970f115b1