-
-
Notifications
You must be signed in to change notification settings - Fork 259
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
55
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 12 commits
Commits
Show all changes
55 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 75b3816
Added tests
theSlyest b676df1
CodeRabbitAI suggested changes
theSlyest da1aea7
Merge branch 'master' into livequery
theSlyest 5ae15c6
CodeRabbitAI suggestions
theSlyest e983359
CodeRabbitAI suggested changes
theSlyest d9669e9
Suggested changes
theSlyest ed1a751
CodeRabbitAI suggestions
theSlyest 86cdeac
Add ParseClient constructor test with LiveQuery
theSlyest 172a4fc
Add missing tests
theSlyest 1fc8184
Add ServiceHub unit tests
theSlyest 38dd690
Suggested changes
theSlyest 43c5da1
Requested changes
theSlyest e90c570
Fixed failing test
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
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
49 changes: 49 additions & 0 deletions
49
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,49 @@ | ||
| 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> | ||
| public Task SendAsync(string message, CancellationToken cancellationToken); | ||
| } |
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
127 changes: 127 additions & 0 deletions
127
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,127 @@ | ||
| 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> | ||
| /// Gets or sets the timeout duration, in milliseconds, for operations performed by the LiveQuery controller. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// This property determines the maximum time the system will wait for an operation to complete | ||
| /// before timing out. It is particularly relevant to tasks such as establishing a connection | ||
| /// to the LiveQuery server or awaiting responses for subscription or query update requests. | ||
| /// Developers can use this property to configure timeouts based on the expected network | ||
| /// and performance conditions of the application environment. | ||
| /// </remarks> | ||
| public int TimeOut { get; set; } | ||
|
|
||
| /// <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); | ||
| } |
77 changes: 77 additions & 0 deletions
77
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,77 @@ | ||
| using System; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| using Parse.Abstractions.Platform.Objects; | ||
| using Parse.Platform.LiveQueries; | ||
|
|
||
| namespace Parse.Abstractions.Platform.LiveQueries; | ||
|
|
||
| /// <summary> | ||
| /// Represents a live query subscription that is used with Parse's Live Query service. | ||
| /// It allows real-time monitoring and event handling for object changes that match | ||
| /// a specified query. | ||
| /// </summary> | ||
| 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internalinterface members without a body are not valid in C# (interface members are public by default unless they have a default implementation). Theseinternal void On*declarations will fail to compile. Consider moving these callbacks to a separateinternalinterface (implemented by the concrete subscription) that the controller holds internally, or make them explicit methods on the concrete type instead of part of the public interface.