Пример #1
0
 /**
  * {@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;
 }
Пример #2
0
 /**
  * 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;
 }
Пример #3
0
 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;
 }
Пример #4
0
 /**
  * {@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;
 }
Пример #5
0
 /**
  * Helper method that collects errors thrown by promises into an array and allways resolves.
  * 
  * @param array $tasks
  * @param array $errors
  */
 protected function awaitFirstResult(array $tasks, array &$errors) : Awaitable
 {
     $await = new AwaitFirst($tasks);
     $defer = new Deferred(function (Deferred $defer, \Throwable $e) use($await) {
         $await->cancel($e);
     });
     $await->when(function (MultiReasonException $e = null, array $val = null) use($defer, &$errors) {
         if ($e) {
             foreach ($e->getReasons() as $error) {
                 $errors[] = $error;
             }
         }
         $defer->resolve($val);
     });
     return $defer;
 }
Пример #6
0
 /**
  * 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;
 }