Skip to content

Commit

Permalink
Adds Counter methods to CSharp SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
igooch committed Feb 5, 2024
1 parent 5f58fce commit 5c6b7fa
Show file tree
Hide file tree
Showing 5 changed files with 485 additions and 6 deletions.
4 changes: 3 additions & 1 deletion build/includes/sdk.mk
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ DEFAULT_CONFORMANCE_TESTS = ready,allocate,setlabel,setannotation,gameserver,hea
ALPHA_CONFORMANCE_TESTS = getplayercapacity,setplayercapacity,playerconnect,playerdisconnect,getplayercount,isplayerconnected,getconnectedplayers
# TODO: Move Counter and List tests into ALPHA_CONFORMANCE_TESTS once the they are written for all SDKs
COUNTS_AND_LISTS_TESTS = getcounter,updatecounter,setcountcounter,setcapacitycounter,getlist,updatelist,addlistvalue,removelistvalue
# TODO: Remove once Lists are implemented for csharp and use COUNTS_AND_LISTS_TESTS instead
COUNTERS_TESTS = getcounter,updatecounter,setcountcounter,setcapacitycounter

.PHONY: test-sdks test-sdk build-sdks build-sdk gen-all-sdk-grpc gen-sdk-grpc run-all-sdk-command run-sdk-command build-example

Expand Down Expand Up @@ -187,7 +189,7 @@ run-sdk-conformance-test-csharp:
# run without feature flags
$(MAKE) run-sdk-conformance-test SDK_FOLDER=csharp GRPC_PORT=9005 HTTP_PORT=9105
# run with feature flags enabled
$(MAKE) run-sdk-conformance-test SDK_FOLDER=csharp GRPC_PORT=9005 HTTP_PORT=9105 FEATURE_GATES=PlayerTracking=true TESTS=$(DEFAULT_CONFORMANCE_TESTS),$(ALPHA_CONFORMANCE_TESTS)
$(MAKE) run-sdk-conformance-test SDK_FOLDER=csharp GRPC_PORT=9005 HTTP_PORT=9105 FEATURE_GATES=$(ALPHA_FEATURE_GATES) TESTS=$(DEFAULT_CONFORMANCE_TESTS),$(ALPHA_CONFORMANCE_TESTS),$(COUNTERS_TESTS)

run-sdk-conformance-test-rest:
# (note: the restapi folder doesn't use GRPC_PORT but run-sdk-conformance-no-build defaults it, so we supply a unique value here)
Expand Down
189 changes: 185 additions & 4 deletions sdks/csharp/sdk/Alpha.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public Alpha(
{
_logger = logger;
RequestTimeoutSec = requestTimeoutSec;

if (cancellationTokenSource == null)
{
cts = new CancellationTokenSource();
Expand All @@ -60,7 +60,7 @@ public Alpha(
cts = cancellationTokenSource;
ownsCts = false;
}

ctoken = cts.Token;
client = new SDK.SDKClient(channel);
}
Expand Down Expand Up @@ -210,6 +210,187 @@ public async Task<List<string>> GetConnectedPlayersAsync()
}
}

/// <summary>
/// GetCounterCountAsync returns the Count for a Counter, given the Counter's key (name).
/// Will error if the key was not predefined in the GameServer resource on creation.
/// </summary>
/// <returns>The Counter's Count</returns>
public async Task<long> GetCounterCountAsync(string key)
{
try
{
var request = new GetCounterRequest()
{
Name = key,
};
var counter = await client.GetCounterAsync(request,
deadline: DateTime.UtcNow.AddSeconds(RequestTimeoutSec), cancellationToken: ctoken);
return counter.Count;
}
catch (RpcException ex)
{
LogError(ex, $"Unable to invoke GetCounterCount({key}).");
throw;
}
}

/// <summary>
/// IncrementCounterAsync increases a counter by the given nonnegative integer amount.
/// Will execute the increment operation against the current CRD value. Will max at max(int64).
/// Will error if the key was not predefined in the GameServer resource on creation.
/// Returns false if the count is at the current capacity (to the latest knowledge of the SDK),
/// and no increment will occur.
///
/// Note: A potential race condition here is that if count values are set from both the SDK and
/// through the K8s API (Allocation or otherwise), since the SDK append operation back to the CRD
/// value is batched asynchronous any value incremented past the capacity will be silently truncated.
/// </summary>
/// <returns>True if the increment counter request was successful.</returns>
public async Task<bool> IncrementCounterAsync(string key, long amount)
{
if (amount < 0)
{
throw new ArgumentOutOfRangeException($"CountIncrement amount must be a positive number, found {amount}");
}
try
{
var request = new CounterUpdateRequest()
{
Name = key,
CountDiff = amount,
};
var updateRequest = new UpdateCounterRequest()
{
CounterUpdateRequest = request,
};
var response = await client.UpdateCounterAsync(updateRequest,
deadline: DateTime.UtcNow.AddSeconds(RequestTimeoutSec), cancellationToken: ctoken);
// If we get a response (Counter) without an error, then the request was successful.
return true;
}
catch (RpcException ex)
{
LogError(ex, $"Unable to invoke IncrementCounter({key}, {amount}).");
throw;
}
}

/// <summary>
/// DecrementCounterAsync decreases the current count by the given nonnegative integer amount.
/// The Counter Will not go below 0. Will execute the decrement operation against the current CRD value.
/// Returns false if the count is at 0 (to the latest knowledge of the SDK), and no decrement will occur.
/// </summary>
/// <returns>True if the decrement counter request was successful.</returns>
public async Task<bool> DecrementCounterAsync(string key, long amount)
{
if (amount < 0)
{
throw new ArgumentOutOfRangeException($"DecrementCounter amount must be a positive number, found {amount}");
}
try
{
var request = new CounterUpdateRequest()
{
Name = key,
CountDiff = amount * -1,
};
var updateRequest = new UpdateCounterRequest()
{
CounterUpdateRequest = request,
};
var response = await client.UpdateCounterAsync(updateRequest,
deadline: DateTime.UtcNow.AddSeconds(RequestTimeoutSec), cancellationToken: ctoken);
return true;
}
catch (RpcException ex)
{
LogError(ex, $"Unable to invoke DecrementCounter({key}, {amount}).");
throw;
}
}

/// <summary>
/// SetCounterCountAsync sets a count to the given value. Use with care, as this will
/// overwrite any previous invocations’ value. Cannot be greater than Capacity.
/// </summary>
/// <returns>True if the set Counter count request was successful.</returns>
public async Task<bool> SetCounterCountAsync(string key, long amount)
{
try
{
var request = new CounterUpdateRequest()
{
Name = key,
Count = amount,
};
var updateRequest = new UpdateCounterRequest()
{
CounterUpdateRequest = request,
};
var response = await client.UpdateCounterAsync(updateRequest,
deadline: DateTime.UtcNow.AddSeconds(RequestTimeoutSec), cancellationToken: ctoken);
return true;
}
catch (RpcException ex)
{
LogError(ex, $"Unable to invoke SetCounterCount({key}, {amount}).");
throw;
}
}

/// <summary>
/// GetCounterCapacityAsync returns the Capacity for a Counter, given the Counter's key (name).
/// Will error if the key was not predefined in the GameServer resource on creation.
/// </summary>
/// <returns>The Counter's capacity</returns>
public async Task<long> GetCounterCapacityAsync(string key)
{
try
{
var request = new GetCounterRequest()
{
Name = key,
};
var counter = await client.GetCounterAsync(request,
deadline: DateTime.UtcNow.AddSeconds(RequestTimeoutSec), cancellationToken: ctoken);
return counter.Capacity;
}
catch (RpcException ex)
{
LogError(ex, $"Unable to invoke GetCounterCapacity({key}).");
throw;
}
}

/// <summary>
/// SetCounterCapacityAsync sets the capacity for the given Counter.
/// A capacity of 0 is no capacity.
/// </summary>
/// <returns>True if the set Counter capacity request was successful.</returns>
public async Task<bool> SetCounterCapacityAsync(string key, long amount)
{
try
{
var request = new CounterUpdateRequest()
{
Name = key,
Capacity = amount,
};
var updateRequest = new UpdateCounterRequest()
{
CounterUpdateRequest = request,
};
var response = await client.UpdateCounterAsync(updateRequest,
deadline: DateTime.UtcNow.AddSeconds(RequestTimeoutSec), cancellationToken: ctoken);
return true;
}
catch (RpcException ex)
{
LogError(ex, $"Unable to invoke SetCounterCapacity({key}, {amount}).");
throw;
}
}

public void Dispose()
{
if (_disposed)
Expand All @@ -218,12 +399,12 @@ public void Dispose()
}

cts.Cancel();

if (ownsCts)
{
cts.Dispose();
}

_disposed = true;
GC.SuppressFinalize(this);
}
Expand Down
6 changes: 6 additions & 0 deletions sdks/csharp/sdk/IAgonesAlphaSDK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,11 @@ public interface IAgonesAlphaSDK : IDisposable
Task<long> GetPlayerCountAsync();
Task<bool> IsPlayerConnectedAsync(string id);
Task<List<string>> GetConnectedPlayersAsync();
Task<long> GetCounterCountAsync(string key);
Task<bool> IncrementCounterAsync(string key, long amount);
Task<bool> DecrementCounterAsync(string key, long amount);
Task<bool> SetCounterCountAsync(string key, long amount);
Task<long> GetCounterCapacityAsync(string key);
Task<bool> SetCounterCapacityAsync(string key, long amount);
}
}
Loading

0 comments on commit 5c6b7fa

Please sign in to comment.