Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding storage client #191

Merged
merged 16 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
"Leaderboard\\": "types/Leaderboard/",
"Permission_messages\\": "types/Permission_messages/",
"Token\\": "types/Token/",
"Webhook\\": "types/Webhook/"
"Webhook\\": "types/Webhook/",
"Store\\": "types/Store/"
},
"files": [
"src/Utilities/_DataValidation.php"
],
"classmap": [
"src/Cache/CacheOperationTypes/CacheOperationTypes.php",
"src/Storage/StorageOperationTypes/StorageOperationTypes.php",
"src/Cache/Errors/Errors.php"
]
},
Expand Down
125 changes: 125 additions & 0 deletions examples/storage-example.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
require "vendor/autoload.php";

use Momento\Auth\CredentialProvider;
use Momento\Config\Configurations\StorageLaptop;
use Momento\Logging\StderrLoggerFactory;
use Psr\Log\LoggerInterface;
use Momento\Storage\PreviewStorageClient;
use Momento\Storage\StorageOperationTypes\StorageValueType;

$STORE_NAME = uniqid("php-storage-example-");
$VALUES = [
"str"=> "StringValue",
"int" => 123,
"double" => 123.456,
"fakeout" => "123"
];

// Setup
$authProvider = CredentialProvider::fromEnvironmentVariable("MOMENTO_AUTH_TOKEN");
$configuration = StorageLaptop::latest(new StderrLoggerFactory());
$client = new PreviewStorageClient($configuration, $authProvider);
$logger = $configuration->getLoggerFactory()->getLogger("ex:");

function printBanner(string $message, LoggerInterface $logger): void
{
$line = "**************************************************************************";
$logger->info($line);
$logger->info($message);
$logger->info($line);
}

// Used to tear down temporary store after failure or completion of script
function deleteStore(string $storeName, LoggerInterface $logger, PreviewStorageClient $client): void
{
$logger->info("Deleting store $storeName\n");
$response = $client->deleteStore($storeName);
if ($response->asError()) {
$logger->info("Error deleting store: " . $response->asError()->message() . "\n");
exit(1);
}
}

printBanner("* Momento Storage Example Start *", $logger);

// Ensure test store exists
$response = $client->createStore($STORE_NAME);
if ($response->asSuccess()) {
$logger->info("Created store " . $STORE_NAME . "\n");
} elseif ($response->asError()) {
$logger->info("Error creating store: " . $response->asError()->message() . "\n");
exit(1);
} elseif ($response->asAlreadyExists()) {
$logger->info("Store " . $STORE_NAME . " already exists.\n");
}

// List stores
$response = $client->listStores();
if ($response->asSuccess()) {
$logger->info("SUCCESS: List stores: \n");
foreach ($response->asSuccess()->stores() as $store) {
$storeName = $store->name();
$logger->info("$storeName\n");
}
$logger->info("\n");
} elseif ($response->asError()) {
$logger->info("Error listing store: " . $response->asError()->message() . "\n");
deleteStore($STORE_NAME, $logger, $client);
exit(1);
}

// Set
foreach ($VALUES as $key => $value) {
$logger->info("Setting key: '$key' to value: '$value', type = " . get_class($value) . "\n");
$response = $client->set($STORE_NAME, $key, $value);
if ($response->asSuccess()) {
$logger->info("SUCCESS\n");
} elseif ($response->asError()) {
$logger->info("Error setting key: " . $response->asError()->message() . "\n");
deleteStore($STORE_NAME, $logger, $client);
exit(1);
}
}

// Get
foreach ($VALUES as $key => $value) {
$logger->info("Getting value for key: '$key'\n");
$response = $client->get($STORE_NAME, $key);
if ($response->asSuccess()) {
$logger->info("SUCCESS\n");
$valueType = $response->asSuccess()->type();
if ($valueType == StorageValueType::STRING) {
print("Got string value: " . $response->asSuccess()->tryGetString() . "\n");
} elseif ($valueType == StorageValueType::INTEGER) {
print("Got integer value: " . $response->asSuccess()->tryGetInteger() . "\n");
} elseif ($valueType == StorageValueType::DOUBLE) {
print("Got double value: " . $response->asSuccess()->tryGetDouble() . "\n");
} elseif ($valueType == StorageValueType::BYTES) {
// This case is not expected in this example as PHP doesn't have a native byte type
print("Got bytes value: " . $response->asSuccess()->tryGetBytes() . "\n");
}
} elseif ($response->asError()) {
$logger->info("Error getting key: " . $response->asError()->message() . "\n");
deleteStore($STORE_NAME, $logger, $client);
exit(1);
}
}

// Delete
foreach (array_keys($VALUES) as $key) {
$logger->info("Deleting key: '$key'\n");
$response = $client->delete($STORE_NAME, $key);
if ($response->asSuccess()) {
$logger->info("SUCCESS\n");
} elseif ($response->asError()) {
$logger->info("Error deleting key: " . $response->asError()->message() . "\n");
exit(1);
}
}

// Delete store
deleteStore($STORE_NAME, $logger, $client);

printBanner("* Momento Storage Example End *", $logger);
2 changes: 2 additions & 0 deletions src/Auth/AuthUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public static function parseV1Token(string $authToken): object {
$payload = new \stdClass();
$payload->c = "cache.{$tokenData->endpoint}";
$payload->cp = "control.{$tokenData->endpoint}";
$payload->storage = "storage.{$tokenData->endpoint}";
$payload->authToken = $tokenData->api_key;
return $payload;
}
Expand All @@ -47,6 +48,7 @@ public static function parseJwtToken(string $authToken): object
try {
$payload = $exploded[1];
$payload = JWT::jsonDecode(JWT::urlsafeB64Decode($payload));
$payload->storage = null;
pgautier404 marked this conversation as resolved.
Show resolved Hide resolved
$payload->authToken = $authToken;
} catch (\Exception $e) {
self::throwBadAuthToken();
Expand Down
3 changes: 2 additions & 1 deletion src/Auth/EnvMomentoTokenProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public function __construct(
string $envVariableName,
?string $controlEndpoint = null,
?string $cacheEndpoint = null,
?string $storageEndpoint = null,
?string $trustedControlEndpointCertificateName = null,
?string $trustedCacheEndpointCertificateName = null
)
Expand All @@ -23,6 +24,6 @@ public function __construct(
throw new InvalidArgumentError("Environment variable $envVariableName is empty or null.");
}
$authToken = $_SERVER[$envVariableName];
parent::__construct($authToken, $controlEndpoint, $cacheEndpoint, $trustedControlEndpointCertificateName, $trustedCacheEndpointCertificateName);
parent::__construct($authToken, $controlEndpoint, $cacheEndpoint, $storageEndpoint, $trustedControlEndpointCertificateName, $trustedCacheEndpointCertificateName);
}
}
14 changes: 14 additions & 0 deletions src/Auth/StringMomentoTokenProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ class StringMomentoTokenProvider extends CredentialProvider
protected string $authToken;
protected ?string $controlEndpoint = null;
protected ?string $cacheEndpoint = null;
protected ?string $storageEndpoint = null;
protected ?string $trustedControlEndpointCertificateName = null;
protected ?string $trustedCacheEndpointCertificateName = null;

public function __construct(
string $authToken,
?string $controlEndpoint = null,
?string $cacheEndpoint = null,
// TODO: adding this arg would be a breaking change for anyone currently passing in
// endpointCertificateName arguments. I am pretty sure that is 0 people, but wanted
// to call it out.
?string $storageEndpoint = null,
malandis marked this conversation as resolved.
Show resolved Hide resolved
?string $trustedControlEndpointCertificateName = null,
?string $trustedCacheEndpointCertificateName = null
)
Expand All @@ -38,6 +43,7 @@ public function __construct(
$this->authToken = $payload->authToken;
$this->controlEndpoint = $controlEndpoint ?? $payload->cp;
$this->cacheEndpoint = $cacheEndpoint ?? $payload->c;
$this->storageEndpoint = $storageEndpoint ?? $payload->storage;
$this->trustedControlEndpointCertificateName = $trustedControlEndpointCertificateName;
$this->trustedCacheEndpointCertificateName = $trustedCacheEndpointCertificateName;
}
Expand Down Expand Up @@ -66,6 +72,14 @@ public function getControlEndpoint(): string
return $this->controlEndpoint;
}

/**
* @return string|null The host which the Momento client will connect to for Momento storage operations.
*/
public function getStorageEndpoint(): ?string
{
return $this->storageEndpoint;
}

/**
* @return string|null Used for routing gRPC calls through a proxy server
*/
Expand Down
66 changes: 66 additions & 0 deletions src/Cache/Internal/ScsControlClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,37 @@
namespace Momento\Cache\Internal;

use Control_client\_CreateCacheRequest;
use Control_client\_CreateStoreRequest;
use Control_client\_DeleteCacheRequest;
use Control_client\_DeleteStoreRequest;
use Control_client\_FlushCacheRequest;
use Control_client\_ListCachesRequest;
use Control_client\_ListStoresRequest;
use Grpc\UnaryCall;
use Momento\Auth\ICredentialProvider;
use Momento\Cache\CacheOperationTypes\CreateCacheResponse;
use Momento\Cache\CacheOperationTypes\CreateCacheAlreadyExists;
use Momento\Cache\CacheOperationTypes\CreateCacheError;
use Momento\Cache\CacheOperationTypes\CreateCacheSuccess;
use Momento\Storage\StorageOperationTypes\CreateStoreResponse;
use Momento\Storage\StorageOperationTypes\CreateStoreAlreadyExists;
use Momento\Storage\StorageOperationTypes\CreateStoreSuccess;
use Momento\Storage\StorageOperationTypes\CreateStoreError;
use Momento\Cache\CacheOperationTypes\DeleteCacheResponse;
use Momento\Cache\CacheOperationTypes\DeleteCacheError;
use Momento\Cache\CacheOperationTypes\DeleteCacheSuccess;
use Momento\Storage\StorageOperationTypes\DeleteStoreResponse;
use Momento\Storage\StorageOperationTypes\DeleteStoreError;
use Momento\Storage\StorageOperationTypes\DeleteStoreSuccess;
use Momento\Cache\CacheOperationTypes\FlushCacheError;
use Momento\Cache\CacheOperationTypes\FlushCacheResponse;
use Momento\Cache\CacheOperationTypes\FlushCacheSuccess;
use Momento\Cache\CacheOperationTypes\ListCachesResponse;
use Momento\Cache\CacheOperationTypes\ListCachesError;
use Momento\Cache\CacheOperationTypes\ListCachesSuccess;
use Momento\Storage\StorageOperationTypes\ListStoresResponse;
use Momento\Storage\StorageOperationTypes\ListStoresError;
use Momento\Storage\StorageOperationTypes\ListStoresSuccess;
use Momento\Cache\Errors\AlreadyExistsError;
use Momento\Cache\Errors\SdkError;
use Momento\Cache\Errors\UnknownError;
Expand All @@ -30,6 +43,7 @@
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use function Momento\Utilities\validateCacheName;
use function Momento\Utilities\validateStoreName;

class ScsControlClient implements LoggerAwareInterface
{
Expand Down Expand Up @@ -132,4 +146,56 @@ public function flushCache(string $cacheName): FlushCacheResponse
return new FlushCacheSuccess();
}

public function createStore(string $storeName): CreateStoreResponse
{
try {
validateStoreName($storeName);
$request = new _CreateStoreRequest();
$request->setStoreName($storeName);
$call = $this->grpcManager->client->CreateStore($request);
$this->processCall($call);
} catch (AlreadyExistsError $e) {
return new CreateStoreAlreadyExists();
} catch (SdkError $e) {
$this->logger->debug("Failed to create store $storeName: {$e->getMessage()}");
return new CreateStoreError($e);
} catch (\Exception $e) {
$this->logger->debug("Failed to create store $storeName: {$e->getMessage()}");
return new CreateStoreError(new UnknownError($e->getMessage()));
malandis marked this conversation as resolved.
Show resolved Hide resolved
}
return new CreateStoreSuccess();
}

public function deleteStore(string $storeName): DeleteStoreResponse
{
try {
validateStoreName($storeName);
$request = new _DeleteStoreRequest();
$request->setStoreName($storeName);
$call = $this->grpcManager->client->DeleteStore($request);
$this->processCall($call);
} catch (SdkError $e) {
$this->logger->debug("Failed to delete store $storeName: {$e->getMessage()}");
return new DeleteStoreError($e);
} catch (\Exception $e) {
$this->logger->debug("Failed to delete store $storeName: {$e->getMessage()}");
return new DeleteStoreError(new UnknownError($e->getMessage()));
}
return new DeleteStoreSuccess();
}

public function listStores(?string $nextToken = null): ListStoresResponse
{
try {
$request = new _ListStoresRequest();
$request->setNextToken($nextToken ? $nextToken : "");
$call = $this->grpcManager->client->ListStores($request);
$response = $this->processCall($call);
} catch (SdkError $e) {
return new ListStoresError($e);
} catch (\Exception $e) {
return new ListStoresError(new UnknownError($e->getMessage()));
}
return new ListStoresSuccess($response);
}
}
5 changes: 2 additions & 3 deletions src/Cache/Internal/ScsDataClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
use Cache_client\_SetDifferenceRequest\_Subtrahend;
use Cache_client\_SetDifferenceRequest\_Subtrahend\_Set;
use Cache_client\_SetFetchRequest;
use Cache_client\_SetIfNotExistsRequest;
use Cache_client\_SetIfRequest;
use Cache_client\_SetLengthRequest;
use Cache_client\_SetRequest;
Expand Down Expand Up @@ -272,7 +271,7 @@ public function set(string $cacheName, string $key, string $value, $ttlSeconds =
} catch (SdkError $e) {
return ResponseFuture::createResolved(new SetError($e));
} catch (Exception $e) {
return ResponseFuture::createResolved(SetError(new UnknownError($e->getMessage(), 0, $e)));
return ResponseFuture::createResolved(new SetError(new UnknownError($e->getMessage(), 0, $e)));
}

return ResponseFuture::createPending(
Expand All @@ -282,7 +281,7 @@ function () use ($call): SetResponse {
} catch (SdkError $e) {
return new SetError($e);
} catch (Exception $e) {
return SetError(new UnknownError($e->getMessage(), 0, $e));
return new SetError(new UnknownError($e->getMessage(), 0, $e));
}

return new SetSuccess();
Expand Down
2 changes: 1 addition & 1 deletion src/Config/Configurations/InRegion.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class InRegion extends Configuration
* @param ILoggerFactory|null $loggerFactory
* @return InRegion
*/
public static function latest(?ILoggerFactory $loggerFactory = null): Laptop
public static function latest(?ILoggerFactory $loggerFactory = null): InRegion
{
return self::v1($loggerFactory);
}
Expand Down
Loading