-
-
Notifications
You must be signed in to change notification settings - Fork 261
feat: Add livequery support #411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
theSlyest
wants to merge
42
commits into
parse-community:master
Choose a base branch
from
theSlyest:livequery
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 17 commits
Commits
Show all changes
42 commits
Select commit
Hold shift + click to select a range
e0d63ab
Add ParseLiveQuery and dependencies
theSlyest d7c8c71
Added ParseLiveQuerySubscription and refactored accordingly
theSlyest 0932e35
Added EventArgs
theSlyest 8740db2
ParseLiveQueryController initialization
theSlyest 542e3cb
Subscription bug fixes
theSlyest 40044a2
Updated event argument types
theSlyest 0f737a0
Added DualParseLiveQueryEventArgs
theSlyest 98e295a
Live query server error management
theSlyest c0a6bec
Renamed DualParseLiveQueryEventArgs to ParseLiveQueryDualEventArgs
theSlyest a267f63
Code quality
theSlyest 4b83d23
Improve code quality
theSlyest 65c73e4
Add null safety for the "where" clause extraction
theSlyest 340f6fb
Improve code quality
theSlyest 7e66bb6
Improvements
theSlyest 84f7060
Null checks
theSlyest 834ff89
Move TimeOut and BufferSize to new LiveQueryServerConnectionData and …
theSlyest bd36b7d
Minor improvements
theSlyest e9c6bcc
Improve message parsing
theSlyest 8938a4d
Improve the retrieval of data objects from a message
theSlyest b65e230
Null safety and small changes
theSlyest cc5168c
Improve controller disposal
theSlyest e70789e
Fix race conditions
theSlyest 2cfef04
Websocket exception handling
theSlyest 97313bf
Small clean up
theSlyest f3374f6
Fix test error
theSlyest 62e81fb
Fix RelationTests
theSlyest a76014f
Fix UserTests
theSlyest fbe273a
Fix RelationTests for net9.0
theSlyest c59316b
Add live query and live query event arg tests
theSlyest d9ec311
Live query event args test corrections
theSlyest e3b5df9
Code quality improvement
theSlyest 70e587a
Fix tests
theSlyest 6a50ce4
Tests code quality
theSlyest 871f015
Replaced "int TimeOut" by "TimeSpan Timeout" and other improvements
theSlyest 5444d5d
Improve code quality
theSlyest 96b20f6
Code rabbits improvements
theSlyest 854beaa
Refactor and add tests
theSlyest a13c7ab
Moved responsibilities from ParseLiveQueryController to 2 new classes
theSlyest b86a45a
Fine tuning some tests
theSlyest ea60936
Added TextWebSocketClientTests
theSlyest 8341e12
CodeRabbit required changes
theSlyest a608262
CodeRabbit requested changes
theSlyest File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
Parse/Abstractions/Infrastructure/Execution/IWebSocketClient.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Parse.Abstractions.Infrastructure.Execution; | ||
|
||
/// <summary> | ||
/// Represents an interface for a WebSocket client to handle WebSocket connections and communications. | ||
/// </summary> | ||
public interface IWebSocketClient | ||
{ | ||
/// <summary> | ||
/// An event that is triggered when a message is received via the WebSocket connection. | ||
/// </summary> | ||
/// <remarks> | ||
/// The event handler receives the message as a string parameter. This can be used to process incoming | ||
/// WebSocket messages, such as notifications, commands, or data updates. | ||
/// </remarks> | ||
public event EventHandler<string> MessageReceived; | ||
|
||
/// <summary> | ||
/// Establishes a WebSocket connection to the specified server URI. | ||
/// </summary> | ||
/// <param name="serverUri">The URI of the WebSocket server to connect to.</param> | ||
/// <param name="cancellationToken"> | ||
/// A token to observe cancellation requests. The operation will stop if the token is canceled. | ||
/// </param> | ||
/// <returns>A task that represents the asynchronous operation of opening the WebSocket connection.</returns> | ||
public Task OpenAsync(string serverUri, CancellationToken cancellationToken = default); | ||
|
||
/// <summary> | ||
/// Closes the active WebSocket connection asynchronously. | ||
/// </summary> | ||
/// <param name="cancellationToken"> | ||
/// A token to observe cancellation requests. The operation will stop if the token is canceled. | ||
/// </param> | ||
/// <returns>A task that represents the asynchronous operation of closing the WebSocket connection.</returns> | ||
public Task CloseAsync(CancellationToken cancellationToken = default); | ||
|
||
/// <summary> | ||
/// Sends a message over the established WebSocket connection asynchronously. | ||
/// </summary> | ||
/// <param name="message">The message to send through the WebSocket connection.</param> | ||
/// <param name="cancellationToken"> | ||
/// A token to observe cancellation requests. The operation will stop if the token is canceled. | ||
/// </param> | ||
/// <returns>A task that represents the asynchronous operation of sending the message.</returns> | ||
/// <exception cref="InvalidOperationException">Thrown when trying to send a message on a WebSocket connection that is not in the Open state.</exception> | ||
public Task SendAsync(string message, CancellationToken cancellationToken = default); | ||
} |
25 changes: 25 additions & 0 deletions
25
Parse/Abstractions/Infrastructure/ILiveQueryServerConnectionData.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
namespace Parse.Abstractions.Infrastructure; | ||
|
||
public interface ILiveQueryServerConnectionData : IServerConnectionData | ||
{ | ||
/// <summary> | ||
/// Represents the default timeout duration, in milliseconds. | ||
/// </summary> | ||
public const int DefaultTimeOut = 5000; // 5 seconds | ||
|
||
/// <summary> | ||
/// The timeout duration, in milliseconds, used for various operations, such as | ||
/// establishing a connection or completing a subscription. | ||
/// </summary> | ||
int TimeOut { get; set; } | ||
|
||
/// <summary> | ||
/// The default buffer size, in bytes. | ||
/// </summary> | ||
public const int DefaultBufferSize = 4096; // 4KB | ||
|
||
/// <summary> | ||
/// The buffer size, in bytes, used for the WebSocket operations to handle incoming messages. | ||
/// </summary> | ||
int MessageBufferSize { get; set; } | ||
theSlyest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
Parse/Abstractions/Platform/LiveQueries/IParseLiveQueryController.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Parse.Platform.LiveQueries; | ||
|
||
namespace Parse.Abstractions.Platform.LiveQueries; | ||
|
||
/// <summary> | ||
/// Defines an interface for managing LiveQuery connections, subscriptions, and updates | ||
/// in a Parse Server environment. | ||
/// </summary> | ||
public interface IParseLiveQueryController | ||
{ | ||
/// <summary> | ||
/// Event triggered when an error occurs during the operation of the ParseLiveQueryController. | ||
/// </summary> | ||
/// <remarks> | ||
/// This event provides details about a live query operation failure, such as specific error messages, | ||
/// error codes, and whether automatic reconnection is recommended. | ||
/// It is raised in scenarios like: | ||
/// - Receiving an error response from the LiveQuery server. | ||
/// - Issues with subscriptions, unsubscriptions, or query updates. | ||
/// Subscribers to this event can use the provided <see cref="ParseLiveQueryErrorEventArgs"/> to | ||
/// understand the error and implement appropriate handling mechanisms. | ||
/// </remarks> | ||
public event EventHandler<ParseLiveQueryErrorEventArgs> Error; | ||
|
||
/// <summary> | ||
/// Establishes a connection to the live query server asynchronously. | ||
/// </summary> | ||
/// <param name="cancellationToken"> | ||
/// A cancellation token that can be used to cancel the connection process. If the token is triggered, | ||
/// the connection process will be terminated. | ||
/// </param> | ||
/// <returns> | ||
/// A task that represents the asynchronous connection operation. | ||
/// </returns> | ||
/// <exception cref="TimeoutException"> | ||
/// Thrown when the connection request times out before receiving confirmation from the server. | ||
/// </exception> | ||
Task ConnectAsync(CancellationToken cancellationToken = default); | ||
|
||
/// <summary> | ||
/// Subscribes to a live query, enabling real-time updates for the specified query object. | ||
/// </summary> | ||
/// <typeparam name="T"> | ||
/// The type of the ParseObject associated with the live query. | ||
/// </typeparam> | ||
/// <param name="liveQuery"> | ||
/// The live query instance to subscribe to. It contains details about the query and its parameters. | ||
/// </param> | ||
/// <param name="cancellationToken"> | ||
/// A token to monitor for cancellation requests. It allows the operation to be canceled if requested. | ||
/// </param> | ||
/// <returns> | ||
/// An object representing the active subscription for the specified query, enabling interaction with the subscribed events and updates. | ||
/// </returns> | ||
/// <exception cref="InvalidOperationException"> | ||
/// Thrown when attempting to subscribe while the live query connection is in a closed state. | ||
/// </exception> | ||
/// <exception cref="TimeoutException"> | ||
/// Thrown when the subscription request times out before receiving confirmation from the server. | ||
/// </exception> | ||
Task<IParseLiveQuerySubscription> SubscribeAsync<T>(ParseLiveQuery<T> liveQuery, CancellationToken cancellationToken = default) where T : ParseObject; | ||
|
||
/// <summary> | ||
/// Updates an active subscription. This method modifies the parameters of an existing subscription for a specific query. | ||
/// </summary> | ||
/// <param name="liveQuery"> | ||
/// The live query object that holds the query parameters to be updated. | ||
/// </param> | ||
/// <param name="requestId"> | ||
/// The unique identifier of the subscription to update. | ||
/// </param> | ||
/// <param name="cancellationToken"> | ||
/// A token to monitor for cancellation requests, allowing the operation to be cancelled before completion. | ||
/// </param> | ||
/// <typeparam name="T"> | ||
/// The type of the ParseObject that the query targets. | ||
/// </typeparam> | ||
/// <returns> | ||
/// A task that represents the asynchronous operation of updating the subscription. | ||
/// </returns> | ||
Task UpdateSubscriptionAsync<T>(ParseLiveQuery<T> liveQuery, int requestId, CancellationToken cancellationToken = default) where T : ParseObject; | ||
|
||
/// <summary> | ||
/// Unsubscribes from a live query subscription associated with the given request identifier. | ||
/// </summary> | ||
/// <param name="requestId"> | ||
/// The unique identifier of the subscription to unsubscribe from. | ||
/// </param> | ||
/// <param name="cancellationToken"> | ||
/// A cancellation token that can be used to cancel the unsubscription operation before completion. | ||
/// </param> | ||
/// <returns> | ||
/// A task that represents the asynchronous unsubscription operation. | ||
/// </returns> | ||
/// <exception cref="TimeoutException"> | ||
/// Thrown if the unsubscription process does not complete within the specified timeout period. | ||
/// </exception> | ||
Task UnsubscribeAsync(int requestId, CancellationToken cancellationToken = default); | ||
|
||
/// <summary> | ||
/// Closes the live query connection asynchronously. | ||
/// </summary> | ||
/// <param name="cancellationToken"> | ||
/// A token to monitor for cancellation requests while closing the live query connection. | ||
/// If the operation is canceled, the task will terminate early. | ||
/// </param> | ||
/// <returns> | ||
/// A task that represents the asynchronous operation of closing the live query connection. | ||
/// The task completes when the connection is fully closed and resources are cleaned up. | ||
/// </returns> | ||
Task CloseAsync(CancellationToken cancellationToken = default); | ||
} |
72 changes: 72 additions & 0 deletions
72
Parse/Abstractions/Platform/LiveQueries/IParseLiveQuerySubscription.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Parse.Abstractions.Platform.Objects; | ||
using Parse.Platform.LiveQueries; | ||
|
||
namespace Parse.Abstractions.Platform.LiveQueries; | ||
|
||
public interface IParseLiveQuerySubscription | ||
{ | ||
/// <summary> | ||
/// Represents the Create event for a live query subscription. | ||
/// This event is triggered when a new object matching the subscription's query is created. | ||
/// </summary> | ||
event EventHandler<ParseLiveQueryEventArgs> Create; | ||
|
||
/// <summary> | ||
/// Represents the Enter event for a live query subscription. | ||
/// This event is triggered when an object that did not previously match the query (and was thus not part of the subscription) | ||
/// starts matching the query, typically due to an update. | ||
/// </summary> | ||
event EventHandler<ParseLiveQueryDualEventArgs> Enter; | ||
|
||
/// <summary> | ||
/// Represents the Update event for a live query subscription. | ||
/// This event is triggered when an existing object matching the subscription's query is updated. | ||
/// </summary> | ||
event EventHandler<ParseLiveQueryDualEventArgs> Update; | ||
|
||
/// <summary> | ||
/// Represents the Leave event for a live query subscription. | ||
/// This event is triggered when an object that previously matched the subscription's query | ||
/// no longer matches the criteria and is removed. | ||
/// </summary> | ||
event EventHandler<ParseLiveQueryDualEventArgs> Leave; | ||
|
||
/// <summary> | ||
/// Represents the Delete event for a live query subscription. | ||
/// This event is triggered when an object matching the subscription's query is deleted. | ||
/// </summary> | ||
event EventHandler<ParseLiveQueryEventArgs> Delete; | ||
|
||
/// <summary> | ||
/// Updates the current live query subscription with new query parameters, | ||
/// effectively modifying the subscription to reflect the provided live query. | ||
/// This allows adjustments to the filter or watched keys without unsubscribing | ||
/// and re-subscribing. | ||
/// </summary> | ||
/// <typeparam name="T">The type of the ParseObject associated with the subscription.</typeparam> | ||
/// <param name="liveQuery">The updated live query containing new parameters that | ||
/// will replace the existing ones for this subscription.</param> | ||
/// <param name="cancellationToken">A token to monitor for cancellation requests. If triggered, | ||
/// the update process will be halted.</param> | ||
/// <returns>A task that represents the asynchronous operation of updating | ||
/// the subscription with the new query parameters.</returns> | ||
Task UpdateAsync<T>(ParseLiveQuery<T> liveQuery, CancellationToken cancellationToken = default) where T : ParseObject; | ||
|
||
/// <summary> | ||
/// Cancels the current live query subscription by unsubscribing from the Parse Live Query server. | ||
/// This ensures that the client will no longer receive real-time updates or notifications | ||
/// associated with this subscription. | ||
/// </summary> | ||
/// <param name="cancellationToken">A token to monitor for cancellation requests. If triggered, the cancellation process will halt.</param> | ||
/// <returns>A task that represents the asynchronous operation of canceling the subscription.</returns> | ||
Task CancelAsync(CancellationToken cancellationToken = default); | ||
|
||
internal void OnCreate(IObjectState objectState); | ||
internal void OnEnter(IObjectState objectState, IObjectState originalState); | ||
internal void OnUpdate(IObjectState objectState, IObjectState originalState); | ||
internal void OnLeave(IObjectState objectState, IObjectState originalState); | ||
internal void OnDelete(IObjectState objectState); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.