Last active
November 23, 2021 06:46
-
-
Save MatteoOreficeIT/cf38a8a4c04bc71bf1557ee10fbea737 to your computer and use it in GitHub Desktop.
Integrating Guzzle 6 Asynchronous Requests with ReactPHP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Credits to : | |
* @see https://gist.github.com/psampaz/7f2aad5d1d54eeeec8ae | |
*/ | |
use GuzzleHttp\Handler\CurlMultiHandler; | |
use GuzzleHttp\HandlerStack; | |
use GuzzleHttp\Middleware; | |
use Psr\Http\Message\RequestInterface; | |
use Psr\Http\Message\ResponseInterface; | |
use React\EventLoop\LoopInterface; | |
use function GuzzleHttp\Promise\queue; | |
use function GuzzleHttp\choose_handler; | |
use React\EventLoop\StreamSelectLoop; | |
use React\EventLoop\TimerInterface; | |
use React\Promise\Deferred; | |
use GuzzleHttp\Promise\PromiseInterface as GuzzlePromise; | |
class ReactHandlerStack extends HandlerStack | |
{ | |
/** | |
* @var TimerInterface | |
*/ | |
protected $timer; | |
/** | |
* @var callable | |
*/ | |
protected $handlerRef; | |
/** | |
* @var LoopInterface | |
*/ | |
protected $loop; | |
public function __construct(callable $handler = null) | |
{ | |
$this->handlerRef = $handler; | |
parent::__construct($handler); | |
} | |
/** | |
* @param callable|null $handler | |
* @return HandlerStack|ReactHandlerStack | |
*/ | |
public static function create(callable $handler = null) | |
{ | |
$stack = new static($handler ?: choose_handler()); | |
$stack->push(Middleware::httpErrors(), 'http_errors'); | |
$stack->push(Middleware::redirect(), 'allow_redirects'); | |
$stack->push(Middleware::cookies(), 'cookies'); | |
$stack->push(Middleware::prepareBody(), 'prepare_body'); | |
return $stack; | |
} | |
public static function bindReactPhpPromiseTicker(LoopInterface $loop) | |
{ | |
return (self::create(new CurlMultiHandler()))->enableReactPhpPromiseTicker($loop); | |
} | |
/** | |
* Crea un HandlerStack che funziona con ReactPHP | |
* | |
* @param LoopInterface $loop | |
* @return HandlerStack | |
*/ | |
protected function enableReactPhpPromiseTicker(LoopInterface $loop) | |
{ | |
/** | |
* Avvia un timer ogni qualvolta parte una prima chiamata, quando le risposte arrivano | |
*/ | |
$this->push(function (callable $handler) use($loop) { | |
return function ( | |
RequestInterface $request, | |
array $options | |
) use ($handler,$loop) { | |
$that = $this; | |
if(!$this->timer) { | |
$this->timer = $loop->addPeriodicTimer($loop instanceof StreamSelectLoop ? 0 : 0.001,\Closure::bind(function($timer)use($that){ | |
$this->execute(); | |
$that->cancelTimer(); | |
},$this->handlerRef,$this->handlerRef)); | |
} | |
return $handler($request, $options); | |
}; | |
},'reactphp_promise_ticker'); | |
$this->setLoop($loop); | |
return $this; | |
} | |
/** | |
* @return LoopInterface | |
*/ | |
public function getLoop(): LoopInterface | |
{ | |
return $this->loop; | |
} | |
/** | |
* @param LoopInterface $loop | |
* @return ReactHandlerStack | |
*/ | |
public function setLoop(LoopInterface $loop): ReactHandlerStack | |
{ | |
$this->loop = $loop; | |
return $this; | |
} | |
public function cancelTimer() | |
{ | |
$this->loop->cancelTimer($this->timer); | |
$this->timer = null; | |
} | |
/** | |
* Dont ever mix GuzzlePromise with ReactPhpPromise !!! use instead this wrapper | |
* | |
* @param GuzzlePromise $promise | |
* @return Promise|\React\Promise\PromiseInterface | |
*/ | |
public static function guzzleToReactPromise(GuzzlePromise $promise) | |
{ | |
$deferred = new Deferred(); | |
$promise->then(function ($value) use($deferred){ | |
$deferred->resolve($value); | |
}, function ($error) use($deferred) { | |
$deferred->reject($error); | |
}); | |
return $deferred->promise(); | |
} | |
} |
I simplified the code, now the timer is going to be canceled when the execute() method ends, since the promise queue becomes empty
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
wow bellissimo.