From a9053c5420770f9af5e498a0a09de54ab0d2b1ed Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Mon, 13 May 2024 12:07:28 -0400 Subject: [PATCH] Switch to TaskCompletionSource (#89) ## Description of Changes There is only one place where we use Channels, and it's to create and await a channel with one element - which is functionally the same as a more precise and low-weight TaskCompletionSource. Switching also makes the SDK compatible with the widely supported .NET Standard 2.1 subset, which is supported natively in Unity and allows to remove a custom System.Threading.Channels package from Unity SDK dependencies. ## API - [ ] This is an API breaking change to the SDK *If the API is breaking, please state below what will break* ## Requires SpacetimeDB PRs *List any PRs here that are required for this SDK change to work* --- SpacetimeDB.ClientSDK.csproj | 2 +- src/SpacetimeDBClient.cs | 28 +++++++++++----------------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/SpacetimeDB.ClientSDK.csproj b/SpacetimeDB.ClientSDK.csproj index ea112980..f8790c37 100644 --- a/SpacetimeDB.ClientSDK.csproj +++ b/SpacetimeDB.ClientSDK.csproj @@ -1,7 +1,7 @@ - net7.0 + netstandard2.1 9 disable enable diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs index bddc4e6c..1a7bb192 100644 --- a/src/SpacetimeDBClient.cs +++ b/src/SpacetimeDBClient.cs @@ -8,12 +8,10 @@ using System.Reflection; using System.Text; using System.Threading; -using System.Threading.Channels; using System.Threading.Tasks; using ClientApi; using Newtonsoft.Json; using SpacetimeDB.SATS; -using Channel = System.Threading.Channels.Channel; using Thread = System.Threading.Thread; namespace SpacetimeDB @@ -101,14 +99,11 @@ public struct DbOp private bool connectionClosed; public static ClientCache clientDB; - public static Dictionary> reducerEventCache = - new Dictionary>(); + private static Dictionary> reducerEventCache = new(); - public static Dictionary> deserializeEventCache = - new Dictionary>(); + private static Dictionary> deserializeEventCache = new(); - private static Dictionary> waitingOneOffQueries = - new Dictionary>(); + private static Dictionary> waitingOneOffQueries = new(); private bool isClosing; private Thread networkMessageProcessThread; @@ -459,16 +454,15 @@ HashSet GetInsertHashSet(string tableName, int tableSize) case ClientApi.Message.TypeOneofCase.OneOffQueryResponse: /// This case does NOT produce a list of DBOps, because it should not modify the client cache state! var resp = message.OneOffQueryResponse; - Guid messageId = new Guid(resp.MessageId.Span); + var messageId = new Guid(resp.MessageId.Span); - if (!waitingOneOffQueries.ContainsKey(messageId)) + if (!waitingOneOffQueries.Remove(messageId, out var resultSource)) { Logger.LogError("Response to unknown one-off-query: " + messageId); break; } - waitingOneOffQueries[messageId].Writer.TryWrite(resp); - waitingOneOffQueries.Remove(messageId); + resultSource.SetResult(resp); break; } @@ -897,10 +891,10 @@ public void Subscribe(List queries) /// Usage: SpacetimeDBClient.instance.OneOffQuery("WHERE sender = \"bob\""); public async Task OneOffQuery(string query) where T : IDatabaseTable { - Guid messageId = Guid.NewGuid(); - Type type = typeof(T); - Channel resultChannel = Channel.CreateBounded(1); - waitingOneOffQueries[messageId] = resultChannel; + var messageId = Guid.NewGuid(); + var type = typeof(T); + var resultSource = new TaskCompletionSource(); + waitingOneOffQueries[messageId] = resultSource; // unsanitized here, but writes will be prevented serverside. // the best they can do is send multiple selects, which will just result in them getting no data back. @@ -913,7 +907,7 @@ public async Task OneOffQuery(string query) where T : IDatabaseTable webSocket.Send(Encoding.UTF8.GetBytes(serializedQuery)); // Suspend for an arbitrary amount of time - var result = await resultChannel.Reader.ReadAsync(); + var result = await resultSource.Task; T[] LogAndThrow(string error) {