Skip to content

Commit

Permalink
No commit message
Browse files Browse the repository at this point in the history
  • Loading branch information
2 parents 7dac267 + ced1fd7 commit 46d0468
Show file tree
Hide file tree
Showing 14 changed files with 266 additions and 13 deletions.
1 change: 0 additions & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ jobs:
runs-on: ${{ matrix.os }}
env:
TEST_AUTH_TOKEN: ${{ secrets.ALPHA_TEST_AUTH_TOKEN }}
TEST_CACHE_NAME: client-sdk-dotnet-${{ github.sha }}-${{ matrix.target-framework }}

steps:
- name: Get current time
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/on-push-to-main-branch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ jobs:
runs-on: ${{ matrix.os }}
env:
TEST_AUTH_TOKEN: ${{ secrets.ALPHA_TEST_AUTH_TOKEN }}
TEST_CACHE_NAME: client-sdk-dotnet-${{ github.sha }}-${{ matrix.target-framework }}

steps:
- name: Get current time
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -406,3 +406,4 @@ ASALocalRun/

# VS Code
.vscode
/exportToHTML/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
Momento Cache is a fast, simple, pay-as-you-go caching solution without any of the operational overhead
required by traditional caching solutions. This repo contains the source code for the Momento .NET client library.

To get started with Momento you will need a Momento Auth Token. You can get one from the [Momento Console](https://console.gomomento.com).

* Website: [https://www.gomomento.com/](https://www.gomomento.com/)
* Momento Documentation: [https://docs.momentohq.com/](https://docs.momentohq.com/)
* Getting Started: [https://docs.momentohq.com/getting-started](https://docs.momentohq.com/getting-started)
Expand Down
38 changes: 38 additions & 0 deletions src/Momento.Sdk/CacheClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,44 @@ public async Task<CacheUpdateTtlResponse> UpdateTtlAsync(string cacheName, strin
return await this.DataClient.UpdateTtlAsync(cacheName, key, ttl);
}

/// <inheritdoc />
public async Task<CacheItemGetTtlResponse> ItemGetTtlAsync(string cacheName, byte[] key)
{
try
{
Utils.ArgumentNotNull(cacheName, nameof(cacheName));
Utils.ArgumentNotNull(key, nameof(key));
}
catch (ArgumentNullException e)
{
return new CacheItemGetTtlResponse.Error(new InvalidArgumentException(e.Message));
}
catch (ArgumentOutOfRangeException e)
{
return new CacheItemGetTtlResponse.Error(new InvalidArgumentException(e.Message));
}
return await this.DataClient.ItemGetTtlAsync(cacheName, key);
}

/// <inheritdoc />
public async Task<CacheItemGetTtlResponse> ItemGetTtlAsync(string cacheName, string key)
{
try
{
Utils.ArgumentNotNull(cacheName, nameof(cacheName));
Utils.ArgumentNotNull(key, nameof(key));
}
catch (ArgumentNullException e)
{
return new CacheItemGetTtlResponse.Error(new InvalidArgumentException(e.Message));
}
catch (ArgumentOutOfRangeException e)
{
return new CacheItemGetTtlResponse.Error(new InvalidArgumentException(e.Message));
}
return await this.DataClient.ItemGetTtlAsync(cacheName, key);
}

/// <inheritdoc />
public async Task<CacheSetResponse> SetAsync(string cacheName, byte[] key, byte[] value, TimeSpan? ttl = null)
{
Expand Down
13 changes: 12 additions & 1 deletion src/Momento.Sdk/ICacheClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,17 @@ public interface ICacheClient : IDisposable
/// <inheritdoc cref="UpdateTtlAsync(string, byte[], TimeSpan)"/>
public Task<CacheUpdateTtlResponse> UpdateTtlAsync(string cacheName, string key, TimeSpan ttl);

/// <summary>
/// Get the TTL of a cache item.
/// </summary>
/// <param name="cacheName">The name of the cache to perform the lookup in.</param>
/// <param name="key">The key to get the TTL for.</param>
/// <returns>Task representing the result of the item get TTL operation.</returns>
public Task<CacheItemGetTtlResponse> ItemGetTtlAsync(string cacheName, byte[] key);

/// <inheritdoc cref="ItemGetTtlAsync(string, byte[])"/>
public Task<CacheItemGetTtlResponse> ItemGetTtlAsync(string cacheName, string key);

/// <summary>
/// Set the value in cache with a given time to live (TTL) seconds.
/// </summary>
Expand Down Expand Up @@ -531,7 +542,7 @@ public interface ICacheClient : IDisposable
/// <param name="setName">The set to fetch.</param>
/// <returns>Task representing with the status of the fetch operation and the associated set.</returns>
public Task<CacheSetFetchResponse> SetFetchAsync(string cacheName, string setName);

/// <summary>
/// Calculate the length of a set in the cache.
///
Expand Down
7 changes: 7 additions & 0 deletions src/Momento.Sdk/Internal/DataGrpcManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public interface IDataClient
{
public Task<_KeysExistResponse> KeysExistAsync(_KeysExistRequest request, CallOptions callOptions);
public Task<_UpdateTtlResponse> UpdateTtlAsync(_UpdateTtlRequest request, CallOptions callOptions);
public Task<_ItemGetTtlResponse> ItemGetTtlAsync(_ItemGetTtlRequest request, CallOptions callOptions);
public Task<_GetResponse> GetAsync(_GetRequest request, CallOptions callOptions);
public Task<_SetResponse> SetAsync(_SetRequest request, CallOptions callOptions);
public Task<_DeleteResponse> DeleteAsync(_DeleteRequest request, CallOptions callOptions);
Expand Down Expand Up @@ -84,6 +85,12 @@ public async Task<_UpdateTtlResponse> UpdateTtlAsync(_UpdateTtlRequest request,
return await wrapped.ResponseAsync;
}

public async Task<_ItemGetTtlResponse> ItemGetTtlAsync(_ItemGetTtlRequest request, CallOptions callOptions)
{
var wrapped = await _middlewares.WrapRequest(request, callOptions, (r, o) => _generatedClient.ItemGetTtlAsync(r, o));
return await wrapped.ResponseAsync;
}

public async Task<_DeleteResponse> DeleteAsync(_DeleteRequest request, CallOptions callOptions)
{
var wrapped = await _middlewares.WrapRequest(request, callOptions, (r, o) => _generatedClient.DeleteAsync(r, o));
Expand Down
45 changes: 43 additions & 2 deletions src/Momento.Sdk/Internal/ScsDataClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ public async Task<CacheUpdateTtlResponse> UpdateTtlAsync(string cacheName, strin
return await this.SendUpdateTtlAsync(cacheName, key: key.ToByteString(), ttl: ttl);
}

public async Task<CacheItemGetTtlResponse> ItemGetTtlAsync(string cacheName, byte[] key)
{
return await this.SendItemGetTtlAsync(cacheName, key: key.ToByteString());
}

public async Task<CacheItemGetTtlResponse> ItemGetTtlAsync(string cacheName, string key)
{
return await this.SendItemGetTtlAsync(cacheName, key: key.ToByteString());
}

public async Task<CacheSetResponse> SetAsync(string cacheName, byte[] key, byte[] value, TimeSpan? ttl = null)
{
return await this.SendSetAsync(cacheName, key: key.ToByteString(), value: value.ToByteString(), ttl: ttl);
Expand Down Expand Up @@ -307,7 +317,7 @@ public async Task<CacheSetFetchResponse> SetFetchAsync(string cacheName, string
{
return await SendSetFetchAsync(cacheName, setName);
}

public async Task<CacheSetLengthResponse> SetLengthAsync(string cacheName, string setName)
{
return await SendSetLengthAsync(cacheName, setName);
Expand Down Expand Up @@ -468,6 +478,37 @@ private async Task<CacheUpdateTtlResponse> SendUpdateTtlAsync(string cacheName,
}
}

const string REQUEST_TYPE_ITEM_GET_TTL = "ITEM_GET_TTL";
private async Task<CacheItemGetTtlResponse> SendItemGetTtlAsync(string cacheName, ByteString key)
{
_ItemGetTtlRequest request = new _ItemGetTtlRequest() { CacheKey = key };
_ItemGetTtlResponse response;
var metadata = MetadataWithCache(cacheName);
try
{
this._logger.LogTraceExecutingRequest(REQUEST_TYPE_UPDATE_TTL, cacheName, key, null, null);
response = await this.grpcManager.Client.ItemGetTtlAsync(request, new CallOptions(headers: metadata, deadline: CalculateDeadline()));
}
catch (Exception e)
{
return this._logger.LogTraceRequestError(REQUEST_TYPE_UPDATE_TTL, cacheName, key, null, null, new CacheItemGetTtlResponse.Error(_exceptionMapper.Convert(e, metadata)));
}

if (response.ResultCase == _ItemGetTtlResponse.ResultOneofCase.Missing)
{
return this._logger.LogTraceRequestSuccess(REQUEST_TYPE_ITEM_GET_TTL, cacheName, key, null, null, new CacheItemGetTtlResponse.Miss());
}
else if (response.ResultCase == _ItemGetTtlResponse.ResultOneofCase.Found)
{
return this._logger.LogTraceRequestSuccess(REQUEST_TYPE_ITEM_GET_TTL, cacheName, key, null, null, new CacheItemGetTtlResponse.Hit(response));
}
else
{
return this._logger.LogTraceRequestError(REQUEST_TYPE_ITEM_GET_TTL, cacheName, key, null, null, new CacheItemGetTtlResponse.Error(
_exceptionMapper.Convert(new Exception("Unknown response type"), metadata)));
}
}

const string REQUEST_TYPE_SET = "SET";
private async Task<CacheSetResponse> SendSetAsync(string cacheName, ByteString key, ByteString value, TimeSpan? ttl = null)
{
Expand Down Expand Up @@ -939,7 +980,7 @@ private async Task<CacheSetFetchResponse> SendSetFetchAsync(string cacheName, st

return this._logger.LogTraceCollectionRequestSuccess(REQUEST_TYPE_SET_FETCH, cacheName, setName, new CacheSetFetchResponse.Miss());
}

const string REQUEST_TYPE_SET_LENGTH = "SET_LENGTH";
private async Task<CacheSetLengthResponse> SendSetLengthAsync(string cacheName, string setName)
{
Expand Down
103 changes: 103 additions & 0 deletions src/Momento.Sdk/Responses/CacheItemGetTtlResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
namespace Momento.Sdk.Responses;

using System;
using Momento.Protos.CacheClient;
using Momento.Sdk.Exceptions;

/// <summary>
/// Parent response type for a cache item get ttl request. The
/// response object is resolved to a type-safe object of one of
/// the following subtypes:
/// <list type="bullet">
/// <item><description>CacheItemGetTtlResponse.Hit</description></item>
/// <item><description>CacheItemGetTtlResponse.Miss</description></item>
/// <item><description>CacheItemGetTtlResponse.Error</description></item>
/// </list>
/// Pattern matching can be used to operate on the appropriate subtype.
/// For example:
/// <code>
/// if (response is CacheItemGetTtlResponse.Hit hitResponse)
/// {
/// // handle ttl value as appropriate
/// }
/// else if (response is CacheItemGetTtlResponse.Miss missResponse)
/// {
/// // handle key was not found as appropriate
/// }
/// else if (response is CacheItemGetTtlResponse.Error errorResponse)
/// {
/// // handle error as appropriate
/// }
/// else
/// {
/// // handle unexpected response
/// }
/// </code>
/// </summary>
public abstract class CacheItemGetTtlResponse
{
/// <summary>
/// Indicates the key was found in the cache and the ttl was returned.
/// </summary>
public class Hit : CacheItemGetTtlResponse {
/// <summary>
/// The value of the ttl.
/// </summary>
protected readonly ulong value;

/// <include file="../docs.xml" path='docs/class[@name="Hit"]/description/*' />
public Hit(_ItemGetTtlResponse response)
{
value = response.Found.RemainingTtlMillis;
}

/// <summary>
/// The value of the ttl.
/// </summary>
public TimeSpan Value
{
get => TimeSpan.FromMilliseconds(value);
}

/// <inheritdoc />
public override string ToString()
{
return $"{base.ToString()}: Value: {Value}";
}
}

/// <summary>
/// Indicates the key was not found in the cache, hence the ttl was not returned.
/// </summary>
public class Miss : CacheItemGetTtlResponse { }

/// <include file = "../docs.xml" path='docs/class[@name="Error"]/description/*' />
public class Error : CacheItemGetTtlResponse, IError
{
private readonly SdkException _error;

/// <include file = "../docs.xml" path='docs/class[@name="Error"]/constructor/*' />
public Error(SdkException error)
{
_error = error;
}

/// <inheritdoc />
public SdkException InnerException
{
get => _error;
}

/// <inheritdoc />
public MomentoErrorCode ErrorCode
{
get => _error.ErrorCode;
}

/// <inheritdoc />
public string Message
{
get => _error.Message;
}
}
}
6 changes: 3 additions & 3 deletions tests/Integration/Momento.Sdk.Tests/CacheControlTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public async Task CreateCacheAsync_NullCache_InvalidArgumentError()
public async Task FlushCacheAsync_HappyPath()
{
string cacheName = Utils.TestCacheName();
await client.CreateCacheAsync(cacheName);
Utils.CreateCacheForTest(client, cacheName);

try
{
Expand Down Expand Up @@ -113,7 +113,7 @@ public async Task ListCachesAsync_OneCache_HappyPath()
{
// Create cache
string cacheName = Utils.TestCacheName();
await client.CreateCacheAsync(cacheName);
Utils.CreateCacheForTest(client, cacheName);

// Test cache exists
ListCachesResponse result = await client.ListCachesAsync();
Expand Down Expand Up @@ -142,7 +142,7 @@ public async Task ListCachesAsync_Iteration_HappyPath()
{
String cacheName = Utils.TestCacheName();
cacheNames.Add(cacheName);
await client.CreateCacheAsync(cacheName);
Utils.CreateCacheForTest(client, cacheName);
}
try
{
Expand Down
1 change: 0 additions & 1 deletion tests/Integration/Momento.Sdk.Tests/CacheDataTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ public async Task KeysExistAsync_String()
Assert.Equal(expectedDict, goodResponse.ExistsDictionary);
}


[Theory]
[InlineData(null, new byte[] { 0x00 }, new byte[] { 0x00 })]
[InlineData("cache", null, new byte[] { 0x00 })]
Expand Down
6 changes: 2 additions & 4 deletions tests/Integration/Momento.Sdk.Tests/Fixtures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ public class CacheClientFixture : IDisposable
public CacheClientFixture()
{
AuthProvider = new EnvMomentoTokenProvider("TEST_AUTH_TOKEN");
CacheName = Environment.GetEnvironmentVariable("TEST_CACHE_NAME") ??
throw new NullReferenceException("TEST_CACHE_NAME environment variable must be set.");
CacheName = $"dotnet-integration-{Utils.NewGuidString()}";
Client = new CacheClient(Configurations.Laptop.Latest(LoggerFactory.Create(builder =>
{
builder.AddSimpleConsole(options =>
Expand All @@ -35,8 +34,7 @@ public CacheClientFixture()
builder.SetMinimumLevel(LogLevel.Information);
})),
AuthProvider, defaultTtl: DefaultTtl);

var result = Client.CreateCacheAsync(CacheName).Result;
Utils.CreateCacheForTest(Client, CacheName);
}

public void Dispose()
Expand Down
Loading

0 comments on commit 46d0468

Please sign in to comment.