Skip to content

Commit

Permalink
No commit message
Browse files Browse the repository at this point in the history
  • Loading branch information
2 parents 3ddf538 + e3cead4 commit b047ba4
Show file tree
Hide file tree
Showing 15 changed files with 101 additions and 25 deletions.
2 changes: 1 addition & 1 deletion examples/DictionaryExample/DictionaryExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="Momento.Sdk" Version="1.8.0" />
<PackageReference Include="Momento.Sdk" Version="1.9.0" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion examples/MomentoApplication/MomentoApplication.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Momento.Sdk" Version="1.8.0" />
<PackageReference Include="Momento.Sdk" Version="1.9.0" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 0 additions & 2 deletions examples/MomentoExamples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MomentoUsage", "MomentoUsag
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DictionaryExample", "DictionaryExample\DictionaryExample.csproj", "{61F79DA8-BA7F-4F6E-B4EA-29DACF9C7571}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Momento.Sdk", "..\src\Momento.Sdk\Momento.Sdk.csproj", "{ABDFBF7A-9639-4449-91E3-4558C366D297}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Momento.Sdk\Momento.Sdk.csproj" />
<PackageReference Include="Momento.Sdk" Version="1.9.0" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion examples/MomentoLoadGen/MomentoLoadGen.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Momento.Sdk" Version="1.8.0" />
<PackageReference Include="Momento.Sdk" Version="1.9.0" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion examples/MomentoUsage/MomentoUsage.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Momento.Sdk" Version="1.8.0" />
<PackageReference Include="Momento.Sdk" Version="1.9.0" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion src/Momento.Sdk/Auth/EnvMomentoTokenProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public EnvMomentoTokenProvider(string name)
this.envVarName = name;
if (String.IsNullOrEmpty(name))
{
throw new InvalidArgumentException($"Environment variable name is empty or null.");
throw new InvalidArgumentException($"Environment variable '{name}' is empty or null.");
}

AuthToken = Environment.GetEnvironmentVariable(name);
Expand Down
15 changes: 11 additions & 4 deletions src/Momento.Sdk/Auth/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Momento.Sdk.Auth;

internal class TokenAndEndpoints
{
public string AuthToken { get; }
public string AuthToken { get; }
public string ControlEndpoint { get; }
public string CacheEndpoint { get; }

Expand All @@ -29,8 +29,15 @@ internal static class AuthUtils
{
public static bool IsBase64String(string base64)
{
Span<byte> buffer = new Span<byte>(new byte[base64.Length]);
return Convert.TryFromBase64String(base64, buffer, out int bytesParsed);
try
{
Convert.FromBase64String(base64);
return true;
}
catch (Exception)
{
return false;
}
}

public static TokenAndEndpoints TryDecodeAuthToken(string authToken)
Expand All @@ -47,7 +54,7 @@ public static TokenAndEndpoints TryDecodeAuthToken(string authToken)
throw new InvalidArgumentException("");
}
return new TokenAndEndpoints(
decodedToken.api_key,
decodedToken.api_key!,
"control." + decodedToken.endpoint,
"cache." + decodedToken.endpoint
);
Expand Down
28 changes: 28 additions & 0 deletions src/Momento.Sdk/Config/Configurations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,5 +163,33 @@ public static IConfiguration V1(ILoggerFactory? loggerFactory = null)
return new LowLatency(finalLoggerFactory, retryStrategy, transportStrategy);
}
}

/// <summary>
/// This config optimizes for lambda environments. In addition to the in region settings of
/// <see cref="Default"/>, this configures the clients to eagerly connect to the Momento service
/// to avoid the cold start penalty of establishing a connection on the first request.
/// </summary>
public class Lambda : Configuration
{
private Lambda(ILoggerFactory loggerFactory, IRetryStrategy retryStrategy, ITransportStrategy transportStrategy)
: base(loggerFactory, retryStrategy, transportStrategy)
{

}

/// <summary>
/// Provides the latest recommended configuration for a lambda environment.
/// </summary>
/// <param name="loggerFactory"></param>
/// <returns></returns>
public static IConfiguration Latest(ILoggerFactory? loggerFactory = null)
{
var config = Default.V1(loggerFactory);
var transportStrategy = config.TransportStrategy.WithEagerConnectionTimeout(
TimeSpan.FromSeconds(30)
);
return config.WithTransportStrategy(transportStrategy);
}
}
}
}
27 changes: 27 additions & 0 deletions src/Momento.Sdk/Internal/ExtensionMethods/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,30 @@ public static IDictionary<string, string> Clone(this IDictionary<string, string>
return new Dictionary<string, string>(dictionary);
}
}


/// <summary>
/// Defines extension methods to operate on dictionaries with
/// generic keys and values.
/// </summary>
public static class DictionaryExtensions
{
/// <summary>
/// Add all items in <paramref name="items"/> to <paramref name="dictionary"/>.
/// </summary>
/// <remark>
/// We add this since the .NET Framework does not have a constructor that takes an
/// <see cref="IEnumerable{T}"/>.
/// </remark>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="dictionary">The dictionary to add the items to.</param>
/// <param name="items">The key-value pairs to add.</param>
public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, IEnumerable<KeyValuePair<TKey, TValue>> items)
{
foreach (var item in items)
{
dictionary.Add(item);
}
}
}
2 changes: 1 addition & 1 deletion src/Momento.Sdk/Momento.Sdk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Build Configuration -->
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<!-- Include documentation in build -->
Expand Down
17 changes: 10 additions & 7 deletions src/Momento.Sdk/Responses/CacheDictionaryFetchResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,23 @@ public Hit(_DictionaryFetchResponse response)
items = response.Found.Items;
_dictionaryByteArrayByteArray = new(() =>
{
return new Dictionary<byte[], byte[]>(
items.Select(kv => new KeyValuePair<byte[], byte[]>(kv.Field.ToByteArray(), kv.Value.ToByteArray())),
Utils.ByteArrayComparer);
var dictionary = new Dictionary<byte[], byte[]>(Utils.ByteArrayComparer);
dictionary.AddRange(items.Select(kv => new KeyValuePair<byte[], byte[]>(kv.Field.ToByteArray(), kv.Value.ToByteArray())));
return dictionary;
});

_dictionaryStringString = new(() =>
{
return new Dictionary<string, string>(
items.Select(kv => new KeyValuePair<string, string>(kv.Field.ToStringUtf8(), kv.Value.ToStringUtf8())));
var dictionary = new Dictionary<string, string>();
dictionary.AddRange(items.Select(kv => new KeyValuePair<string, string>(kv.Field.ToStringUtf8(), kv.Value.ToStringUtf8())));
return dictionary;
});
_dictionaryStringByteArray = new(() =>
{
return new Dictionary<string, byte[]>(
items.Select(kv => new KeyValuePair<string, byte[]>(kv.Field.ToStringUtf8(), kv.Value.ToByteArray())));
var dictionary = new Dictionary<string, byte[]>();
dictionary.AddRange(items.Select(kv => new KeyValuePair<string, byte[]>(kv.Field.ToStringUtf8(), kv.Value.ToByteArray())));
return dictionary;
});
}

Expand Down
15 changes: 10 additions & 5 deletions src/Momento.Sdk/Responses/CacheDictionaryGetFieldsResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,26 +87,31 @@ public Hit(IEnumerable<ByteString> fields, _DictionaryGetResponse responses)

_dictionaryByteArrayByteArray = new(() =>
{
return new Dictionary<byte[], byte[]>(
var dictionary = new Dictionary<byte[], byte[]>(Utils.ByteArrayComparer);
dictionary.AddRange(
fields.Zip(responses.Found.Items, (f, r) => new ValueTuple<ByteString, _DictionaryGetResponsePart>(f, r))
.Where(pair => pair.Item2.Result == ECacheResult.Hit)
.Select(pair => new KeyValuePair<byte[], byte[]>(pair.Item1.ToByteArray(), pair.Item2.CacheBody.ToByteArray())),
Utils.ByteArrayComparer);
.Select(pair => new KeyValuePair<byte[], byte[]>(pair.Item1.ToByteArray(), pair.Item2.CacheBody.ToByteArray())));
return dictionary;
});

_dictionaryStringString = new(() =>
{
return new Dictionary<string, string>(
var dictionary = new Dictionary<string, string>();
dictionary.AddRange(
fields.Zip(responses.Found.Items, (f, r) => new ValueTuple<ByteString, _DictionaryGetResponsePart>(f, r))
.Where(pair => pair.Item2.Result == ECacheResult.Hit)
.Select(pair => new KeyValuePair<string, string>(pair.Item1.ToStringUtf8(), pair.Item2.CacheBody.ToStringUtf8())));
return dictionary;
});
_dictionaryStringByteArray = new(() =>
{
return new Dictionary<string, byte[]>(
var dictionary = new Dictionary<string, byte[]>();
dictionary.AddRange(
fields.Zip(responses.Found.Items, (f, r) => new ValueTuple<ByteString, _DictionaryGetResponsePart>(f, r))
.Where(pair => pair.Item2.Result == ECacheResult.Hit)
.Select(pair => new KeyValuePair<string, byte[]>(pair.Item1.ToStringUtf8(), pair.Item2.CacheBody.ToByteArray())));
return dictionary;
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public void CacheClientConstructor_EagerConnection_BadEndpoint()
var config = Configurations.Laptop.Latest(loggerFactory);
config = config.WithTransportStrategy(config.TransportStrategy.WithEagerConnectionTimeout(TimeSpan.FromSeconds(2)));
var authProviderWithBadCacheEndpoint = authProvider.WithCacheEndpoint("cache.cell-external-beta-1.prod.a.momentohq.com:65000");
Console.WriteLine($"Hello developer! We are about to run a test that verifies that the cache client is still operational even if our eager connection (ping) fails. So you will see the test log a warning message about that. It's expected, don't worry!");
// validating that the constructor doesn't fail when the eager connection fails
var client = new CacheClient(config, authProviderWithBadCacheEndpoint, defaultTtl);
}
Expand Down
7 changes: 7 additions & 0 deletions tests/Unit/Momento.Sdk.Tests/ConfigTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,11 @@ public void V1VConfigs_EqualLatest_HappyPath()
Assert.Equal(Configurations.InRegion.Default.Latest(), Configurations.InRegion.Default.V1());
Assert.Equal(Configurations.InRegion.LowLatency.Latest(), Configurations.InRegion.LowLatency.V1());
}

[Fact]
public void LambdaLatest_HasEagerConnectionTimeout_HappyPath()
{
var config = Configurations.InRegion.Lambda.Latest();
Assert.Equal(TimeSpan.FromSeconds(30), config.TransportStrategy.EagerConnectionTimeout);
}
}

0 comments on commit b047ba4

Please sign in to comment.