public function write(string $bytes) : Awaitable { if ($bytes === '') { if (!\is_resource($this->socket)) { return new Failure(new StreamClosedException('Socket resource unavailable')); } return new Success(0); } $len = \strlen($bytes); if (!$this->writerEnabled) { try { $bytes = $this->writeBytes($bytes); } catch (\Throwable $e) { return new Failure($e); } if ($bytes === '') { return new Success($len); } $this->writerEnabled = true; if ($this->pendingWrites === null) { $this->pendingWrites = new \SplQueue(); } if ($this->writeWatcher === null) { $this->writeWatcher = Loop::onWritable($this->socket, $this->createWriteWatcher()); } else { try { Loop::enable($this->writeWatcher); } catch (InvalidWatcherException $e) { $this->writeWatcher = Loop::onWritable($this->socket, $this->createWriteWatcher()); } } if (!$this->writerReferenced) { Loop::unreference($this->writeWatcher); } } $this->pendingWrites->enqueue($write = new PendingWrite($bytes, $len, function () { foreach ($this->pendingWrites as $write) { if (!$write->disabled) { return; } } $this->writerEnabled = false; Loop::disable($this->writeWatcher); })); return $write; }
public function read(int $length = 8192) : Awaitable { if (!$this->readerEnabled) { $len = \strlen($this->readBuffer); try { $chunk = $this->fillReadBuffer($len, $length); } catch (\Throwable $e) { return new Failure($e); } if ($chunk === null) { return new Success(null); } if ($chunk !== $this) { if ($len > $length) { $this->readBuffer = \substr($chunk, $length); return new Success(\substr($chunk, 0, $length)); } $this->readBuffer = ''; return new Success($chunk); } $this->readerEnabled = true; if ($this->pendingReads === null) { $this->pendingReads = new \SplQueue(); } if ($this->readWatcher === null) { $this->readWatcher = Loop::onReadable($this->socket, $this->createReadWatcher()); } else { try { Loop::enable($this->readWatcher); } catch (InvalidWatcherException $e) { $this->readWatcher = Loop::onReadable($this->socket, $this->createReadWatcher()); } } } $this->pendingReads->enqueue($read = new PendingRead($length, function () { foreach ($this->pendingReads as $read) { if (!$read->disabled) { return; } } $this->readerEnabled = false; Loop::disable($this->readWatcher); })); return $read; }
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; }