public function current() { if ($this->isLastChunk) { return $this->applyChunkEncoding(''); } elseif (($current = $this->iterator->current()) === '') { return null; } elseif (is_string($current)) { return $this->applyChunkEncoding($current); } elseif ($current instanceof Promise) { $promisor = new Deferred(); $current->when(function ($error, $result) use($promisor) { if ($error) { $promisor->fail($error); } elseif (is_string($result)) { $promisor->succeed($this->applyChunkEncoding($result)); } else { $promisor->fail(new \DomainException(sprintf('Only string/Promise elements may be chunked; %s provided', gettype($result)))); } }); return $promisor->promise(); } else { // @TODO How to react to an invalid type returned from an iterator? return null; } }
private function requestNonce(string $uri) : Promise { $deferred = new Deferred(); $request = (new Request())->setMethod("HEAD")->setUri($uri); $this->http->request($request)->when(function (Throwable $error = null, Response $response = null) use($deferred) { if ($error) { $deferred->fail(new AcmeException("Couldn't fetch nonce!", $error)); } else { if (!$response->hasHeader("replay-nonce")) { $deferred->fail(new AcmeException("Server didn't send required replay-nonce header!")); } list($nonce) = $response->getHeader("replay-nonce"); $deferred->succeed($nonce); } }); return $deferred->promise(); }
public function save(string $id, array $data, int $ttl) : Promise { $promisor = new Deferred(); parent::save($id, $data, $ttl)->when(function ($error, $result) use($id, $data, $promisor) { if ($error) { $promisor->fail($error); } else { $data = json_encode($data); $this->client->publish("sess:update", "{$id} {$data}")->when(function ($error) use($result, $promisor) { if ($error) { $promisor->fail(new Exception("failed to publish update", 0, $error)); } else { $promisor->succeed($result); } }); } }); return $promisor->promise(); }
private function requestNonce($uri) { if (!is_string($uri)) { throw new InvalidArgumentException(sprintf("\$uri must be of type string, %s given.", gettype($uri))); } $deferred = new Deferred(); $request = (new Request())->setMethod("HEAD")->setUri($uri); $this->http->request($request)->when(function ($error = null, Response $response = null) use($deferred, $uri) { if ($error) { $deferred->fail(new AcmeException("HEAD request to {$uri} failed, could not obtain a replay nonce.", null, $error)); } else { if (!$response->hasHeader("replay-nonce")) { $deferred->fail(new AcmeException("HTTP response didn't carry replay-nonce header.")); } list($nonce) = $response->getHeader("replay-nonce"); $deferred->succeed($nonce); } }); return $deferred->promise(); }
/** * Return a key-value array of headers to add to the outbound request * * @return \Amp\Promise * @TODO */ public function getHeaders() { // @TODO Implement non-blocking php-uv header retrieval. // For now we'll just use the dumb blocking version. // v1.0.0 cannot be a thing until this is implemented. $promisor = new Deferred(); $this->getLength()->when(function ($error, $result) use($promisor) { if ($error) { $promisor->fail($error); } else { $promisor->succeed(['Content-Length' => $result]); } }); return $promisor->promise(); }
public function update(string $key, int $user, int $change) : Promise { $promisor = new Deferred(); $this->redis->hIncrBy($key, $user, $change)->when(function ($error, $result) use($key, $user, $promisor) { if ($error) { $promisor->fail($error); } else { if ($result) { $promisor->succeed($result); } else { $promisor->succeed(pipe($this->redis->hDel($key, $user), function () use($result) { return $result; })); } } }); return $promisor->promise(); }
/** @see 14.7.4 COM_STMT_PREPARE */ public function prepare($query, $data = null) { $promise = $this->startCommand(function () use($query) { $this->query = $query; $regex = <<<'REGEX' ("|'|`)((?:\\\\|\\\1|(?!\1).)*+)\1|(\?)|:([a-zA-Z_]+) REGEX; $index = 0; $query = preg_replace_callback("~{$regex}~ms", function ($m) use(&$index) { if (!isset($m[3])) { return $m[1] . $m[2] . $m[1]; } if ($m[3] !== "?") { $this->named[$m[4]][] = $index; } $index++; return "?"; }, $query); $this->sendPacket("{$query}"); $this->parseCallback = [$this, "handlePrepare"]; }); if ($data === null) { return $promise; } $retDeferred = new Deferred(); $promise->when(function ($error, $stmt) use($retDeferred, $data) { if ($error) { $retDeferred->fail($error); } else { try { $retDeferred->succeed($stmt->execute($data)); } catch (\Exception $e) { $retDeferred->fail($e); } } }); return $retDeferred->promise(); }
/** * Unlocks the session, reloads data without saving * @return \Amp\Promise resolving to an array with current session data */ public function unlock(string $id) : Promise { $token = $this->locks[$id] ?? ""; if (!$token) { return new Success(); } $promisor = new Deferred(); $this->mutex->unlock($id, $token)->when(function ($error) use($id, $promisor) { if ($error) { $promisor->fail(new Exception("couldn't unlock session", 0, $error)); } else { unset($this->locks[$id]); $promisor->succeed(); } }); return $promisor->promise(); }
/** * Saves and unlocks a session * @return \Amp\Promise resolving after success */ public function save() : Promise { if ($this->state !== self::LOCKED) { if ($this->state === self::PENDING) { throw new LockException("Session is not yet locked, wait until the Promise returned by Session::open() is resolved"); } else { throw new LockException("Session is not locked, can't write"); } } if (!$this->data) { return $this->destroy(); } $this->state = self::PENDING; if (!$this->id) { $this->setId($this->generateId()); } /* if we wait until "browser close", save the session for at most $config["maxlife"] (just to not have the sessions indefinitely...) */ $deferred = new Deferred(); $this->driver->save($this->id, $this->data, $this->ttl == -1 ? $this->maxlife : $this->ttl + 1)->when(function ($e) use($deferred) { if ($e) { $this->driver->read($this->id)->when(function ($unlockE, $data) use($deferred, $e) { $this->state = self::UNLOCKED; if ($unlockE) { $this->data = []; $deferred->fail($unlockE); } else { $this->data = $data; $deferred->fail($e); } }); } else { $this->saveConfig(); $this->state = self::UNLOCKED; $deferred->succeed($this); } }); return $deferred->promise(); }
/** * @param string $pattern * @return Promise */ public function pSubscribe($pattern) { $promisor = new Deferred(); $promise = $this->connection->send(["psubscribe", $pattern]); $promise->when(function ($error) use($pattern, $promisor) { if ($error) { $promisor->fail($error); } else { $this->patternPromisors[$pattern][] = $promisor; $promisor->promise()->when(function () use($pattern) { array_shift($this->patternPromisors[$pattern]); }); } }); return $promisor->promise(); }
private function doPut($path, $contents) : \Generator { $flags = \UV::O_WRONLY | \UV::O_CREAT; $mode = \UV::S_IRWXU | \UV::S_IRUSR; $this->reactor->addRef(); $promise = $this->doFsOpen($path, $flags, $mode); if (!($fh = (yield $promise))) { $this->reactor->delRef(); throw new \RuntimeException("Failed opening write file handle"); } $promisor = new Deferred(); $len = strlen($contents); \uv_fs_write($this->loop, $fh, $contents, $offset = 0, function ($fh, $result) use($promisor, $len) { \uv_fs_close($this->loop, $fh, function () use($promisor, $result, $len) { $this->reactor->delRef(); if ($result < 0) { $promisor->fail(new \RuntimeException(uv_strerror($result))); } else { $promisor->succeed($len); } }); }); (yield new \Amp\CoroutineResult((yield $promisor->promise()))); }
private function initializeNewConnection(Deferred $promisor, $uri, $options) { $this->pendingSockets[$uri] = isset($this->pendingSockets[$uri]) ? $this->pendingSockets[$uri] + 1 : 1; $futureSocket = \Amp\Socket\connect($uri, $options); $futureSocket->when(function ($error, $socket) use($promisor, $uri, $options) { if ($error) { $promisor->fail($error); } else { $this->finalizeNewConnection($promisor, $uri, $socket, $options); } }); }
private function sumMultipartFieldLengths(array $fields) { $lengths = []; foreach ($fields as $field) { if (is_string($field)) { $lengths[] = strlen($field); } else { $lengths[] = $field->getLength(); } } $promisor = new Deferred(); \Amp\all($lengths)->when(function ($error, $result) use($promisor) { if ($error) { $promisor->fail($error); } else { $promisor->succeed(array_sum($result)); } }); return $promisor->promise(); }
private function loadNewServer($uri) { if (!($socket = @\stream_socket_client($uri, $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT))) { throw new ResolutionException(sprintf("Connection to %s failed: [Error #%d] %s", $uri, $errno, $errstr)); } \stream_set_blocking($socket, false); $id = (int) $socket; $server = new \StdClass(); $server->id = $id; $server->uri = $uri; $server->socket = $socket; $server->buffer = ""; $server->length = INF; $server->pendingRequests = []; $server->watcherId = \Amp\onReadable($socket, $this->makePrivateCallable("onReadable"), ["enable" => true, "keep_alive" => true]); $this->serverIdMap[$id] = $server; $this->serverUriMap[$uri] = $server; if (substr($uri, 0, 6) == "tcp://") { $promisor = new Deferred(); $server->connect = $promisor->promise(); $watcher = \Amp\onWritable($server->socket, static function ($watcher) use($server, $promisor, &$timer) { \Amp\cancel($watcher); \Amp\cancel($timer); unset($server->connect); $promisor->succeed(); }); $timer = \Amp\once(function () use($id, $promisor, $watcher, $uri) { \Amp\cancel($watcher); $this->unloadServer($id); $promisor->fail(new TimeoutException("Name resolution timed out, could not connect to server at {$uri}")); }, 5000); } return $server; }
private function tunnelThroughProxy(Deferred $promisor, $socket, $authority) { if (empty(stream_context_get_options($socket)['artax*']['is_tunneled'])) { $futureTunnel = $this->tunneler->tunnel($socket, $authority); $futureTunnel->when(function ($error) use($promisor, $socket) { if ($error) { $promisor->fail($error); } else { $promisor->succeed($socket); } }); } else { $promisor->succeed($socket); } }
/** * {@inheritdoc} */ public function ctime($path) { $promisor = new Deferred(); $this->stat($path)->when(function ($error, $result) use($promisor) { if ($result) { $promisor->succeed($result["ctime"]); } else { $promisor->fail(new FilesystemException("Specified path does not exist")); } }); return $promisor->promise(); }
/** * Asynchronously request an HTTP resource * * @param mixed[string|\Amp\Artax\Request] An HTTP URI string or an \Amp\Artax\Request instance * @param array $options An array specifying options applicable only for this request * @return \Amp\Promise A promise to resolve the request at some point in the future */ public function request($uriOrRequest, array $options = []) { $promisor = new Deferred(); try { $cycle = new RequestCycle(); $cycle->futureResponse = $promisor; list($cycle->request, $cycle->uri) = $this->generateRequestFromUri($uriOrRequest); $cycle->options = $options ? array_merge($this->options, $options) : $this->options; $body = $cycle->request->getBody(); if ($body instanceof AggregateBody) { $this->processAggregateBody($cycle, $body); } else { $this->finalizeRequest($cycle); } } catch (\Exception $e) { $promisor->fail($e); } return $promisor->promise(); }