mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-05-16 04:37:55 -04:00
78c28d4936
# Description of Changes Closes: #3533 Updated the C# SDK to handle procedures and procedure callbacks in a similar fashion to the Rust client as well as added the codegen to support it. # API and ABI breaking changes N/A # Expected complexity level and risk 2 - This adds a new testing frame that should be removed once procedures are handled with C# module bindings # Testing Added /sdks/csharp/examples~/regression-tests/procedure-client to match modules/sdk-test-procedure which we can roll into the standard regression-tests once C# supports the procedure attribute. - [x] Add C# client test of sdk-test-procedure --------- Signed-off-by: Jason Larabie <jason@clockworklabs.io>
79 lines
2.7 KiB
C#
79 lines
2.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using SpacetimeDB.BSATN;
|
|
using SpacetimeDB.ClientApi;
|
|
|
|
namespace SpacetimeDB
|
|
{
|
|
public delegate void ProcedureCallback<T>(IProcedureEventContext ctx, ProcedureCallbackResult<T> result);
|
|
|
|
public readonly struct ProcedureCallbackResult<T>
|
|
{
|
|
public readonly bool IsSuccess;
|
|
public readonly T? Value;
|
|
public readonly Exception? Error;
|
|
|
|
public static ProcedureCallbackResult<T> Success(T value) => new(true, value, null);
|
|
public static ProcedureCallbackResult<T> Failure(Exception error) => new(false, default, error);
|
|
|
|
private ProcedureCallbackResult(bool isSuccess, T? value, Exception? error)
|
|
{
|
|
IsSuccess = isSuccess;
|
|
Value = value;
|
|
Error = error;
|
|
}
|
|
}
|
|
|
|
internal sealed class ProcedureCallbacks
|
|
{
|
|
private readonly Dictionary<uint, IProcedureCallbackWrapper> callbacks = new();
|
|
|
|
public void RegisterCallback<T>(uint requestId, ProcedureCallback<T> callback)
|
|
where T : IStructuralReadWrite, new()
|
|
{
|
|
callbacks[requestId] = new ProcedureCallbackWrapper<T>(callback);
|
|
}
|
|
|
|
public bool TryResolveCallback(IProcedureEventContext ctx, uint requestId, ProcedureResult result)
|
|
{
|
|
if (callbacks.Remove(requestId, out var wrapper))
|
|
{
|
|
wrapper.Invoke(ctx, result);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
internal interface IProcedureCallbackWrapper
|
|
{
|
|
void Invoke(IProcedureEventContext ctx, ProcedureResult result);
|
|
}
|
|
|
|
internal sealed class ProcedureCallbackWrapper<T> : IProcedureCallbackWrapper
|
|
where T : IStructuralReadWrite, new()
|
|
{
|
|
private readonly ProcedureCallback<T> callback;
|
|
|
|
public ProcedureCallbackWrapper(ProcedureCallback<T> callback)
|
|
{
|
|
this.callback = callback;
|
|
}
|
|
|
|
public void Invoke(IProcedureEventContext ctx, ProcedureResult result)
|
|
{
|
|
var callbackResult = result.Status switch
|
|
{
|
|
ProcedureStatus.Returned(var bytes) =>
|
|
ProcedureCallbackResult<T>.Success(BSATNHelpers.Decode<T>(bytes.ToArray())),
|
|
ProcedureStatus.InternalError(var error) =>
|
|
ProcedureCallbackResult<T>.Failure(new Exception($"Procedure failed: {error}")),
|
|
ProcedureStatus.OutOfEnergy =>
|
|
ProcedureCallbackResult<T>.Failure(new Exception("Procedure execution aborted due to insufficient energy")),
|
|
_ => ProcedureCallbackResult<T>.Failure(new Exception("Unknown procedure status"))
|
|
};
|
|
|
|
callback(ctx, callbackResult);
|
|
}
|
|
}
|
|
} |