Skip to content

Commit a608262

Browse files
committed
CodeRabbit requested changes
1 parent 8341e12 commit a608262

File tree

5 files changed

+44
-73
lines changed

5 files changed

+44
-73
lines changed

Parse.Tests/LiveQueryMessageBuilderTests.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public async Task TestBuildConnectMessage()
4848
Assert.IsTrue(message.ContainsKey("applicationId"));
4949
Assert.IsTrue(message.ContainsKey("windowsKey"));
5050
Assert.IsTrue(message.ContainsKey("sessionToken"));
51-
Assert.HasCount(4, message);
51+
Assert.AreEqual(4, message.Count);
5252
Assert.AreEqual("connect", message["op"]);
5353
Assert.AreEqual(Client.Services.LiveQueryServerConnectionData.ApplicationID, message["applicationId"]);
5454
Assert.AreEqual(Client.Services.LiveQueryServerConnectionData.Key, message["windowsKey"]);
@@ -65,17 +65,17 @@ public void TestBuildUnsubscribeMessage()
6565
Assert.IsNotNull(message);
6666
Assert.IsTrue(message.ContainsKey("op"));
6767
Assert.IsTrue(message.ContainsKey("requestId"));
68-
Assert.HasCount(2, message);
68+
Assert.AreEqual(2, message.Count);
6969
Assert.AreEqual("unsubscribe", message["op"]);
7070
Assert.AreEqual(requestId, message["requestId"]);
7171

72-
Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => builder.BuildUnsubscribeMessage(0));
72+
Assert.ThrowsException<ArgumentOutOfRangeException>(() => builder.BuildUnsubscribeMessage(0));
7373
}
7474

7575
private void ValidateSubscriptionMessage(IDictionary<string, object> message, string expectedOp, int requestId)
7676
{
7777
Assert.IsNotNull(message);
78-
Assert.HasCount(4, message);
78+
Assert.AreEqual(4, message.Count);
7979

8080
Assert.IsTrue(message.ContainsKey("op"));
8181
Assert.AreEqual(expectedOp, message["op"]);
@@ -84,28 +84,28 @@ private void ValidateSubscriptionMessage(IDictionary<string, object> message, st
8484
Assert.AreEqual(requestId, message["requestId"]);
8585

8686
Assert.IsTrue(message.ContainsKey("query"));
87-
Assert.IsInstanceOfType<IDictionary<string, object>>(message["query"], "The 'query' value should be a Dictionary<string, object>.");
88-
Assert.HasCount(4, (IDictionary<string, object>) message["query"]);
87+
Assert.IsInstanceOfType(message["query"], typeof(IDictionary<string, object>), "The 'query' value should be a Dictionary<string, object>.");
88+
Assert.AreEqual(4, ((IDictionary<string, object>) message["query"]).Count);
8989
IDictionary<string, object> query = message["query"] as IDictionary<string, object>;
9090

9191
Assert.IsTrue(query.ContainsKey("className"), "The 'query' dictionary should contain the 'className' key.");
9292
Assert.AreEqual("DummyClass", query["className"], "The 'className' property should be 'DummyClass'.");
9393

9494
Assert.IsTrue(query.ContainsKey("where"), "The 'query' dictionary should contain the 'where' key.");
95-
Assert.IsInstanceOfType<IDictionary<string, object>>(query["where"], "The 'where' property should be a Dictionary<string, object>.");
95+
Assert.IsInstanceOfType(query["where"], typeof(IDictionary<string, object>), "The 'where' property should be a Dictionary<string, object>.");
9696
IDictionary<string, object> where = (IDictionary<string, object>) query["where"];
97-
Assert.HasCount(1, where, "The 'where' dictionary should contain exactly one key-value pair.");
97+
Assert.AreEqual(1, where.Count, "The 'where' dictionary should contain exactly one key-value pair.");
9898
Assert.IsTrue(where.ContainsKey("foo"), "The 'where' dictionary should contain the 'foo' key.");
9999
Assert.AreEqual("bar", where["foo"], "The 'foo' property in 'where' should be 'bar'.");
100100

101101
Assert.IsTrue(query.ContainsKey("keys"), "The 'query' dictionary should contain the 'keys' key.");
102-
Assert.IsInstanceOfType<string[]>(query["keys"], "The 'keys' property should be a string array.");
103-
Assert.HasCount(1, (string[]) query["keys"], "The 'keys' array should contain exactly one element.");
102+
Assert.IsInstanceOfType(query["keys"], typeof(string[]), "The 'keys' property should be a string array.");
103+
Assert.AreEqual(1, ((string[]) query["keys"]).Length, "The 'keys' array should contain exactly one element.");
104104
Assert.AreEqual("foo", ((string[]) query["keys"])[0], "The 'keys' parameter should contain 'foo'.");
105105

106106
Assert.IsTrue(query.ContainsKey("watch"), "The 'query' dictionary should contain the 'watch' key.");
107-
Assert.IsInstanceOfType<string[]>(query["watch"], "The 'watch' property should be a string array.");
108-
Assert.HasCount(1, (string[]) query["watch"], "The 'watch' array should contain exactly one element.");
107+
Assert.IsInstanceOfType(query["watch"], typeof(string[]), "The 'watch' property should be a string array.");
108+
Assert.AreEqual(1, ((string[]) query["watch"]).Length, "The 'watch' array should contain exactly one element.");
109109
Assert.AreEqual("foo", ((string[]) query["watch"])[0], "The 'watch' parameter should contain 'foo'.");
110110

111111
}
@@ -118,15 +118,15 @@ public async Task TestBuildSubscribeMessage()
118118
Client.Services,
119119
"DummyClass",
120120
new Dictionary<string, object> { { "foo", "bar" } },
121-
["foo"],
122-
["foo"]);
121+
new[] { "foo" },
122+
new[] { "foo" });
123123
ParseLiveQueryMessageBuilder builder = new ParseLiveQueryMessageBuilder();
124124
IDictionary<string, object> message = await builder.BuildSubscribeMessage<ParseObject>(requestId, liveQuery);
125125

126126
ValidateSubscriptionMessage(message, "subscribe", requestId);
127127

128-
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () => await builder.BuildSubscribeMessage<ParseObject>(0, liveQuery));
129-
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () => await builder.BuildSubscribeMessage<ParseObject>(requestId, null));
128+
await Assert.ThrowsExceptionAsync<ArgumentOutOfRangeException>(async () => await builder.BuildSubscribeMessage<ParseObject>(0, liveQuery));
129+
await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await builder.BuildSubscribeMessage<ParseObject>(requestId, null));
130130
}
131131

132132
[TestMethod]
@@ -137,14 +137,14 @@ public async Task TestBuildUpdateSubscriptionMessage()
137137
Client.Services,
138138
"DummyClass",
139139
new Dictionary<string, object> { { "foo", "bar" } },
140-
["foo"],
141-
["foo"]);
140+
new[] { "foo" },
141+
new[] { "foo" });
142142
ParseLiveQueryMessageBuilder builder = new ParseLiveQueryMessageBuilder();
143143
IDictionary<string, object> message = await builder.BuildUpdateSubscriptionMessage<ParseObject>(requestId, liveQuery);
144144

145145
ValidateSubscriptionMessage(message, "update", requestId);
146146

147-
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () => await builder.BuildUpdateSubscriptionMessage<ParseObject>(0, liveQuery));
148-
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () => await builder.BuildUpdateSubscriptionMessage<ParseObject>(requestId, null));
147+
await Assert.ThrowsExceptionAsync<ArgumentOutOfRangeException>(async () => await builder.BuildUpdateSubscriptionMessage<ParseObject>(0, liveQuery));
148+
await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await builder.BuildUpdateSubscriptionMessage<ParseObject>(requestId, null));
149149
}
150150
}

Parse.Tests/LiveQueryMessageParserTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public void TestGetError()
137137
};
138138

139139
IParseLiveQueryMessageParser.LiveQueryError error = parser.GetError(message);
140-
Assert.HasCount(3, message);
140+
Assert.AreEqual(3, message.Count);
141141
Assert.AreEqual(errorCode, error.Code);
142142
Assert.AreEqual(errorMessage, error.Message);
143143
Assert.AreEqual(reconnect, error.Reconnect);

Parse/Abstractions/Platform/LiveQueries/IParseLiveQueryMessageParser.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ namespace Parse.Abstractions.Platform.LiveQueries;
99
public interface IParseLiveQueryMessageParser
1010
{
1111

12-
struct LiveQueryError
12+
/// <summary>
13+
/// Structure representing a Live Query Server error
14+
/// </summary>
15+
readonly struct LiveQueryError
1316
{
1417
public int Code { get; }
1518
public string Message { get; }
@@ -56,7 +59,7 @@ public LiveQueryError(int code, string message, bool reconnect)
5659
/// </summary>
5760
/// <param name="message">The message containing error details.</param>
5861
/// <returns>
59-
/// A tuple containing the error code, error message, and a boolean indicating whether to reconnect.
62+
/// A LiveQueryError containing the error code, message, and a boolean indicating whether to reconnect.
6063
/// </returns>
6164
LiveQueryError GetError(IDictionary<string, object> message);
6265
}

Parse/Platform/LiveQueries/ParseLiveQueryController.cs

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class ParseLiveQueryController : IParseLiveQueryController, IDisposable,
3434
private bool disposed;
3535

3636
/// <summary>
37-
/// Gets or sets the timeout duration, in milliseconds, used by the ParseLiveQueryController
37+
/// Gets or sets the timeout duration used by the ParseLiveQueryController (as a TimeSpan)
3838
/// for various operations, such as establishing a connection or completing a subscription.
3939
/// </summary>
4040
/// <remarks>
@@ -106,7 +106,7 @@ public enum ParseLiveQueryState
106106
TaskCompletionSource ConnectionSignal { get; set; }
107107
private ConcurrentDictionary<int, TaskCompletionSource> SubscriptionSignals { get; } = new ConcurrentDictionary<int, TaskCompletionSource>();
108108
private ConcurrentDictionary<int, TaskCompletionSource> UnsubscriptionSignals { get; } = new ConcurrentDictionary<int, TaskCompletionSource>();
109-
private ConcurrentDictionary<int, IParseLiveQuerySubscription> Subscriptions { get; set; } = new ConcurrentDictionary<int, IParseLiveQuerySubscription>();
109+
private ConcurrentDictionary<int, IParseLiveQuerySubscription> Subscriptions { get; } = new ConcurrentDictionary<int, IParseLiveQuerySubscription>();
110110

111111
/// <summary>
112112
/// Initializes a new instance of the <see cref="ParseLiveQueryController"/> class.
@@ -279,20 +279,7 @@ void ProcessCreateEventMessage(IDictionary<string, object> message)
279279

280280
void ProcessErrorMessage(IDictionary<string, object> message)
281281
{
282-
if (!(message.TryGetValue("code", out object codeObj) &&
283-
Int32.TryParse(codeObj?.ToString(), out int code)))
284-
return;
285-
286-
if (!(message.TryGetValue("error", out object errorObj) &&
287-
errorObj is string error))
288-
return;
289-
290-
if (!(message.TryGetValue("reconnect", out object reconnectObj) &&
291-
Boolean.TryParse(reconnectObj?.ToString(), out bool reconnect)))
292-
return;
293-
294282
var liveQueryError = MessageParser.GetError(message);
295-
296283
Error?.Invoke(this, new ParseLiveQueryErrorEventArgs(liveQueryError.Code, liveQueryError.Message, liveQueryError.Reconnect));
297284
}
298285

@@ -325,27 +312,17 @@ void ProcessConnectionMessage(IDictionary<string, object> message)
325312
ConnectionSignal?.TrySetResult();
326313
}
327314

328-
private async Task<IDictionary<string, object>> AppendSessionToken(IDictionary<string, object> message)
329-
{
330-
string sessionToken = await ParseClient.Instance.Services.GetCurrentSessionToken();
331-
return sessionToken is null
332-
? message
333-
: message.Concat(new Dictionary<string, object> {
334-
{ "sessionToken", sessionToken }
335-
}).ToDictionary();
336-
}
337-
338315
private async Task SendMessage(IDictionary<string, object> message, CancellationToken cancellationToken) =>
339316
await WebSocketClient.SendAsync(JsonUtilities.Encode(message), cancellationToken);
340317

341318
private async Task OpenAsync(CancellationToken cancellationToken = default)
342319
{
343-
if (ParseClient.Instance.Services == null)
320+
if (ParseClient.Instance.Services is null)
344321
{
345322
throw new InvalidOperationException("ParseClient.Services must be initialized before connecting to the LiveQuery server.");
346323
}
347324

348-
if (ParseClient.Instance.Services.LiveQueryServerConnectionData == null)
325+
if (ParseClient.Instance.Services.LiveQueryServerConnectionData is null)
349326
{
350327
throw new InvalidOperationException("ParseClient.Services.LiveQueryServerConnectionData must be initialized before connecting to the LiveQuery server.");
351328
}
@@ -384,12 +361,12 @@ private async Task EstablishConnectionAsync(CancellationToken cancellationToken)
384361
WebSocketClient.UnknownError += WebSocketClientOnUnknownError;
385362

386363
IDictionary<string, object> message = await MessageBuilder.BuildConnectMessage();
387-
ConnectionSignal = new TaskCompletionSource();
388-
364+
ConnectionSignal = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
365+
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
366+
389367
try
390368
{
391369
await SendMessage(message, cancellationToken);
392-
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
393370
cts.CancelAfter(Timeout);
394371
await ConnectionSignal.Task.WaitAsync(cts.Token);
395372
}
@@ -404,6 +381,7 @@ private async Task EstablishConnectionAsync(CancellationToken cancellationToken)
404381
}
405382
finally
406383
{
384+
cts.Dispose();
407385
ConnectionSignal = null;
408386
}
409387
}
@@ -458,16 +436,14 @@ private async Task SendAndWaitForSignalAsync(IDictionary<string, object> message
458436
int requestId,
459437
CancellationToken cancellationToken)
460438
{
461-
TaskCompletionSource tcs = new TaskCompletionSource();
439+
CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
440+
TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
462441
signalDictionary.TryAdd(requestId, tcs);
463442

464443
try
465444
{
466445
await SendMessage(message, cancellationToken);
467-
468-
CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
469446
cts.CancelAfter(Timeout);
470-
471447
await tcs.Task.WaitAsync(cts.Token);
472448
}
473449
catch (OperationCanceledException)
@@ -477,6 +453,8 @@ private async Task SendAndWaitForSignalAsync(IDictionary<string, object> message
477453
finally
478454
{
479455
signalDictionary.TryRemove(requestId, out _);
456+
tcs = null;
457+
cts.Dispose();
480458
}
481459
}
482460

Parse/Platform/LiveQueries/ParseLiveQueryMessageBuilder.cs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public async Task<IDictionary<string, object>> BuildConnectMessage() => await Ap
3232
}
3333
});
3434

35-
public async Task<IDictionary<string, object>> BuildSubscribeMessage<T>(int requestId, ParseLiveQuery<T> liveQuery) where T : ParseObject
35+
private async Task<IDictionary<string, object>> BuildSubscriptionMessageCore<T>(string operation, int requestId, ParseLiveQuery<T> liveQuery) where T : ParseObject
3636
{
3737
if (requestId <= 0)
3838
throw new ArgumentOutOfRangeException(nameof(requestId), "Request ID must be greater than zero.");
@@ -42,27 +42,17 @@ public async Task<IDictionary<string, object>> BuildSubscribeMessage<T>(int requ
4242

4343
return await AppendSessionToken(new Dictionary<string, object>
4444
{
45-
{ "op", "subscribe" },
45+
{ "op", operation },
4646
{ "requestId", requestId },
4747
{ "query", liveQuery.BuildParameters() }
4848
});
4949
}
5050

51-
public async Task<IDictionary<string, object>> BuildUpdateSubscriptionMessage<T>(int requestId, ParseLiveQuery<T> liveQuery) where T : ParseObject
52-
{
53-
if (requestId <= 0)
54-
throw new ArgumentOutOfRangeException(nameof(requestId), "Request ID must be greater than zero.");
55-
56-
if (liveQuery is null)
57-
throw new ArgumentNullException(nameof(liveQuery));
51+
public async Task<IDictionary<string, object>> BuildSubscribeMessage<T>(int requestId, ParseLiveQuery<T> liveQuery) where T : ParseObject
52+
=> await BuildSubscriptionMessageCore("subscribe", requestId, liveQuery);
5853

59-
return await AppendSessionToken(new Dictionary<string, object>
60-
{
61-
{ "op", "update" },
62-
{ "requestId", requestId },
63-
{ "query", liveQuery.BuildParameters() }
64-
});
65-
}
54+
public async Task<IDictionary<string, object>> BuildUpdateSubscriptionMessage<T>(int requestId, ParseLiveQuery<T> liveQuery) where T : ParseObject
55+
=> await BuildSubscriptionMessageCore("update", requestId, liveQuery);
6656

6757
public IDictionary<string, object> BuildUnsubscribeMessage(int requestId)
6858
{

0 commit comments

Comments
 (0)