public function when(callable $onResolved) { try { $onResolved($this->error); } catch (\Throwable $e) { Loop::defer(function () use($e) { throw $e; }); } }
/** * {@inheritdoc} */ public function when(callable $onResolved) { try { $onResolved($this->exception, null); } catch (\Throwable $exception) { Loop::defer(static function () use($exception) { throw $exception; }); } }
protected function runServer(callable $server, callable $client) : \Generator { $socket = (yield $this->serverFactory->createSocketServer()); try { return (yield new AwaitAll([new Coroutine($this->serverTask($socket, $server)), new Coroutine($this->clientTask($socket, $client))])); } finally { Loop::defer(function () use($socket) { $socket->close(); }); } }
/** * Calls each callback in the queue, passing the provided values to the function. * * @param \Throwable|null $exception * @param mixed $value */ public function __invoke($exception, $value) { foreach ($this->queue as $callback) { try { $callback($exception, $value); } catch (\Throwable $exception) { Loop::defer(static function () use($exception) { throw $exception; }); } } }
/** * @param callable(callable(mixed $value): Promise $emit): \Generator $emitter * * @throws \Error Thrown if the callable does not return a Generator. */ public function __construct(callable $emitter) { $result = $emitter($this->callableFromInstanceMethod("emit")); if (!$result instanceof \Generator) { throw new \Error("The callable did not return a Generator"); } Loop::defer(function () use($result) { $coroutine = new Coroutine($result); $coroutine->when(function ($exception, $value) { if ($this->resolved) { return; } if ($exception) { $this->fail($exception); return; } $this->resolve($value); }); }); }
/** * Internal resolution * * @param $callback * * @throws \Exception|\Throwable */ private function resolve($callback) { try { $callback(); } catch (\Throwable $exception) { if ($this->hasActiveLoop()) { Loop::defer(static function () use($exception) { throw $exception; }); } throw $exception; } catch (\Exception $exception) { if ($this->hasActiveLoop()) { Loop::defer(static function () use($exception) { throw $exception; }); } throw $exception; } }
protected function advance($val) { while (($this->valid = $this->generator->valid()) && $val instanceof Promise) { $done = false; $val->when(function (\Throwable $e = null, $v = null) use(&$val, &$done) { if (!$this->valid || !self::$alive) { return; } if ($e) { $this->dispose($e); } elseif ($done) { $this->running = true; try { $this->advance($this->generator->send($v)); $this->running = false; if ($this->error) { $this->dispose($this->error); } } catch (\Throwable $e) { $this->running = false; $this->dispose($e); } } else { $done = true; $val = $v; } }); if (!$done || !self::$alive) { $done = true; $this->promise = $val; return; } $this->running = true; try { $val = $this->generator->send($val); $this->running = false; if ($this->error) { return $this->dispose($this->error); } } catch (\Throwable $e) { $this->running = false; return $this->dispose($e); } } if ($this->valid) { return Loop::defer(function ($id, $val) { if (!$this->valid || !self::$alive) { return; } $this->running = true; try { $this->advance($this->generator->send($val)); $this->running = false; if ($this->error) { $this->dispose($this->error); } } catch (\Throwable $e) { $this->running = false; $this->dispose($e); } }, $val); } if ($this->error) { return $this->dispose($this->error); } if ($this->state === self::PENDING) { $this->resolve($this->generator->getReturn()); } }
/** * Fail the awaitable with the given error. * * @param \Throwable $error * * @throws \RuntimeException If the awaitable has already been resolved or failed. */ protected function fail(\Throwable $error) { if ($this->state !== Awaitable::PENDING) { return; } $this->state = Awaitable::FAILED; $this->result = $error; if ($this->callbacks) { try { foreach ($this->callbacks as $callback) { try { $callback($error); } catch (\Throwable $ex) { Loop::defer(function () use($ex) { throw $ex; }); } } } finally { $this->callbacks = null; } } }
protected function dispose(\Throwable $e) { if ($this->promise) { $promise = $this->promise; $this->promise = null; Loop::defer(function () use($promise, $e) { $promise->cancel($e); }); } $this->error = null; while ($this->valid = $this->generator->valid() && self::$alive) { $this->running = true; try { return $this->advance($this->generator->throw($e)); } catch (\Throwable $e) { // Continue loop switching to the outer exception. } finally { $this->running = false; } } if (!self::$alive || !$this->valid && $this->state === Awaitable::PENDING) { $this->fail($e); } }