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; } }
public function send($socket) { $deferred = new Deferred(); stream_set_blocking($socket, false); $data = $this->getRequest(); \Amp\onWritable($socket, function ($writer, $socket) use($deferred, &$data) { if ($bytes = fwrite($socket, $data)) { if ($bytes < \strlen($data)) { $data = substr($data, $bytes); return; } $data = ''; \Amp\onReadable($socket, function ($reader, $socket) use($deferred, &$data) { $data .= $bytes = fgets($socket); if ($bytes == '' || \strlen($bytes) > 32768) { \Amp\cancel($reader); $deferred->succeed(null); } elseif (substr($data, -4) == "\r\n\r\n") { \Amp\cancel($reader); $deferred->succeed($this->parseResponse($data)); } }); } else { $deferred->succeed(null); } \Amp\cancel($writer); }); return $deferred->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(); }
/** * 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(); }
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(); }
private function loadFile(string $filePath) : \Generator { if (isset($this->loadPromises[$filePath])) { (yield $this->loadPromises[$filePath]); return $this->dataCache[$filePath]; } $deferred = new Deferred(); $this->loadPromises[$filePath] = $deferred->promise(); $this->lockMutexes[$filePath] = new QueuedExclusiveMutex(); return (yield $this->lockMutexes[$filePath]->withLock(function () use($filePath, $deferred) { try { // we may have been waiting on a lock and it's been populated by now if (!isset($this->dataCache[$filePath])) { $this->dataCache[$filePath] = (yield exists($filePath)) ? json_try_decode((yield get($filePath)), true) : []; } } catch (\Throwable $e) { $this->dataCache[$filePath] = []; } finally { $deferred->succeed(); unset($this->loadPromises[$filePath]); } return $this->dataCache[$filePath]; })); }
/** * 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(); }
private function successfulResultsetFetch() { $deferred =& $this->result->next; if ($this->connInfo->statusFlags & StatusFlags::SERVER_MORE_RESULTS_EXISTS) { $this->parseCallback = [$this, "handleQuery"]; $this->deferreds[] = $deferred ?: ($deferred = new Deferred()); } else { if ($deferred) { $deferred->succeed(null); } else { $deferred = new Success(null); } $this->parseCallback = null; } $this->query = null; $this->ready(); $this->result->updateState(ResultProxy::ROWS_FETCHED); }
public function send($socket) { $deferred = new Deferred(); stream_set_blocking($socket, false); $data = $this->getRequest(); \Amp\onWritable($socket, function ($writer, $socket) use($deferred, &$data) { if ($bytes = fwrite($socket, $data)) { if ($bytes < \strlen($data)) { $data = substr($data, $bytes); return; } $size = 8192; \Amp\onReadable($socket, function ($reader, $socket) use($deferred, &$size) { /* make attention to not read too much data */ $data = stream_socket_recvfrom($socket, $size, STREAM_PEEK); if (false === ($pos = strpos($data, "\r\n\r\n"))) { if (\strlen($data) == $size) { $size *= 2; // unbounded?? } return; } \Amp\cancel($reader); $deferred->succeed($this->parseResponse(fread($socket, $pos + 4))); }); } else { $deferred->succeed(null); } \Amp\cancel($writer); }); return $deferred->promise(); }
private function finalizeNewConnection(Deferred $promisor, $uri, $socket, $options) { if (--$this->pendingSockets[$uri] === 0) { unset($this->pendingSockets[$uri]); } $socketId = (int) $socket; $poolStruct = new SocketPoolStruct(); $poolStruct->id = $socketId; $poolStruct->uri = $uri; $poolStruct->resource = $socket; $poolStruct->isAvailable = false; $poolStruct->msIdleTimeout = $options[self::OP_MS_IDLE_TIMEOUT]; $this->sockets[$uri][$socketId] = $poolStruct; $this->socketIdUriMap[$socketId] = $uri; $promisor->succeed($poolStruct->resource); if (empty($this->queuedSocketRequests[$uri])) { unset($this->queuedSocketRequests[$uri]); } }
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 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; }
/** * 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(); }
/** * {@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(); }
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 close() { $this->isCloseInitialized = true; $this->reactor->addRef(); $promisor = new Deferred(); \uv_fs_close($this->loop, $this->fh, function ($fh) use($promisor) { $this->reactor->delRef(); $promisor->succeed(); }); return $promisor->promise(); }