Skip to content

Commit fa2e9b3

Browse files
authored
C#: Add confirmed reads configuration (#3282)
Allows the SpacetimeDBClient to be configured with or without confirmed reads. Like for [TypeScript], the parameter is optional -- the server chooses the default if not set explicitly. [TypeScript]: #3247 # Expected complexity level and risk 1 # Testing I don't actually know what I'm doing 😅
1 parent ba31c80 commit fa2e9b3

File tree

2 files changed

+49
-15
lines changed

2 files changed

+49
-15
lines changed

sdks/csharp/src/SpacetimeDBClient.cs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public sealed class DbConnectionBuilder<DbConnection>
2121
string? token;
2222
Compression? compression;
2323
bool light;
24+
bool? confirmedReads;
2425

2526
public DbConnection Build()
2627
{
@@ -32,7 +33,7 @@ public DbConnection Build()
3233
{
3334
throw new InvalidOperationException("Building DbConnection with a null nameOrAddress. Call WithModuleName() first.");
3435
}
35-
conn.Connect(token, uri, nameOrAddress, compression ?? Compression.Brotli, light);
36+
conn.Connect(token, uri, nameOrAddress, compression ?? Compression.Brotli, light, confirmedReads);
3637
#if UNITY_5_3_OR_NEWER
3738
if (SpacetimeDBNetworkManager._instance != null)
3839
{
@@ -72,6 +73,12 @@ public DbConnectionBuilder<DbConnection> WithLightMode(bool light)
7273
return this;
7374
}
7475

76+
public DbConnectionBuilder<DbConnection> WithConfirmedReads(bool confirmedReads)
77+
{
78+
this.confirmedReads = confirmedReads;
79+
return this;
80+
}
81+
7582
public delegate void ConnectCallback(DbConnection conn, Identity identity, string token);
7683

7784
public DbConnectionBuilder<DbConnection> OnConnect(ConnectCallback cb)
@@ -99,7 +106,7 @@ public DbConnectionBuilder<DbConnection> OnDisconnect(DisconnectCallback cb)
99106

100107
public interface IDbConnection
101108
{
102-
internal void Connect(string? token, string uri, string addressOrName, Compression compression, bool light);
109+
internal void Connect(string? token, string uri, string addressOrName, Compression compression, bool light, bool? confirmedReads);
103110

104111
internal void AddOnConnect(Action<Identity, string> cb);
105112
internal void AddOnConnectError(WebSocket.ConnectErrorEventHandler cb);
@@ -184,7 +191,7 @@ protected DbConnectionBase()
184191
SpacetimeDBNetworkManager._instance.RemoveConnection(this);
185192
}
186193
};
187-
194+
188195
#if UNITY_WEBGL && !UNITY_EDITOR
189196
if (SpacetimeDBNetworkManager._instance != null)
190197
SpacetimeDBNetworkManager._instance.StartCoroutine(ParseMessages());
@@ -484,7 +491,22 @@ public void Disconnect()
484491
/// </summary>
485492
/// <param name="uri"> URI of the SpacetimeDB server (ex: https://testnet.spacetimedb.com)
486493
/// <param name="addressOrName">The name or address of the database to connect to</param>
487-
void IDbConnection.Connect(string? token, string uri, string addressOrName, Compression compression, bool light)
494+
/// <param name="compression">The compression settings to use</param>
495+
/// <param name="light">Whether or not to request light updates</param>
496+
/// <param name="confirmedReads">
497+
/// If set to true, instruct the server to send updates for transactions
498+
/// only after they are confirmed to be durable.
499+
///
500+
/// What durable means depends on the server configuration. In general,
501+
/// a transaction is durable when it has been written to disk on one or
502+
/// more servers.
503+
///
504+
/// If set to false, instruct the server to send updates as soon as
505+
/// transactions are committed in memory.
506+
///
507+
/// If not set, the server chooses the default.
508+
/// </param>
509+
void IDbConnection.Connect(string? token, string uri, string addressOrName, Compression compression, bool light, bool? confirmedReads)
488510
{
489511
isClosing = false;
490512

@@ -509,7 +531,7 @@ async Task Function()
509531
{
510532
try
511533
{
512-
await webSocket.Connect(token, uri, addressOrName, ConnectionId, compression, light);
534+
await webSocket.Connect(token, uri, addressOrName, ConnectionId, compression, light, confirmedReads);
513535
}
514536
catch (Exception e)
515537
{
@@ -879,8 +901,8 @@ void IDbConnection.Unsubscribe(QueryId queryId)
879901
/// Represents the result of parsing a database update message from SpacetimeDB.
880902
/// Contains updates for all tables affected by the update, with each entry mapping a table handle
881903
/// to its respective set of row changes (by primary key or row instance).
882-
///
883-
/// Note: Due to C#'s struct constructor limitations, you must use <see cref="ParsedDatabaseUpdate.New"/>
904+
///
905+
/// Note: Due to C#'s struct constructor limitations, you must use <see cref="ParsedDatabaseUpdate.New"/>
884906
/// to create new instances.
885907
/// Do not use the default constructor, as it will not initialize the Updates dictionary.
886908
/// </summary>

sdks/csharp/src/WebSocket.cs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public WebSocket(ConnectOptions options)
6161
private bool _isConnected = false;
6262
private bool _isConnecting = false;
6363
public bool IsConnected => _isConnected;
64-
#else
64+
#else
6565
public bool IsConnected { get { return Ws != null && Ws.State == WebSocketState.Open; } }
6666
#endif
6767

@@ -136,22 +136,28 @@ private void InitializeWebGL()
136136
var messagePtr = Marshal.GetFunctionPointerForDelegate((Action<int, IntPtr, int>)WebGLOnMessage);
137137
var closePtr = Marshal.GetFunctionPointerForDelegate((Action<int, int, IntPtr>)WebGLOnClose);
138138
var errorPtr = Marshal.GetFunctionPointerForDelegate((Action<int>)WebGLOnError);
139-
139+
140140
WebSocket_Init(openPtr, messagePtr, closePtr, errorPtr);
141141
}
142142
#endif
143143

144-
public async Task Connect(string? auth, string host, string nameOrAddress, ConnectionId connectionId, Compression compression, bool light)
144+
public async Task Connect(string? auth, string host, string nameOrAddress, ConnectionId connectionId, Compression compression, bool light, bool? confirmedReads)
145145
{
146146
#if UNITY_WEBGL && !UNITY_EDITOR
147147
if (_isConnecting || _isConnected) return;
148-
148+
149149
_isConnecting = true;
150150
try
151151
{
152152
var uri = $"{host}/v1/database/{nameOrAddress}/subscribe?connection_id={connectionId}&compression={compression}";
153153
if (light) uri += "&light=true";
154-
154+
if (confirmedReads.HasValue)
155+
{
156+
// Ensure to transmit the bool as lowercase.
157+
var enabled = confirmedReads.GetValueOrDefault() ? "true" : "false";
158+
uri += $"&confirmed={enabled}";
159+
}
160+
155161
_socketId = new TaskCompletionSource<int>();
156162
var callbackPtr = Marshal.GetFunctionPointerForDelegate((Action<int>)OnSocketIdReceived);
157163
WebSocket_Connect(host, uri, _options.Protocol, auth, callbackPtr);
@@ -177,6 +183,12 @@ public async Task Connect(string? auth, string host, string nameOrAddress, Conne
177183
{
178184
uri += "&light=true";
179185
}
186+
if (confirmedReads.HasValue)
187+
{
188+
// Ensure to transmit the bool as lowercase.
189+
var enabled = confirmedReads.GetValueOrDefault() ? "true" : "false";
190+
uri += $"&confirmed={enabled}";
191+
}
180192
var url = new Uri(uri);
181193
Ws.Options.AddSubProtocol(_options.Protocol);
182194

@@ -457,15 +469,15 @@ public void HandleWebGLOpen(int socketId)
457469
dispatchQueue.Enqueue(() => OnConnect());
458470
}
459471
}
460-
472+
461473
public void HandleWebGLMessage(int socketId, byte[] message)
462474
{
463475
if (socketId == _webglSocketId && OnMessage != null)
464476
{
465477
dispatchQueue.Enqueue(() => OnMessage(message, DateTime.UtcNow));
466478
}
467479
}
468-
480+
469481
public void HandleWebGLClose(int socketId, int code, string reason)
470482
{
471483
UnityEngine.Debug.Log($"HandleWebGLClose: {code} {reason}");
@@ -476,7 +488,7 @@ public void HandleWebGLClose(int socketId, int code, string reason)
476488
dispatchQueue.Enqueue(() => OnClose?.Invoke(ex));
477489
}
478490
}
479-
491+
480492
public void HandleWebGLError(int socketId)
481493
{
482494
UnityEngine.Debug.Log($"HandleWebGLError: {socketId}");

0 commit comments

Comments
 (0)