/** * Completes the observable with the given value. * * @param mixed $value */ public function complete($value = null) { if (null !== $this->started) { $this->started->reject(new CompletedError()); } $this->delayed->resolve($value); }
/** * Marks the observable as complete. * * @param mixed $value Observable return value. */ public function complete($value) { if (null === $this->observable) { return; } $this->observable = null; $this->delayed->resolve($value); }
/** * Closes the stream and rejects any pending promises. * * @param \Throwable|null $exception */ protected function free(\Throwable $exception = null) { $this->readable = false; $this->writable = false; if (null !== $this->delayed) { $this->delayed->resolve(''); } if (0 !== $this->hwm) { while (!$this->queue->isEmpty()) { /** @var \Icicle\Awaitable\Delayed $delayed */ $delayed = $this->queue->shift(); $delayed->reject($exception = $exception ?: new ClosedException('The stream was unexpectedly closed.')); } } }
/** * @throws \Icicle\Concurrent\Exception\ProcessException If starting the process fails. * @throws \Icicle\Concurrent\Exception\StatusError If the process is already running. */ public function start() { if (null !== $this->delayed) { throw new StatusError('The process has already been started.'); } $this->delayed = new Delayed(); $fd = [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'a'], ['pipe', 'w']]; $nd = 0 === strncasecmp(PHP_OS, 'WIN', 3) ? 'NUL' : '/dev/null'; $command = sprintf('(%s) 3>%s; code=$?; echo $code >&3; exit $code', $this->command, $nd); $this->process = proc_open($command, $fd, $pipes, $this->cwd ?: null, $this->env ?: null, $this->options); if (!is_resource($this->process)) { throw new ProcessException('Could not start process.'); } $this->oid = getmypid(); $status = proc_get_status($this->process); if (!$status) { proc_close($this->process); $this->process = null; throw new ProcessException('Could not get process status.'); } $this->pid = $status['pid']; $this->stdin = new WritablePipe($pipes[0]); $this->stdout = new ReadablePipe($pipes[1]); $this->stderr = new ReadablePipe($pipes[2]); $stream = $pipes[3]; stream_set_blocking($stream, 0); $this->poll = Loop\poll($stream, function ($resource) { if (!is_resource($resource) || feof($resource)) { $this->close($resource); $this->delayed->reject(new ProcessException('Process ended unexpectedly.')); } else { $code = fread($resource, 1); $this->close($resource); if (!strlen($code) || !is_numeric($code)) { $this->delayed->reject(new ProcessException('Process ended without providing a status code.')); } else { $this->delayed->resolve((int) $code); } } $this->poll->free(); }); }
/** * Notifies the placeholder that the consumer is ready. */ public function ready() { if (0 === --$this->waiting) { $this->delayed->resolve(); } }
/** * Returns an observable that emits a value every $interval seconds, up to $count times (or indefinitely if $count * is 0). The value emitted is an integer of the number of times the observable emitted a value. * * @param float|int $interval Time interval between emitted values in seconds. * @param int $count Use 0 to emit values indefinitely. * * @return \Icicle\Observable\Observable */ function interval(float $interval, int $count = 0) : Observable { return new Emitter(function (callable $emit) use($interval, $count) : \Generator { if (0 > $count) { throw new InvalidArgumentError('The number of times to emit must be a non-negative value.'); } $start = microtime(true); $i = 0; $delayed = new Delayed(); $timer = Loop\periodic($interval, function () use(&$delayed, &$i) { $delayed->resolve(++$i); $delayed = new Delayed(); }); try { while (0 === $count || $i < $count) { yield from $emit($delayed); } } finally { $timer->stop(); } return microtime(true) - $start; }); }
/** * Completes the observable with the given value. * * @param mixed $value */ public function complete($value = null) { $this->delayed->resolve($value); }