Ejemplo n.º 1
0
 private function send(string $message, callable $transform = null)
 {
     $promisor = new Deferred();
     $this->connection->send($message);
     $this->promisors[] = $promisor;
     return $transform ? pipe($promisor->promise(), $transform) : $promisor->promise();
 }
Ejemplo n.º 2
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;
     }
 }
Ejemplo n.º 3
0
 public function getRoomSessionInfo(Identifier $identifier) : Promise
 {
     $deferred = new Deferred();
     $this->queue->push([$identifier, $deferred]);
     if (!$this->haveLoop) {
         resolve($this->executeActionsFromQueue());
     }
     return $deferred->promise();
 }
Ejemplo n.º 4
0
 private function connect()
 {
     // If we're in the process of connecting already return that same promise
     if ($this->connectPromisor) {
         return $this->connectPromisor->promise();
     }
     // If a read watcher exists we know we're already connected
     if ($this->readWatcher) {
         return new Success($this);
     }
     $this->connectPromisor = new Deferred();
     $socketPromise = connect($this->uri, ["timeout" => $this->timeout]);
     $onWrite = function ($watcherId) {
         if ($this->outputBufferLength === 0) {
             disable($watcherId);
             return;
         }
         $bytes = @fwrite($this->socket, $this->outputBuffer);
         if ($bytes === 0) {
             $this->onError(new ConnectException("Connection went away (write)", $code = 1));
         } else {
             $this->outputBuffer = (string) substr($this->outputBuffer, $bytes);
             $this->outputBufferLength -= $bytes;
         }
     };
     $socketPromise->when(function ($error, $socket) use($onWrite) {
         $connectPromisor = $this->connectPromisor;
         $this->connectPromisor = null;
         if ($error) {
             $connectPromisor->fail(new ConnectException("Connection attempt failed", $code = 0, $error));
             return;
         }
         $this->socket = $socket;
         foreach ($this->handlers["connect"] as $handler) {
             $pipelinedCommand = $handler();
             if (!empty($pipelinedCommand)) {
                 $this->outputBuffer = $pipelinedCommand . $this->outputBuffer;
                 $this->outputBufferLength += strlen($pipelinedCommand);
             }
         }
         $this->readWatcher = onReadable($this->socket, function () {
             $read = fread($this->socket, 8192);
             if ($read != "") {
                 $this->parser->append($read);
             } elseif (!is_resource($this->socket) || @feof($this->socket)) {
                 $this->onError(new ConnectException("Connection went away (read)", $code = 2));
             }
         });
         $this->writeWatcher = onWritable($this->socket, $onWrite, ["enable" => !empty($this->outputBuffer)]);
         $connectPromisor->succeed();
     });
     return $this->connectPromisor->promise();
 }
Ejemplo n.º 5
0
 protected function genericFetch(callable $cb = null)
 {
     if ($this->result->userFetched < $this->result->fetchedRows) {
         $row = $this->result->rows[$this->result->userFetched++];
         return new Success($cb ? $cb($row) : $row);
     } elseif ($this->result->state == ResultProxy::ROWS_FETCHED) {
         return new Success(null);
     } else {
         $deferred = new Deferred();
         $this->result->deferreds[ResultProxy::SINGLE_ROW_FETCH][] = [$deferred, null, $cb];
         return $deferred->promise();
     }
 }
Ejemplo n.º 6
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();
 }
Ejemplo n.º 7
0
 public function log(int $logLevel, string $message, $extraData = null) : Promise
 {
     if (!$this->meetsLogLevel($logLevel)) {
         return new Success();
     }
     $messages = [$message];
     if ($extraData !== null && $this->meetsLogLevel(Level::EXTRA_DATA)) {
         $messages[] = json_encode($extraData);
     }
     $this->writeQueue->push([(new \DateTime())->format('Y-m-d H:i:s'), $messages, $deferred = new Deferred()]);
     if (!$this->haveWriteLoop) {
         resolve($this->writeMessagesFromQueue());
     }
     return $deferred->promise();
 }
Ejemplo n.º 8
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();
 }
Ejemplo n.º 9
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();
 }
Ejemplo n.º 10
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();
 }
Ejemplo n.º 11
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();
 }
Ejemplo n.º 12
0
 /**
  * Succeeds with true if an emitted value is available by calling getCurrent() or false if the observable has
  * resolved. If the observable fails, the returned promise will fail with the same exception.
  *
  * @return \Interop\Async\Promise<bool>
  */
 public function next() : Promise
 {
     if (isset($this->deferreds[$this->position])) {
         $future = $this->deferreds[$this->position];
         unset($this->values[$this->position], $this->deferreds[$this->position]);
         $future->resolve();
     }
     ++$this->position;
     if (\array_key_exists($this->position, $this->values)) {
         return new Success(true);
     }
     if ($this->resolved) {
         --$this->position;
         if ($this->exception) {
             return new Failure($this->exception);
         }
         return new Success(false);
     }
     $this->deferred = new Deferred();
     return $this->deferred->promise();
 }
Ejemplo n.º 13
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];
     }));
 }
Ejemplo n.º 14
0
 public function getFields()
 {
     if ($this->result->state >= ResultProxy::COLUMNS_FETCHED) {
         return new Success($this->result->columns);
     } elseif (isset($this->result->deferreds[ResultProxy::COLUMNS_FETCHED][0])) {
         return $this->result->deferreds[ResultProxy::COLUMNS_FETCHED][0][0]->promise();
     } else {
         $deferred = new Deferred();
         $this->result->deferreds[ResultProxy::COLUMNS_FETCHED][0] = [$deferred, &$this->result->columns, null];
         return $deferred->promise();
     }
 }
Ejemplo n.º 15
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();
 }
Ejemplo n.º 16
0
 private function initField($field, $metadata = [])
 {
     if ($this->inputVarCount++ == $this->maxInputVars || \strlen($field) > $this->maxFieldLen) {
         $this->fail();
         return null;
     }
     $this->curSizes[$field] = 0;
     $this->usedSize += \strlen($field);
     if ($this->usedSize > $this->size) {
         $this->fail();
         return null;
     }
     if (isset($this->bodyPromisors[$field])) {
         $key = key($this->bodyPromisors[$field]);
         list($dataPromisor, $metadataPromisor) = $this->bodyPromisors[$field][$key];
         $metadataPromisor->succeed($metadata);
         unset($this->bodyPromisors[$field]);
     } else {
         $dataPromisor = new Deferred();
         $this->bodies[$field][] = new FieldBody($dataPromisor->promise(), new Success($metadata));
     }
     foreach ($this->watchers as list($cb, $cbData)) {
         $cb($field, $cbData);
     }
     return $dataPromisor;
 }
Ejemplo n.º 17
0
 protected function genericFetch(callable $cb = null)
 {
     if ($this->result->userFetched < $this->result->fetchedRows) {
         $row = $this->result->rows[$this->result->userFetched++];
         return new Success($cb ? $cb($row) : $row);
     } elseif ($this->result->state == ResultProxy::ROWS_FETCHED) {
         return new Success(null);
     } else {
         $deferred = new Deferred();
         /* We need to increment the internal counter, else the next time genericFetch is called,
          * it'll simply return the row we fetch here instead of fetching a new row
          * since callback order on promises isn't defined, we can't do this via when() */
         $incRow = function ($row) use($cb) {
             $this->result->userFetched++;
             return $cb && $row ? $cb($row) : $row;
         };
         $this->result->deferreds[ResultProxy::SINGLE_ROW_FETCH][] = [$deferred, null, $incRow];
         return $deferred->promise();
     }
 }
Ejemplo n.º 18
0
 /**
  * {@inheritdoc}
  */
 public function put($path, $contents)
 {
     $flags = \EIO_O_RDWR | \EIO_O_CREAT;
     $mode = \EIO_S_IRUSR | \EIO_S_IWUSR | \EIO_S_IXUSR;
     $priority = \EIO_PRI_DEFAULT;
     $this->incrementPending();
     $promisor = new Deferred();
     $data = [$contents, $promisor];
     \eio_open($path, $flags, $mode, $priority, [$this, "onPutOpen"], $data);
     return $promisor->promise();
 }
Ejemplo n.º 19
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;
 }
Ejemplo n.º 20
0
 /** @see 14.8.4 COM_STMT_FETCH */
 public function fetchStmt($stmtId)
 {
     $payload = "" . DataTypes::encode_int32($stmtId) . DataTypes::encode_int32(1);
     $deferred = new Deferred();
     $this->appendTask(function () use($payload, $deferred) {
         $this->out[] = null;
         $this->deferreds[] = $deferred;
         $this->sendPacket($payload);
         $this->enableRead();
     });
     return $deferred->promise();
 }
Ejemplo n.º 21
0
 /**
  * Write data to the socket
  *
  * Upon write completion the returned promise will resolve to an integer indicating
  * the number of bytes written. If no bytes were written prior to disconnection the
  * returned promise resolves to NULL.
  *
  * @param string $data
  * @return \Amp\Promise<int|null>
  */
 public function write($data)
 {
     $len = \strlen($data);
     if (!($len && \is_string($data))) {
         return new amp\Failure(new \LogicException("String of minimum length 1 required"));
     }
     $state = $this->state;
     if (!$this->alive()) {
         return new amp\Success(null);
     }
     if (empty($state->isWriteEnabled)) {
         amp\enable($this->state->writeWatcherId);
         $state->isWriteEnabled = true;
     }
     $op = new \StdClass();
     $op->buffer = $data;
     $op->size = $len;
     $op->bytesWritten = null;
     $op->promisor = $promisor = new amp\Deferred();
     $state->writeOperations[] = $op;
     return $promisor->promise();
 }
Ejemplo n.º 22
0
 private function enqueueAction(callable $callable, Identifier $identifier, ...$args) : Promise
 {
     $ident = $identifier->getIdentString();
     if (!isset($this->actionQueues[$ident])) {
         $queue = new Queue();
         $this->actionQueues[$ident] = ['queue' => $queue, 'running' => false];
     } else {
         $queue = $this->actionQueues[$ident]['queue'];
     }
     $queue->push([$callable, $args, $deferred = new Deferred()]);
     if (!$this->actionQueues[$ident]['running']) {
         resolve($this->executeActionsFromQueue($identifier));
     }
     return $deferred->promise();
 }
Ejemplo n.º 23
0
 /**
  * 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();
 }
Ejemplo n.º 24
0
function __doRequest($state, $uri, $name, $type)
{
    $server = __loadExistingServer($state, $uri) ?: __loadNewServer($state, $uri);
    // Get the next available request ID
    do {
        $requestId = $state->requestIdCounter++;
        if ($state->requestIdCounter >= MAX_REQUEST_ID) {
            $state->requestIdCounter = 1;
        }
    } while (isset($state->pendingRequests[$requestId]));
    // Create question record
    $question = $state->questionFactory->create($type);
    $question->setName($name);
    // Create request message
    $request = $state->messageFactory->create(MessageTypes::QUERY);
    $request->getQuestionRecords()->add($question);
    $request->isRecursionDesired(true);
    $request->setID($requestId);
    // Encode request message
    $requestPacket = $state->encoder->encode($request);
    if (substr($uri, 0, 6) == "tcp://") {
        $requestPacket = pack("n", strlen($requestPacket)) . $requestPacket;
    }
    // Send request
    $bytesWritten = \fwrite($server->socket, $requestPacket);
    if ($bytesWritten === false || isset($packet[$bytesWritten])) {
        throw new ResolutionException("Request send failed");
    }
    $promisor = new Deferred();
    $server->pendingRequests[$requestId] = true;
    $state->pendingRequests[$requestId] = [$promisor, $name, $type, $uri];
    return $promisor->promise();
}
Ejemplo n.º 25
0
 public function eval(Command $command) : Promise
 {
     if (!$command->hasParameters()) {
         return new Success();
     }
     $code = $this->normalizeCode($command->getText());
     $body = (new FormBody())->addField("title", "")->addField("code", $code);
     $request = (new HttpRequest())->setUri("https://3v4l.org/new")->setMethod("POST")->setHeader("Accept", "application/json")->setBody($body);
     $deferred = new Deferred();
     $this->queue->push([$request, $command->getRoom(), $deferred]);
     if (!$this->haveLoop) {
         resolve($this->executeActionsFromQueue());
     }
     return $deferred->promise();
 }
Ejemplo n.º 26
0
 /**
  * @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();
 }
Ejemplo n.º 27
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();
 }
Ejemplo n.º 28
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();
 }
Ejemplo n.º 29
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())));
 }
Ejemplo n.º 30
0
 /**
  * {@inheritdoc}
  */
 public function put($path, $contents)
 {
     $flags = \EIO_O_WRONLY | \EIO_O_CREAT | \EIO_O_TRUNC;
     $mode = 0666;
     $priority = \EIO_PRI_DEFAULT;
     \call_user_func($this->incrementor, 1);
     $promisor = new Deferred();
     $data = [$contents, $promisor];
     \eio_open($path, $flags, $mode, $priority, [$this, "onPutOpen"], $data);
     return $promisor->promise();
 }