Skip to content

Commit 0932e35

Browse files
committed
Added EventArgs
1 parent d7c8c71 commit 0932e35

File tree

8 files changed

+165
-71
lines changed

8 files changed

+165
-71
lines changed

Parse.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1717
EndProject
1818
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parse.Tests", "Parse.Tests\Parse.Tests.csproj", "{FEB46D0F-384C-4F27-9E0E-F4A636768C90}"
1919
EndProject
20+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseApp", "ParseApp\ParseApp.csproj", "{71EF1783-2BAA-4119-A666-B7DCA3FD3085}"
21+
EndProject
2022
Global
2123
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2224
Debug|Any CPU = Debug|Any CPU
@@ -31,6 +33,10 @@ Global
3133
{FEB46D0F-384C-4F27-9E0E-F4A636768C90}.Debug|Any CPU.Build.0 = Debug|Any CPU
3234
{FEB46D0F-384C-4F27-9E0E-F4A636768C90}.Release|Any CPU.ActiveCfg = Release|Any CPU
3335
{FEB46D0F-384C-4F27-9E0E-F4A636768C90}.Release|Any CPU.Build.0 = Release|Any CPU
36+
{71EF1783-2BAA-4119-A666-B7DCA3FD3085}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37+
{71EF1783-2BAA-4119-A666-B7DCA3FD3085}.Debug|Any CPU.Build.0 = Debug|Any CPU
38+
{71EF1783-2BAA-4119-A666-B7DCA3FD3085}.Release|Any CPU.ActiveCfg = Release|Any CPU
39+
{71EF1783-2BAA-4119-A666-B7DCA3FD3085}.Release|Any CPU.Build.0 = Release|Any CPU
3440
EndGlobalSection
3541
GlobalSection(SolutionProperties) = preSolution
3642
HideSolutionNode = FALSE

Parse/Abstractions/Platform/LiveQueries/IParseLiveQuerySubscription.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Threading;
44
using System.Threading.Tasks;
5+
using Parse.Platform.LiveQueries;
56

67
namespace Parse.Abstractions.Platform.LiveQueries;
78

@@ -16,33 +17,33 @@ public interface IParseLiveQuerySubscription
1617
/// Represents the Create event for a live query subscription.
1718
/// This event is triggered when a new object matching the subscription's query is created.
1819
/// </summary>
19-
public event EventHandler<IDictionary<string, object>> Create;
20+
public event EventHandler<ParseLiveQueryEventArgs> Create;
2021

2122
/// <summary>
2223
/// Represents the Enter event for a live query subscription.
2324
/// This event is triggered when an object that did not previously match the query (and was thus not part of the subscription)
2425
/// starts matching the query, typically due to an update.
2526
/// </summary>
26-
public event EventHandler<IDictionary<string, object>> Enter;
27+
public event EventHandler<ParseLiveQueryEventArgs> Enter;
2728

2829
/// <summary>
2930
/// Represents the Update event for a live query subscription.
3031
/// This event is triggered when an existing object matching the subscription's query is updated.
3132
/// </summary>
32-
public event EventHandler<IDictionary<string, object>> Update;
33+
public event EventHandler<ParseLiveQueryEventArgs> Update;
3334

3435
/// <summary>
3536
/// Represents the Leave event for a live query subscription.
3637
/// This event is triggered when an object that previously matched the subscription's query
3738
/// no longer matches the criteria and is removed.
3839
/// </summary>
39-
public event EventHandler<IDictionary<string, object>> Leave;
40+
public event EventHandler<ParseLiveQueryEventArgs> Leave;
4041

4142
/// <summary>
4243
/// Represents the Delete event for a live query subscription.
4344
/// This event is triggered when an object matching the subscription's query is deleted.
4445
/// </summary>
45-
public event EventHandler<IDictionary<string, object>> Delete;
46+
public event EventHandler<ParseLiveQueryEventArgs> Delete;
4647

4748
/// <summary>
4849
/// Updates the current live query subscription with new query parameters,

Parse/Platform/LiveQueries/ParseLiveQuery.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Parse.Abstractions.Infrastructure;
88
using Parse.Abstractions.Platform.LiveQueries;
99
using Parse.Infrastructure.Data;
10+
using Parse.Infrastructure.Utilities;
1011

1112
namespace Parse;
1213

@@ -20,7 +21,7 @@ public class ParseLiveQuery<T> where T : ParseObject
2021
/// <summary>
2122
/// Serialized <see langword="where"/> clauses.
2223
/// </summary>
23-
Dictionary<string, object> Filters { get; }
24+
string Filters { get; }
2425

2526
/// <summary>
2627
/// Serialized key selections.
@@ -38,17 +39,12 @@ public class ParseLiveQuery<T> where T : ParseObject
3839

3940
private int RequestId = 0;
4041

41-
public ParseLiveQuery(IServiceHub serviceHub, string className, IDictionary<string, object> filters, IEnumerable<string> selectedKeys = null, IEnumerable<string> watchedKeys = null)
42+
public ParseLiveQuery(IServiceHub serviceHub, string className, object filters, IEnumerable<string> selectedKeys = null, IEnumerable<string> watchedKeys = null)
4243
{
43-
if (filters.Count == 0)
44-
{
45-
// Throw error
46-
}
47-
4844
Services = serviceHub;
4945
ClassName = className;
46+
Filters = JsonUtilities.Encode(filters);
5047

51-
Filters = new Dictionary<string, object>(filters);
5248
if (selectedKeys is not null)
5349
{
5450
KeySelections = new ReadOnlyCollection<string>(selectedKeys.ToList());
@@ -95,11 +91,11 @@ internal ParseLiveQuery(ParseLiveQuery<T> source, IEnumerable<string> watchedKey
9591
/// <returns>A new query with the additional constraint.</returns>
9692
public ParseLiveQuery<T> Watch(string watch) => new(this, new List<string> { watch });
9793

98-
internal IDictionary<string, object> BuildParameters(bool includeClassName = false)
94+
internal IDictionary<string, string> BuildParameters(bool includeClassName = false)
9995
{
100-
Dictionary<string, object> result = new Dictionary<string, object>();
96+
Dictionary<string, string> result = new Dictionary<string, string>();
10197
if (Filters != null)
102-
result["where"] = PointerOrLocalIdEncoder.Instance.Encode(Filters, Services);
98+
result["where"] = Filters;
10399
if (KeySelections != null)
104100
result["keys"] = String.Join(",", KeySelections.ToArray());
105101
if (KeyWatchers != null)

Parse/Platform/LiveQueries/ParseLiveQueryController.cs

Lines changed: 106 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Collections;
32
using System.Collections.Generic;
43
using System.Diagnostics;
54
using System.Linq;
@@ -21,13 +20,15 @@ public class ParseLiveQueryController : IParseLiveQueryController
2120

2221
private int LastRequestId { get; set; } = 0;
2322

23+
private string ClientId { get; set; }
24+
2425
/// <summary>
2526
/// Gets or sets the timeout duration, in milliseconds, used by the ParseLiveQueryController
2627
/// for various operations, such as establishing a connection or completing a subscription.
2728
/// </summary>
2829
/// <remarks>
2930
/// This property determines the maximum amount of time the controller will wait for an operation
30-
/// to complete before throwing a <see cref="TimeoutException"/>. It is used in operations such as:
31+
/// to complete before throwing a <see cref="TimeoutException"/>. It is used in operations such as
3132
/// - Connecting to the LiveQuery server.
3233
/// - Subscribing to a query.
3334
/// - Unsubscribing from a query.
@@ -36,17 +37,23 @@ public class ParseLiveQueryController : IParseLiveQueryController
3637
public int TimeOut { get; set; } = 5000;
3738

3839
/// <summary>
39-
/// Event triggered when an error occurs during Parse Live Query operations.
40+
/// Event triggered when an error occurs during the operation of the ParseLiveQueryController.
4041
/// </summary>
4142
/// <remarks>
42-
/// This event provides detailed information about the encountered error through the event arguments,
43-
/// which consist of a dictionary containing key-value pairs describing the error context and specifics.
44-
/// It can be used to log, handle, or analyze the errors that arise during subscription, connection,
45-
/// or message processing operations. Common scenarios triggering this event include protocol issues,
46-
/// connectivity problems, or invalid message formats.
43+
/// This event provides details about a live query operation failure, such as specific error messages,
44+
/// error codes, and whether automatic reconnection is recommended.
45+
/// It is raised in scenarios like:
46+
/// - Receiving an error response from the LiveQuery server.
47+
/// - Issues with subscriptions, unsubscriptions, or query updates.
48+
/// Subscribers to this event can use the provided <see cref="ParseLiveQueryErrorEventArgs"/> to
49+
/// understand the error and implement appropriate handling mechanisms.
4750
/// </remarks>
48-
public event EventHandler<IDictionary<string, object>> Error;
51+
public event EventHandler<ParseLiveQueryErrorEventArgs> Error;
4952

53+
/// <summary>
54+
/// Represents the state of a connection to the Parse LiveQuery server, indicating whether the connection is closed,
55+
/// in the process of connecting, or fully established.
56+
/// </summary>
5057
public enum ParseLiveQueryState
5158
{
5259
/// <summary>
@@ -71,7 +78,8 @@ public enum ParseLiveQueryState
7178
/// such as when a connection is established or closed, or when an error occurs.
7279
/// </remarks>
7380
public ParseLiveQueryState State { get; private set; }
74-
ArrayList SubscriptionIds { get; }
81+
82+
HashSet<int> SubscriptionIds { get; } = new HashSet<int> { };
7583

7684
CancellationTokenSource ConnectionSignal { get; set; }
7785
private IDictionary<int, CancellationTokenSource> SubscriptionSignals { get; } = new Dictionary<int, CancellationTokenSource> { };
@@ -83,89 +91,143 @@ public enum ParseLiveQueryState
8391
public ParseLiveQueryController(IWebSocketClient webSocketClient)
8492
{
8593
WebSocketClient = webSocketClient;
86-
SubscriptionIds = new ArrayList();
8794
State = ParseLiveQueryState.Closed;
8895
}
8996

9097
private void ProcessMessage(IDictionary<string, object> message)
9198
{
9299
int requestId;
100+
string clientId;
101+
ParseLiveQuerySubscription subscription;
93102
switch (message["op"])
94103
{
95104
case "connected":
96105
State = ParseLiveQueryState.Connected;
106+
ClientId = message["clientId"] as string;
97107
ConnectionSignal?.Cancel();
98-
// Connected?.Invoke(this, EventArgs.Empty);
99108
break;
100109

101-
case "subscribed":
102-
requestId = Convert.ToInt32(message["requestId"]);
103-
SubscriptionIds.Add(requestId);
104-
if (SubscriptionSignals.TryGetValue(requestId, out CancellationTokenSource subscriptionSignal))
110+
case "subscribed": // Response from subscription and subscription update
111+
clientId = message["clientId"] as string;
112+
if (clientId == ClientId)
105113
{
106-
subscriptionSignal?.Cancel();
114+
requestId = Convert.ToInt32(message["requestId"]);
115+
SubscriptionIds.Add(requestId);
116+
if (SubscriptionSignals.TryGetValue(requestId, out CancellationTokenSource subscriptionSignal))
117+
{
118+
subscriptionSignal?.Cancel();
119+
}
107120
}
108-
// Subscribed?.Invoke(this, requestId);
109121
break;
110122

111-
// TODO subscription update case
112-
113123
case "unsubscribed":
114-
requestId = Convert.ToInt32(message["requestId"]);
115-
SubscriptionIds.Remove(requestId);
116-
if (UnsubscriptionSignals.TryGetValue(requestId, out CancellationTokenSource unsubscriptionSignal))
124+
clientId = message["clientId"] as string;
125+
if (clientId == ClientId)
117126
{
118-
unsubscriptionSignal?.Cancel();
127+
requestId = Convert.ToInt32(message["requestId"]);
128+
SubscriptionIds.Remove(requestId);
129+
if (UnsubscriptionSignals.TryGetValue(requestId, out CancellationTokenSource unsubscriptionSignal))
130+
{
131+
unsubscriptionSignal?.Cancel();
132+
}
119133
}
120-
// Unsubscribed?.Invoke(this, requestId);
121134
break;
122135

123136
case "error":
124137
if ((bool)message["reconnect"])
125138
{
126-
OpenAsync();
139+
ConnectAsync();
127140
}
128-
string errorMessage = message["error"] as string;
129-
Error?.Invoke(this, message);
141+
142+
ParseLiveQueryErrorEventArgs errorArgs = new ParseLiveQueryErrorEventArgs
143+
{
144+
Error = message["error"] as string,
145+
Code = Convert.ToInt32(message["code"]),
146+
Reconnected = (bool)message["reconnect"]
147+
};
148+
Error?.Invoke(this, errorArgs);
130149
break;
131150

132151
case "create":
133-
requestId = Convert.ToInt32(message["requestId"]);
134-
if (Subscriptions.TryGetValue(requestId, out ParseLiveQuerySubscription subscription))
152+
clientId = message["clientId"] as string;
153+
if (clientId == ClientId)
135154
{
136-
subscription.OnCreate(message);
155+
requestId = Convert.ToInt32(message["requestId"]);
156+
if (Subscriptions.TryGetValue(requestId, out subscription))
157+
{
158+
ParseLiveQueryEventArgs args = new ParseLiveQueryEventArgs()
159+
{
160+
Object = message["object"]
161+
};
162+
subscription.OnCreate(args);
163+
}
137164
}
138165
break;
139166

140167
case "enter":
141-
requestId = Convert.ToInt32(message["requestId"]);
142-
if (Subscriptions.TryGetValue(requestId, out subscription))
168+
clientId = message["clientId"] as string;
169+
if (clientId == ClientId)
143170
{
144-
subscription.OnEnter(message);
171+
requestId = Convert.ToInt32(message["requestId"]);
172+
if (Subscriptions.TryGetValue(requestId, out subscription))
173+
{
174+
ParseLiveQueryEventArgs args = new ParseLiveQueryEventArgs()
175+
{
176+
Object = message["object"],
177+
Original = message["original"]
178+
};
179+
subscription.OnEnter(args);
180+
}
145181
}
146182
break;
147183

148184
case "update":
149-
requestId = Convert.ToInt32(message["requestId"]);
150-
if (Subscriptions.TryGetValue(requestId, out subscription))
185+
clientId = message["clientId"] as string;
186+
if (clientId == ClientId)
151187
{
152-
subscription.OnUpdate(message);
188+
requestId = Convert.ToInt32(message["requestId"]);
189+
if (Subscriptions.TryGetValue(requestId, out subscription))
190+
{
191+
ParseLiveQueryEventArgs args = new ParseLiveQueryEventArgs()
192+
{
193+
Object = message["object"],
194+
Original = message["original"]
195+
};
196+
subscription.OnUpdate(args);
197+
}
153198
}
154199
break;
155200

156201
case "leave":
157-
requestId = Convert.ToInt32(message["requestId"]);
158-
if (Subscriptions.TryGetValue(requestId, out subscription))
202+
clientId = message["clientId"] as string;
203+
if (clientId == ClientId)
159204
{
160-
subscription.OnLeave(message);
205+
requestId = Convert.ToInt32(message["requestId"]);
206+
if (Subscriptions.TryGetValue(requestId, out subscription))
207+
{
208+
ParseLiveQueryEventArgs args = new ParseLiveQueryEventArgs()
209+
{
210+
Object = message["object"],
211+
Original = message["original"]
212+
};
213+
subscription.OnLeave(args);
214+
}
161215
}
162216
break;
163217

164218
case "delete":
165-
requestId = Convert.ToInt32(message["requestId"]);
166-
if (Subscriptions.TryGetValue(requestId, out subscription))
219+
clientId = message["clientId"] as string;
220+
if (clientId == ClientId)
167221
{
168-
subscription.OnDelete(message);
222+
requestId = Convert.ToInt32(message["requestId"]);
223+
if (Subscriptions.TryGetValue(requestId, out subscription))
224+
{
225+
ParseLiveQueryEventArgs args = new ParseLiveQueryEventArgs()
226+
{
227+
Object = message["object"],
228+
};
229+
subscription.OnDelete(args);
230+
}
169231
}
170232
break;
171233

@@ -369,7 +431,7 @@ public async Task UnsubscribeAsync(int requestId, CancellationToken cancellation
369431
}
370432

371433
/// <summary>
372-
/// Closes the live query connection, resets the state to closed, and clears all active subscriptions and signals.
434+
/// Closes the live query connection, resets the state to close, and clears all active subscriptions and signals.
373435
/// </summary>
374436
/// <param name="cancellationToken">
375437
/// A token to monitor for cancellation requests while closing the connection.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace Parse.Platform.LiveQueries;
4+
5+
public class ParseLiveQueryErrorEventArgs : EventArgs
6+
{
7+
public string Error { get; set; }
8+
public int Code { get; set; }
9+
public bool Reconnected { get; set; }
10+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
3+
namespace Parse.Platform.LiveQueries;
4+
5+
/// <summary>
6+
/// Provides event arguments for events triggered by Parse's Live Query service.
7+
/// This class encapsulates details about a particular event, such as the operation type,
8+
/// client ID, request ID, and the associated Parse object data.
9+
/// </summary>
10+
public class ParseLiveQueryEventArgs : EventArgs
11+
{
12+
public object Object { get; set; }
13+
public object Original { get; set; }
14+
}

0 commit comments

Comments
 (0)