Beispiel #1
0
 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;
     }
 }
Beispiel #2
0
 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();
 }
Beispiel #3
0
 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();
 }
Beispiel #4
0
 /**
  * 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();
 }
Beispiel #5
0
 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();
 }
Beispiel #6
0
 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();
 }
Beispiel #7
0
 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();
 }
Beispiel #8
0
 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];
     }));
 }
Beispiel #9
0
 /**
  * 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();
 }
Beispiel #10
0
 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);
 }
Beispiel #11
0
 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();
 }
Beispiel #12
0
 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]);
     }
 }
Beispiel #13
0
 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())));
 }
Beispiel #14
0
 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();
 }
Beispiel #15
0
 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;
 }
Beispiel #16
0
 /**
  * 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();
 }
Beispiel #17
0
 /**
  * {@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();
 }
Beispiel #18
0
 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);
     }
 }
Beispiel #19
0
 /**
  * {@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();
 }