Generify promises
This commit is contained in:
parent
20bee94175
commit
ee2e8fcc23
5 changed files with 232 additions and 225 deletions
88
src/Appwrite/GraphQL/Promises/Adapter.php
Normal file
88
src/Appwrite/GraphQL/Promises/Adapter.php
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Appwrite\GraphQL\Promises;
|
||||||
|
|
||||||
|
use Appwrite\Promises\Promise;
|
||||||
|
use GraphQL\Executor\Promise\Promise as GQLPromise;
|
||||||
|
use GraphQL\Executor\Promise\PromiseAdapter;
|
||||||
|
|
||||||
|
abstract class Adapter implements PromiseAdapter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns true if the given value is a {@see Promise}.
|
||||||
|
*
|
||||||
|
* @param $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isThenable($value): bool
|
||||||
|
{
|
||||||
|
return $value instanceof Promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@see Promise} into a {@see GQLPromise}
|
||||||
|
*
|
||||||
|
* @param mixed $thenable
|
||||||
|
* @return GQLPromise
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function convertThenable(mixed $thenable): GQLPromise
|
||||||
|
{
|
||||||
|
if (!$thenable instanceof Promise) {
|
||||||
|
throw new \Exception('Expected instance of Promise got: ' . \gettype($thenable));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GQLPromise($thenable, $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise that resolves when the passed in promise resolves.
|
||||||
|
*
|
||||||
|
* @param GQLPromise $promise
|
||||||
|
* @param callable|null $onFulfilled
|
||||||
|
* @param callable|null $onRejected
|
||||||
|
* @return GQLPromise
|
||||||
|
*/
|
||||||
|
public function then(
|
||||||
|
GQLPromise $promise,
|
||||||
|
?callable $onFulfilled = null,
|
||||||
|
?callable $onRejected = null
|
||||||
|
): GQLPromise {
|
||||||
|
/** @var Promise $adoptedPromise */
|
||||||
|
$adoptedPromise = $promise->adoptedPromise;
|
||||||
|
|
||||||
|
return new GQLPromise($adoptedPromise->then($onFulfilled, $onRejected), $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new promise with the given resolver function.
|
||||||
|
*
|
||||||
|
* @param callable $resolver
|
||||||
|
* @return GQLPromise
|
||||||
|
*/
|
||||||
|
abstract public function create(callable $resolver): GQLPromise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new promise that is fulfilled with the given value.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @return GQLPromise
|
||||||
|
*/
|
||||||
|
abstract public function createFulfilled(mixed $value = null): GQLPromise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new promise that is rejected with the given reason.
|
||||||
|
*
|
||||||
|
* @param mixed $reason
|
||||||
|
* @return GQLPromise
|
||||||
|
*/
|
||||||
|
abstract public function createRejected(mixed $reason): GQLPromise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new promise that resolves when all passed in promises resolve.
|
||||||
|
*
|
||||||
|
* @param array $promisesOrValues
|
||||||
|
* @return GQLPromise
|
||||||
|
*/
|
||||||
|
abstract public function all(array $promisesOrValues): GQLPromise;
|
||||||
|
}
|
41
src/Appwrite/GraphQL/Promises/Adapter/Swoole.php
Normal file
41
src/Appwrite/GraphQL/Promises/Adapter/Swoole.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Appwrite\GraphQL\Promises\Adapter;
|
||||||
|
|
||||||
|
use Appwrite\GraphQL\Promises\Adapter;
|
||||||
|
use GraphQL\Executor\Promise\Promise as GQLPromise;
|
||||||
|
|
||||||
|
class Swoole extends Adapter
|
||||||
|
{
|
||||||
|
public function create(callable $resolver): GQLPromise
|
||||||
|
{
|
||||||
|
$promise = new Swoole(function ($resolve, $reject) use ($resolver) {
|
||||||
|
$resolver($resolve, $reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new GQLPromise($promise, $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createFulfilled($value = null): GQLPromise
|
||||||
|
{
|
||||||
|
$promise = new Swoole(function ($resolve, $reject) use ($value) {
|
||||||
|
$resolve($value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new GQLPromise($promise, $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createRejected($reason): GQLPromise
|
||||||
|
{
|
||||||
|
$promise = new Swoole(function ($resolve, $reject) use ($reason) {
|
||||||
|
$reject($reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new GQLPromise($promise, $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(array $promisesOrValues): GQLPromise
|
||||||
|
{
|
||||||
|
return new GQLPromise(Swoole::all($promisesOrValues), $this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,147 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Appwrite\GraphQL\Promises;
|
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
|
||||||
use GraphQL\Executor\Promise\Promise;
|
|
||||||
use GraphQL\Executor\Promise\PromiseAdapter;
|
|
||||||
use GraphQL\Utils\Utils;
|
|
||||||
use Swoole\Coroutine\Channel;
|
|
||||||
|
|
||||||
class CoroutinePromiseAdapter implements PromiseAdapter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns true if the given value is a {@see CoroutinePromise}.
|
|
||||||
*
|
|
||||||
* @param $value
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isThenable($value): bool
|
|
||||||
{
|
|
||||||
return $value instanceof CoroutinePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a {@see CoroutinePromise} into a {@see Promise}
|
|
||||||
*
|
|
||||||
* @param $thenable
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
public function convertThenable($thenable): Promise
|
|
||||||
{
|
|
||||||
if (!$thenable instanceof CoroutinePromise) {
|
|
||||||
throw new InvariantViolation('Expected instance of CoroutinePromise, got ' . Utils::printSafe($thenable));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise($thenable, $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a promise that resolves when the passed in promise resolves.
|
|
||||||
*
|
|
||||||
* @param Promise $promise
|
|
||||||
* @param callable|null $onFulfilled
|
|
||||||
* @param callable|null $onRejected
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
public function then(Promise $promise, ?callable $onFulfilled = null, ?callable $onRejected = null): Promise
|
|
||||||
{
|
|
||||||
/** @var CoroutinePromise $adoptedPromise */
|
|
||||||
$adoptedPromise = $promise->adoptedPromise;
|
|
||||||
|
|
||||||
return new Promise($adoptedPromise->then($onFulfilled, $onRejected), $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new promise with the given resolver function.
|
|
||||||
*
|
|
||||||
* @param callable $resolver
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
public function create(callable $resolver): Promise
|
|
||||||
{
|
|
||||||
$promise = new CoroutinePromise(function ($resolve, $reject) use ($resolver) {
|
|
||||||
$resolver($resolve, $reject);
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Promise($promise, $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new promise that is fulfilled with the given value.
|
|
||||||
*
|
|
||||||
* @param $value
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
public function createFulfilled($value = null): Promise
|
|
||||||
{
|
|
||||||
$promise = new CoroutinePromise(function ($resolve, $reject) use ($value) {
|
|
||||||
$resolve($value);
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Promise($promise, $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new promise that is rejected with the given reason.
|
|
||||||
*
|
|
||||||
* @param $reason
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
public function createRejected($reason): Promise
|
|
||||||
{
|
|
||||||
$promise = new CoroutinePromise(function ($resolve, $reject) use ($reason) {
|
|
||||||
$reject($reason);
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Promise($promise, $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new promise that resolves when all passed in promises resolve.
|
|
||||||
*
|
|
||||||
* @param array $promisesOrValues
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
public function all(array $promisesOrValues): Promise
|
|
||||||
{
|
|
||||||
$all = new CoroutinePromise(function (callable $resolve, callable $reject) use ($promisesOrValues) {
|
|
||||||
$ticks = count($promisesOrValues);
|
|
||||||
$firstError = null;
|
|
||||||
$channel = new Channel($ticks);
|
|
||||||
$result = [];
|
|
||||||
$key = 0;
|
|
||||||
|
|
||||||
foreach ($promisesOrValues as $promiseOrValue) {
|
|
||||||
if (!$promiseOrValue instanceof Promise) {
|
|
||||||
$result[$key] = $promiseOrValue;
|
|
||||||
$channel->push(true);
|
|
||||||
}
|
|
||||||
$promiseOrValue->then(function ($value) use ($key, &$result, $channel) {
|
|
||||||
$result[$key] = $value;
|
|
||||||
$channel->push(true);
|
|
||||||
}, function ($error) use ($channel, &$firstError) {
|
|
||||||
$channel->push(true);
|
|
||||||
if ($firstError === null) {
|
|
||||||
$firstError = $error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$key++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ($ticks--) {
|
|
||||||
$channel->pop();
|
|
||||||
}
|
|
||||||
$channel->close();
|
|
||||||
|
|
||||||
if ($firstError !== null) {
|
|
||||||
$reject($firstError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$resolve($result);
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Promise($all, $this);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Appwrite\GraphQL\Promises;
|
namespace Appwrite\Promises;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
abstract class Promise
|
||||||
use GraphQL\Executor\Promise\Promise;
|
|
||||||
use GraphQL\Utils\Utils;
|
|
||||||
use Swoole\Coroutine\Channel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inspired by https://github.com/streamcommon/promise/blob/master/lib/ExtSwoolePromise.php
|
|
||||||
*
|
|
||||||
* @package Appwrite\GraphQL
|
|
||||||
*/
|
|
||||||
class CoroutinePromise
|
|
||||||
{
|
{
|
||||||
protected const STATE_PENDING = 1;
|
protected const STATE_PENDING = 1;
|
||||||
protected const STATE_FULFILLED = 0;
|
protected const STATE_FULFILLED = 0;
|
||||||
|
@ -35,22 +25,22 @@ class CoroutinePromise
|
||||||
$this->setResult($value);
|
$this->setResult($value);
|
||||||
$this->setState(self::STATE_REJECTED);
|
$this->setState(self::STATE_REJECTED);
|
||||||
};
|
};
|
||||||
\go(function () use ($executor, $resolve, $reject) {
|
$this->execute($executor, $resolve, $reject);
|
||||||
try {
|
|
||||||
$executor($resolve, $reject);
|
|
||||||
} catch (\Throwable $exception) {
|
|
||||||
$reject($exception);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract protected function execute(
|
||||||
|
callable $executor,
|
||||||
|
callable $resolve,
|
||||||
|
callable $reject
|
||||||
|
): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new promise from the given callable.
|
* Create a new promise from the given callable.
|
||||||
*
|
*
|
||||||
* @param callable $promise
|
* @param callable $promise
|
||||||
* @return CoroutinePromise
|
* @return self
|
||||||
*/
|
*/
|
||||||
final public static function create(callable $promise): CoroutinePromise
|
public static function create(callable $promise): self
|
||||||
{
|
{
|
||||||
return new static($promise);
|
return new static($promise);
|
||||||
}
|
}
|
||||||
|
@ -59,9 +49,9 @@ class CoroutinePromise
|
||||||
* Resolve promise with given value.
|
* Resolve promise with given value.
|
||||||
*
|
*
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @return CoroutinePromise
|
* @return self
|
||||||
*/
|
*/
|
||||||
final public static function resolve(mixed $value): CoroutinePromise
|
public static function resolve(mixed $value): self
|
||||||
{
|
{
|
||||||
return new static(function (callable $resolve) use ($value) {
|
return new static(function (callable $resolve) use ($value) {
|
||||||
$resolve($value);
|
$resolve($value);
|
||||||
|
@ -72,9 +62,9 @@ class CoroutinePromise
|
||||||
* Rejects the promise with the given reason.
|
* Rejects the promise with the given reason.
|
||||||
*
|
*
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @return CoroutinePromise
|
* @return self
|
||||||
*/
|
*/
|
||||||
final public static function reject(mixed $value): CoroutinePromise
|
public static function reject(mixed $value): self
|
||||||
{
|
{
|
||||||
return new static(function (callable $resolve, callable $reject) use ($value) {
|
return new static(function (callable $resolve, callable $reject) use ($value) {
|
||||||
$reject($value);
|
$reject($value);
|
||||||
|
@ -85,9 +75,9 @@ class CoroutinePromise
|
||||||
* Catch any exception thrown by the executor.
|
* Catch any exception thrown by the executor.
|
||||||
*
|
*
|
||||||
* @param callable $onRejected
|
* @param callable $onRejected
|
||||||
* @return CoroutinePromise
|
* @return self
|
||||||
*/
|
*/
|
||||||
final public function catch(callable $onRejected): CoroutinePromise
|
public function catch(callable $onRejected): self
|
||||||
{
|
{
|
||||||
return $this->then(null, $onRejected);
|
return $this->then(null, $onRejected);
|
||||||
}
|
}
|
||||||
|
@ -97,10 +87,12 @@ class CoroutinePromise
|
||||||
*
|
*
|
||||||
* @param callable|null $onFulfilled
|
* @param callable|null $onFulfilled
|
||||||
* @param callable|null $onRejected
|
* @param callable|null $onRejected
|
||||||
* @return CoroutinePromise
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function then(?callable $onFulfilled = null, ?callable $onRejected = null): CoroutinePromise
|
public function then(
|
||||||
{
|
?callable $onFulfilled = null,
|
||||||
|
?callable $onRejected = null
|
||||||
|
): self {
|
||||||
if ($this->isRejected() && $onRejected === null) {
|
if ($this->isRejected() && $onRejected === null) {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -127,49 +119,10 @@ class CoroutinePromise
|
||||||
/**
|
/**
|
||||||
* Returns a promise that completes when all passed in promises complete.
|
* Returns a promise that completes when all passed in promises complete.
|
||||||
*
|
*
|
||||||
* @param iterable|CoroutinePromise[] $promises
|
* @param iterable|self[] $promises
|
||||||
* @return CoroutinePromise
|
* @return self
|
||||||
*/
|
*/
|
||||||
public static function all(iterable $promises): CoroutinePromise
|
abstract public static function all(iterable $promises): self;
|
||||||
{
|
|
||||||
return self::create(function (callable $resolve, callable $reject) use ($promises) {
|
|
||||||
$ticks = count($promises);
|
|
||||||
|
|
||||||
$firstError = null;
|
|
||||||
$channel = new Channel($ticks);
|
|
||||||
$result = [];
|
|
||||||
$key = 0;
|
|
||||||
|
|
||||||
foreach ($promises as $promise) {
|
|
||||||
if (!$promise instanceof CoroutinePromise) {
|
|
||||||
$channel->close();
|
|
||||||
throw new InvariantViolation('Expected instance of CoroutinePromise, got ' . Utils::printSafe($promise));
|
|
||||||
}
|
|
||||||
$promise->then(function ($value) use ($key, &$result, $channel) {
|
|
||||||
$result[$key] = $value;
|
|
||||||
$channel->push(true);
|
|
||||||
return $value;
|
|
||||||
}, function ($error) use ($channel, &$firstError) {
|
|
||||||
$channel->push(true);
|
|
||||||
if ($firstError === null) {
|
|
||||||
$firstError = $error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$key++;
|
|
||||||
}
|
|
||||||
while ($ticks--) {
|
|
||||||
$channel->pop();
|
|
||||||
}
|
|
||||||
$channel->close();
|
|
||||||
|
|
||||||
if ($firstError !== null) {
|
|
||||||
$reject($firstError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$resolve($result);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set resolved result
|
* Set resolved result
|
||||||
|
@ -177,18 +130,20 @@ class CoroutinePromise
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function setResult(mixed $value): void
|
protected function setResult(mixed $value): void
|
||||||
{
|
{
|
||||||
if (!$value instanceof Promise) {
|
if (!$value instanceof self) {
|
||||||
$this->result = $value;
|
$this->result = $value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$resolved = false;
|
$resolved = false;
|
||||||
|
|
||||||
$callable = function ($value) use (&$resolved) {
|
$callable = function ($value) use (&$resolved) {
|
||||||
$this->setResult($value);
|
$this->setResult($value);
|
||||||
$resolved = true;
|
$resolved = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
$value->then($callable, $callable);
|
$value->then($callable, $callable);
|
||||||
|
|
||||||
while (!$resolved) {
|
while (!$resolved) {
|
||||||
|
@ -202,7 +157,7 @@ class CoroutinePromise
|
||||||
* @param integer $state
|
* @param integer $state
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
final protected function setState(int $state): void
|
protected function setState(int $state): void
|
||||||
{
|
{
|
||||||
$this->state = $state;
|
$this->state = $state;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +167,7 @@ class CoroutinePromise
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
final protected function isPending(): bool
|
protected function isPending(): bool
|
||||||
{
|
{
|
||||||
return $this->state == self::STATE_PENDING;
|
return $this->state == self::STATE_PENDING;
|
||||||
}
|
}
|
||||||
|
@ -222,7 +177,7 @@ class CoroutinePromise
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
final protected function isFulfilled(): bool
|
protected function isFulfilled(): bool
|
||||||
{
|
{
|
||||||
return $this->state == self::STATE_FULFILLED;
|
return $this->state == self::STATE_FULFILLED;
|
||||||
}
|
}
|
||||||
|
@ -232,7 +187,7 @@ class CoroutinePromise
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
final protected function isRejected(): bool
|
protected function isRejected(): bool
|
||||||
{
|
{
|
||||||
return $this->state == self::STATE_REJECTED;
|
return $this->state == self::STATE_REJECTED;
|
||||||
}
|
}
|
70
src/Appwrite/Promises/Swoole.php
Normal file
70
src/Appwrite/Promises/Swoole.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Appwrite\Promises;
|
||||||
|
|
||||||
|
use Swoole\Coroutine\Channel;
|
||||||
|
|
||||||
|
class Swoole extends Promise
|
||||||
|
{
|
||||||
|
public function __construct(?callable $executor = null)
|
||||||
|
{
|
||||||
|
parent::__construct($executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(
|
||||||
|
callable $executor,
|
||||||
|
callable $resolve,
|
||||||
|
callable $reject
|
||||||
|
): void {
|
||||||
|
\go(function () use ($executor, $resolve, $reject) {
|
||||||
|
try {
|
||||||
|
$executor($resolve, $reject);
|
||||||
|
} catch (\Throwable $exception) {
|
||||||
|
$reject($exception);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise that completes when all passed in promises complete.
|
||||||
|
*
|
||||||
|
* @param iterable|Swoole[] $promises
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
public static function all(iterable $promises): Promise
|
||||||
|
{
|
||||||
|
return self::create(function (callable $resolve, callable $reject) use ($promises) {
|
||||||
|
$ticks = count($promises);
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
$error = null;
|
||||||
|
$channel = new Channel($ticks);
|
||||||
|
$key = 0;
|
||||||
|
|
||||||
|
foreach ($promises as $promise) {
|
||||||
|
$promise->then(function ($value) use ($key, &$result, $channel) {
|
||||||
|
$result[$key] = $value;
|
||||||
|
$channel->push(true);
|
||||||
|
return $value;
|
||||||
|
}, function ($err) use ($channel, &$error) {
|
||||||
|
$channel->push(true);
|
||||||
|
if ($error === null) {
|
||||||
|
$error = $err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$key++;
|
||||||
|
}
|
||||||
|
while ($ticks--) {
|
||||||
|
$channel->pop();
|
||||||
|
}
|
||||||
|
$channel->close();
|
||||||
|
|
||||||
|
if ($error !== null) {
|
||||||
|
$reject($error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolve($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue