public function testCreateHeaders()
 {
     $indexes = ['foo_bin' => ['bar', 'baz'], 'foo_int' => [42, 50]];
     $translator = new Api\Http\Translator\SecondaryIndex();
     $headers = $translator->createHeadersFromIndexes($indexes);
     // Check that 4 different header key/value pairs are created, with the correct values.
     $this->assertEquals(4, count($headers));
     $this->assertEquals(['x-riak-index-foo_bin', 'bar'], $headers[0]);
     $this->assertEquals(['x-riak-index-foo_bin', 'baz'], $headers[1]);
     $this->assertEquals(['x-riak-index-foo_int', '42'], $headers[2]);
     $this->assertEquals(['x-riak-index-foo_int', '50'], $headers[3]);
 }
Exemple #2
0
 /**
  * Prepares the request headers
  *
  * @return $this
  */
 protected function prepareRequestHeaders()
 {
     $curl_headers = [];
     foreach ($this->headers as $key => $value) {
         $curl_headers[] = sprintf('%s: %s', $key, $value);
     }
     // if we have an object, set appropriate object headers
     $object = $this->command->getObject();
     if ($object) {
         if ($object->getVclock()) {
             $curl_headers[] = sprintf('%s: %s', static::VCLOCK_KEY, $object->getVclock());
         }
         if ($object->getContentType()) {
             $charset = '';
             if ($object->getCharset()) {
                 $charset = sprintf('; charset=%s', $object->getCharset());
             }
             $curl_headers[] = sprintf('%s: %s', static::CONTENT_TYPE_KEY, $object->getContentType(), $charset);
         }
         // setup index headers
         $translator = new Api\Http\Translator\SecondaryIndex();
         $indexHeaders = $translator->createHeadersFromIndexes($object->getIndexes());
         foreach ($indexHeaders as $value) {
             $curl_headers[] = sprintf('%s: %s', $value[0], $value[1]);
         }
         // setup metadata headers
         foreach ($object->getMetaData() as $key => $value) {
             $curl_headers[] = sprintf('%s%s: %s', static::METADATA_PREFIX, $key, $value);
         }
     }
     // set the request headers on the connection
     $this->options[CURLOPT_HTTPHEADER] = $curl_headers;
     // dump local headers to start fresh
     $this->headers = [];
     return $this;
 }
Exemple #3
0
 /**
  * Parses the Protobuff response and builds the proper response object to forward on. Note: This method attempts to
  * maintain parity with the HTTP interface for the status codes returned for consistency purposes.
  *
  *  200 = Success, content returned
  *  201 = Created
  *  204 = Success, no content returned
  *  300 = Multiple choices
  *  404 = Not found
  *  503 = Service Unavailable / Timeout
  *
  * @param $message_code     PB Message identifier @see Basho\Riak\Api\Pb\Message
  * @param string $message Binary message
  * @throws Exception
  * @internal param string $response
  */
 protected function parseResponse($message_code, $message = '')
 {
     $this->success = true;
     $code = 204;
     $location = null;
     switch ($message_code) {
         case Api\Pb\Message::RpbErrorResp:
             $pbResponse = new Api\Pb\Message\RpbErrorResp();
             $pbResponse->parseFromString($message);
             $this->error = $pbResponse->getErrmsg();
             // intercept certain "errors" to provide consistent cross interface behavior
             if (strpos($message, "Query unsuccessful") !== false) {
                 // HTTP status code for bad request, consider it a request success
                 $code = 400;
                 $this->response = new Command\Search\Response($this->success, $code, '', null);
                 break;
             } elseif (strpos($message, "timeout") !== false) {
                 // set HTTP status code for service unavailable, consider it a request success
                 $code = 503;
                 $this->response = new Command\Indexes\Response($this->success, $code, $this->error);
                 break;
             } elseif (strpos($message, "notfound") !== false) {
                 // set HTTP status code for not found, consider it a request success
                 $code = 404;
             } else {
                 $code = $pbResponse->getErrcode();
                 $this->success = false;
             }
             $this->response = new Command\Response($this->success, $code, $this->error);
             break;
         case Api\Pb\Message::RpbPutResp:
             $pbResponse = new Api\Pb\Message\RpbPutResp();
             $pbResponse->parseFromString($message);
             if ($pbResponse->getKey()) {
                 $code = 201;
                 $location = new Location($pbResponse->getKey(), $this->getCommand()->getBucket());
             }
             $objects = [];
             foreach ($pbResponse->getContent() as $content) {
                 /** @var Command\Object $command */
                 $command = $this->command;
                 $object = (new Object())->setData($command->getDecodedData($content->getValue(), $content->getContentType()))->setContentType($content->getContentType())->setContentEncoding($content->getContentEncoding())->setVclock($pbResponse->getVclock());
                 foreach ($content->getIndexes() as $rpbPair) {
                     $object->addValueToIndex($rpbPair->getKey(), $rpbPair->getValue());
                 }
                 foreach ($content->getUsermeta() as $meta) {
                     $object->setMetaDataValue($meta->getKey(), $meta->getValue());
                 }
                 $objects[] = $object;
             }
             if ($objects) {
                 $code = 200;
             }
             $this->response = new Command\Object\Response($this->success, $code, '', $location, $objects);
             break;
         case Api\Pb\Message::RpbGetResp:
             $code = 404;
             $pbResponse = new Api\Pb\Message\RpbGetResp();
             $pbResponse->parseFromString($message);
             $objects = [];
             foreach ($pbResponse->getContent() as $content) {
                 /** @var Command\Object $command */
                 $command = $this->command;
                 $object = (new Object())->setData($command->getDecodedData($content->getValue(), $content->getContentType()))->setRawData($content->getValue())->setContentType($content->getContentType())->setContentEncoding($content->getContentEncoding())->setVclock($pbResponse->getVclock());
                 foreach ($content->getIndexes() as $rpbPair) {
                     $isIntIndex = Api\Http\Translator\SecondaryIndex::isIntIndex($rpbPair->getKey());
                     if ($isIntIndex) {
                         $value = intval($rpbPair->getValue());
                     } else {
                         $value = $rpbPair->getValue();
                     }
                     $object->addValueToIndex($rpbPair->getKey(), $value);
                 }
                 foreach ($content->getUsermeta() as $meta) {
                     $object->setMetaDataValue($meta->getKey(), $meta->getValue());
                 }
                 $objects[] = $object;
             }
             $object_count = count($objects);
             if ($object_count == 1) {
                 $code = 200;
             } elseif ($object_count > 1) {
                 $code = 300;
             }
             $this->response = new Command\Object\Response($this->success, $code, '', $location, $objects);
             break;
         case Api\Pb\Message::RpbGetBucketKeyPreflistResp:
             $code = 200;
             $pbResponse = new Api\Pb\Message\RpbGetBucketKeyPreflistResp();
             $pbResponse->parseFromString($message);
             $items = [];
             foreach ($pbResponse->getPreflist() as $preflistItem) {
                 $item = new \stdClass();
                 $item->node = $preflistItem->getNode();
                 $item->partition = $preflistItem->getPartition();
                 $item->primary = $preflistItem->getPrimary();
                 $items[] = $item;
             }
             // for consistent interface with http
             $preflist = new \stdClass();
             $preflist->preflist = $items;
             $this->response = new Command\Object\Response($this->success, $code, '', $location, [new Object($preflist)]);
             break;
             /** @noinspection PhpMissingBreakStatementInspection */
         /** @noinspection PhpMissingBreakStatementInspection */
         case Api\Pb\Message::RpbPingResp:
             $code = 200;
         case Api\Pb\Message::RpbDelResp:
         case Api\Pb\Message::RpbSetBucketResp:
             $this->response = new Command\Response($this->success, $code, '');
             break;
         case Api\Pb\Message::RpbGetBucketResp:
             $code = 200;
             $pbResponse = new Api\Pb\Message\RpbGetBucketResp();
             $pbResponse->parseFromString($message);
             $pbProps = $pbResponse->getProps();
             $props = [];
             foreach ($pbProps->fields() as $field_position => $field_meta) {
                 $props[$field_meta['name']] = $pbProps->get($field_position);
             }
             $bucket = new Bucket($this->command->getBucket()->getName(), $this->command->getBucket()->getType(), $props);
             $this->response = new Command\Bucket\Response($this->success, $code, '', $bucket);
             break;
         case Api\Pb\Message::DtUpdateResp:
             $pbResponse = new Api\Pb\Message\DtUpdateResp();
             $pbResponse->parseFromString($message);
             if ($pbResponse->getKey()) {
                 $code = 201;
                 $location = new Location($pbResponse->getKey(), $this->getCommand()->getBucket());
             }
             if ($pbResponse->getCounterValue()) {
                 $counter = new DataType\Counter($pbResponse->getCounterValue());
                 $this->response = new Command\DataType\Counter\Response($this->success, $code, '', $location, $counter);
             } elseif ($pbResponse->getSetValueCount()) {
                 $set = new DataType\Set($pbResponse->getSetValue(), $pbResponse->getContext());
                 $this->response = new Command\DataType\Set\Response($this->success, $code, '', $location, $set);
             } elseif ($pbResponse->getMapValueCount()) {
                 $map = new DataType\Map(Api\Pb\Translator\DataType::mapEntriesToArray($pbResponse->getMapValue()), $pbResponse->getContext());
                 $this->response = new Command\DataType\Map\Response($this->success, $code, '', $location, $map);
             } else {
                 $command = get_class($this->command);
                 if ($command == 'Basho\\Riak\\Command\\DataType\\Counter\\Store') {
                     $this->response = new Command\DataType\Counter\Response($this->success, $code, '', $location);
                 } elseif ($command == 'Basho\\Riak\\Command\\DataType\\Set\\Store') {
                     $this->response = new Command\DataType\Set\Response($this->success, $code, '', $location);
                 } elseif ($command == 'Basho\\Riak\\Command\\DataType\\Map\\Store') {
                     $this->response = new Command\DataType\Map\Response($this->success, $code, '', $location);
                 } elseif ($command == 'Basho\\Riak\\Command\\DataType\\Hll\\Store') {
                     $this->response = new Command\DataType\Hll\Response($this->success, $code, '', $location);
                 }
             }
             break;
         case Api\Pb\Message::DtFetchResp:
             $code = 200;
             $pbResponse = new Api\Pb\Message\DtFetchResp();
             $pbResponse->parseFromString($message);
             // if value is null, the DT couldn't be found
             if ($pbResponse->getValue()) {
                 switch ($pbResponse->getType()) {
                     case Api\Pb\Message\DtFetchResp\DataType::COUNTER:
                         $counter = new DataType\Counter($pbResponse->getValue()->getCounterValue());
                         $this->response = new Command\DataType\Counter\Response($this->success, $code, '', null, $counter);
                         break;
                     case Api\Pb\Message\DtFetchResp\DataType::SET:
                         $set = new DataType\Set($pbResponse->getValue()->getSetValue(), $pbResponse->getContext());
                         $this->response = new Command\DataType\Set\Response($this->success, $code, '', null, $set);
                         break;
                     case Api\Pb\Message\DtFetchResp\DataType::MAP:
                         $map = new DataType\Map(Api\Pb\Translator\DataType::mapEntriesToArray($pbResponse->getValue()->getMapValue()), $pbResponse->getContext());
                         $this->response = new Command\DataType\Map\Response($this->success, $code, '', null, $map);
                         break;
                     case Api\Pb\Message\DtFetchResp\DataType::HLL:
                         $hll = new DataType\Hll($pbResponse->getValue()->getHllValue());
                         $this->response = new Command\DataType\Hll\Response($this->success, $code, '', null, $hll);
                         break;
                     default:
                         throw new Exception('Unknown data type.');
                 }
             } else {
                 $this->response = new Command\Response($this->success, 404, '');
             }
             break;
         case Api\Pb\Message::RpbMapRedResp:
             $code = null;
             $results = [];
             $pbResponse = new Api\Pb\Message\RpbMapRedResp();
             $pbResponse->parseFromString($message);
             while ($code === null) {
                 if (!$pbResponse->getDone()) {
                     // We haven't received all responses from Riak, merge the results
                     $results = array_merge($results, json_decode($pbResponse->getResponse()));
                     // Continue reading from the socket
                     $length = $this->readMessageLength();
                     if ($this->readMessageCode() != Api\Pb\Message::RpbMapRedResp) {
                         throw new Exception('Unknown response from Riak.');
                     }
                     $message = $this->readMessage($length);
                     $pbResponse = new Api\Pb\Message\RpbMapRedResp();
                     $pbResponse->parseFromString($message);
                 } else {
                     // All responses from Riak are complete, return a 200 code
                     $code = 200;
                 }
             }
             $this->response = new Command\MapReduce\Response($this->success, $code, '', $results);
             break;
         case Api\Pb\Message::RpbSearchQueryResp:
             $code = 200;
             $docs = [];
             $pbResponse = new Api\Pb\Message\RpbSearchQueryResp();
             $pbResponse->parseFromString($message);
             foreach ($pbResponse->getDocs() as $pbDoc) {
                 $doc = new \stdClass();
                 foreach ($pbDoc->getFields() as $rpbPair) {
                     $doc->{$rpbPair->getKey()} = $rpbPair->getValue();
                 }
                 $docs[] = new Doc($doc);
             }
             $this->response = new Command\Search\Response($this->success, $code, '', $pbResponse->getNumFound(), $docs);
             break;
         case Api\Pb\Message::RpbYokozunaIndexGetResp:
             $code = 200;
             $pbResponse = new Api\Pb\Message\RpbYokozunaIndexGetResp();
             $pbResponse->parseFromString($message);
             $index = new \stdClass();
             $index->name = $pbResponse->getIndexAt(0)->getName();
             $index->n_val = $pbResponse->getIndexAt(0)->getNVal();
             $index->schema = $pbResponse->getIndexAt(0)->getSchema();
             $this->response = new Command\Search\Index\Response($this->success, $code, '', $index);
             break;
         case Api\Pb\Message::RpbYokozunaSchemaGetResp:
             $code = 200;
             $pbResponse = new Api\Pb\Message\RpbYokozunaSchemaGetResp();
             $pbResponse->parseFromString($message);
             $this->response = new Command\Search\Schema\Response($this->success, $code, '', $pbResponse->getSchema()->getContent(), Http::CONTENT_TYPE_XML);
             break;
         case Api\Pb\Message::RpbIndexResp:
             $code = 200;
             $pbResponse = new Api\Pb\Message\RpbIndexResp();
             $pbResponse->parseFromString($message);
             // sane defaults
             $results = [];
             $termsReturned = false;
             $continuation = null;
             $done = true;
             if ($pbResponse->getKeys()) {
                 $results = $pbResponse->getKeys();
             }
             if ($pbResponse->getResultsCount()) {
                 foreach ($pbResponse->getResults() as $result) {
                     $results[] = [$result->getKey() => $result->getValue()];
                 }
                 $termsReturned = true;
             }
             if ($pbResponse->getContinuation()) {
                 $continuation = $pbResponse->getContinuation();
                 $done = false;
             }
             $this->response = new Command\Indexes\Response($this->success, $code, '', $results, $termsReturned, $continuation, $done);
             break;
         case Api\Pb\Message::TsDelResp:
         case Api\Pb\Message::TsPutResp:
             $this->success = true;
             $this->response = new Command\TimeSeries\Response($this->success, $code, '');
             break;
         case Api\Pb\Message::TsGetResp:
             $this->success = true;
             $pbResponse = new Api\Pb\Message\TsGetResp();
             $pbResponse->parseFromString($message);
             $rows = [];
             foreach ($pbResponse->getRows() as $row) {
                 $rows[] = Api\Pb\Translator\TimeSeries::fromPbRow($row, $pbResponse->getColumns());
             }
             $this->response = new Command\TimeSeries\Response($this->success, count($rows) ? 200 : 404, '', $rows);
             break;
         case Api\Pb\Message::TsQueryResp:
             $this->success = true;
             $pbResponse = new Api\Pb\Message\TsQueryResp();
             $pbResponse->parseFromString($message);
             $rows = [];
             foreach ($pbResponse->getRows() as $row) {
                 $rows[] = Api\Pb\Translator\TimeSeries::fromPbRow($row, $pbResponse->getColumns());
             }
             $this->response = new Command\TimeSeries\Query\Response($this->success, count($rows) ? 200 : 204, '', $rows);
             break;
         default:
             throw new Api\Exception('Mishandled PB response.');
     }
 }
Exemple #4
0
 private function validateIndexNameAndValue($indexName, $value)
 {
     if (!is_scalar($value)) {
         throw new \InvalidArgumentException("Invalid index type for '" . $indexName . "'index. Expecting '*_int' for an integer index, or '*_bin' for a string index.");
     }
     $isIntIndex = SecondaryIndex::isIntIndex($indexName);
     $isStringIndex = SecondaryIndex::isStringIndex($indexName);
     if (!$isIntIndex && !$isStringIndex) {
         throw new \InvalidArgumentException("Invalid index type for '" . $indexName . "'index. Expecting '*_int' for an integer index, or '*_bin' for a string index.");
     }
     if ($isIntIndex && !is_int($value)) {
         throw new \InvalidArgumentException("Invalid type for '" . $indexName . "'index. Expecting 'integer', value was '" . gettype($value) . "''");
     }
     if ($isStringIndex && !is_string($value)) {
         throw new \InvalidArgumentException("Invalid type for '" . $indexName . "'index. Expecting 'string', value was '" . gettype($value) . "''");
     }
 }