1
0
mirror of https://github.com/danog/amp.git synced 2024-11-26 20:15:00 +01:00

Add TimeoutCancellationToken

This commit is contained in:
Aaron Piotrowski 2017-06-13 12:41:47 -05:00
parent 5d9cf8a11d
commit 5f3e21a4a4
4 changed files with 107 additions and 2 deletions

View File

@ -117,13 +117,16 @@ final class CancellationTokenSource {
return $this->token;
}
public function cancel() {
/**
* @param \Throwable|null $previous Exception to be used as the previous exception to CancelledException.
*/
public function cancel(\Throwable $previous = null) {
if ($this->onCancel === null) {
return;
}
$onCancel = $this->onCancel;
$this->onCancel = null;
$onCancel(new CancelledException);
$onCancel(new CancelledException($previous));
}
}

View File

@ -9,4 +9,7 @@ namespace Amp;
* @see CancellationTokenSource
*/
class CancelledException extends \Exception {
public function __construct(\Throwable $previous = null) {
parent::__construct("The operation was cancelled", 0, $previous);
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace Amp;
/**
* A TimeoutCancellationToken automatically requests cancellation after the timeout has elapsed.
*/
final class TimeoutCancellationToken implements CancellationToken {
/** @var string */
private $watcher;
/** @var \Amp\CancellationToken */
private $token;
/**
* @param int $timeout Milliseconds until cancellation is requested.
*/
public function __construct(int $timeout) {
$source = new CancellationTokenSource;
$this->token = $source->getToken();
$this->watcher = Loop::delay($timeout, static function () use ($source) {
$source->cancel(new TimeoutException);
});
Loop::unreference($this->watcher);
}
/**
* Cancels the delay watcher.
*/
public function __destruct() {
Loop::cancel($this->watcher);
}
/**
* {@inheritdoc}
*/
public function subscribe(callable $callback): string {
return $this->token->subscribe($callback);
}
/**
* {@inheritdoc}
*/
public function unsubscribe(string $id) {
$this->token->unsubscribe($id);
}
/**
* {@inheritdoc}
*/
public function isRequested(): bool {
return $this->token->isRequested();
}
/**
* {@inheritdoc}
*/
public function throwIfRequested() {
$this->token->throwIfRequested();
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Amp\Test;
use Amp\CancelledException;
use Amp\Delayed;
use Amp\Loop;
use Amp\PHPUnit\TestCase;
use Amp\TimeoutCancellationToken;
use Amp\TimeoutException;
class TimeoutCancellationTokenTest extends TestCase {
public function testTimeout() {
Loop::run(function () {
$token = new TimeoutCancellationToken(10);
$this->assertFalse($token->isRequested());
yield new Delayed(20);
$this->assertTrue($token->isRequested());
try {
$token->throwIfRequested();
} catch (CancelledException $exception) {
$this->assertInstanceOf(TimeoutException::class, $exception->getPrevious());
}
});
}
public function testWatcherCancellation() {
Loop::run(function () {
$token = new TimeoutCancellationToken(1);
$this->assertSame(1, Loop::getInfo()["delay"]["enabled"]);
unset($token);
$this->assertSame(0, Loop::getInfo()["delay"]["enabled"]);
});
}
}