/** * {@inheritdoc} */ public function write(string $data) : Awaitable { if ($this->closed) { throw new StreamClosedException('Cannot write to closed stream'); } if ($data === '') { return new Success(0); } $write = $this->pool->invokeFunc('file_put_contents', $this->file, $data, \FILE_APPEND); $defer = new Deferred(function (Deferred $defer, \Throwable $e) use($write) { $write->cancel($e); }); $write->when(function (\Throwable $e = null, $val = null) use($defer) { if ($e) { $defer->fail(new StreamException('Failed to write data to stream', 0, $e)); } else { $defer->resolve($val); } }); return $defer; }
/** * Executes libuv callbacks and ensures that the loop keeps running until the callback has been invoked. * * Arguments must contain 1 closure that is assumed to be the callback being invoked by libuv. * * @param string $func The name of the uv function to be called. * @param mixed $args Arguments to be passed to the function. * @return mixed Value returned / error thrown by the passed callback. * * @throws \InvalidArgumentException When no callback argument has been passed. */ public function handleCallback(string $func, ...$args) : Awaitable { $defer = new Deferred(); $defer->when(function () { $this->watchersReferenced--; }); for ($len = \count($args), $i = 0; $i < $len; $i++) { if ($args[$i] instanceof \Closure) { $callback = $args[$i]; $args[$i] = function (...$args) use($defer, $callback) { try { $result = $callback(...$args); } catch (\Throwable $e) { return $defer->fail($e); } if ($result instanceof \Generator) { $defer->resolve(new Coroutine($result)); } else { $defer->resolve($result); } }; break; } } if (!isset($callback)) { return new Failure(new \InvalidArgumentException('Missing callback argument')); } $this->watchersReferenced++; try { $func(...\array_merge([$this->loop], $args)); } catch (\Throwable $e) { $this->watchersReferenced--; return new Failure($e); } return $defer; }
public function handleCallback(string $func, ...$args) : Awaitable { $request = null; $defer = new Deferred(function () use(&$request) { if (\is_resource($request)) { \eio_cancel($request); } }); $defer->when(function () { $this->pending--; if (!$this->pending) { Loop::disable($this->watcherId); } }); for ($len = \count($args), $i = 0; $i < $len; $i++) { if ($args[$i] instanceof \Closure) { $callback = $args[$i]; $args[$i] = function (...$args) use($defer, $callback) { try { $result = $callback(...$args); } catch (\Throwable $e) { return $defer->fail($e); } if ($result instanceof \Generator) { $defer->resolve(new Coroutine($result)); } else { $defer->resolve($result); } }; break; } } if (!isset($callback)) { throw new \InvalidArgumentException('Missing callback argument'); } if (!$this->pending) { if ($this->watcherId === null) { $this->watcherId = Loop::onReadable(self::$eio, self::$callback); } else { Loop::enable($this->watcherId); } } $this->pending++; try { $request = $func(...$args); } catch (\Throwable $e) { $this->pending--; if (!$this->pending) { Loop::disable($this->watcherId); } return new Failure($e); } return $defer; }
/** * {@inheritdoc} */ public function writeStream(string $path) : Awaitable { $awaitable = $this->pool->invokeStaticMethod(__CLASS__, 'writeFileCallback', $path); $defer = new Deferred(); $awaitable->when(function (\Throwable $e = null, $val = null) use($defer, $path) { if ($e instanceof PoolException) { $defer->fail($e->getPrevious()); } elseif ($e) { $defer->fail($e); } else { $defer->resolve(new WritableFileStream($this->pool, $path)); } }); return $defer; }
/** * Ping the remote endpoint. * * @return bool Returns true after pong frame has been received. */ public function ping() : Awaitable { $payload = \random_bytes(8); $defer = new Deferred(function () use($payload) { unset($this->pings[$payload]); }); $this->writer->writeFrame(new Frame(Frame::PING, $payload))->when(function (\Throwable $e = null) use($defer, $payload) { if ($e) { $defer->fail($e); } else { $this->pings[$payload] = $defer; } }); return $defer; }