@@ -43,7 +43,7 @@ public class ParseLiveQueryController : IParseLiveQueryController, IDisposable,
4343 /// - Unsubscribing from a query.
4444 /// Ensure that the value is configured appropriately to avoid premature timeout errors in network-dependent processes.
4545 /// </remarks>
46- private int TimeOut { get ; }
46+ private TimeSpan Timeout { get ; }
4747
4848 /// <summary>
4949 /// Event triggered when an error occurs during the operation of the ParseLiveQueryController.
@@ -110,19 +110,19 @@ public enum ParseLiveQueryState
110110 /// <summary>
111111 /// Initializes a new instance of the <see cref="ParseLiveQueryController"/> class.
112112 /// </summary>
113- /// <param name="timeOut "></param>
113+ /// <param name="timeout "></param>
114114 /// <param name="webSocketClient">
115115 /// The <see cref="IWebSocketClient"/> implementation to use for the live query connection.
116116 /// </param>
117117 /// <param name="decoder"></param>
118118 /// <remarks>
119119 /// This constructor is used to initialize a new instance of the <see cref="ParseLiveQueryController"/> class
120120 /// </remarks>
121- public ParseLiveQueryController ( int timeOut , IWebSocketClient webSocketClient , IParseDataDecoder decoder )
121+ public ParseLiveQueryController ( TimeSpan timeout , IWebSocketClient webSocketClient , IParseDataDecoder decoder )
122122 {
123123 WebSocketClient = webSocketClient ?? throw new ArgumentNullException ( nameof ( webSocketClient ) ) ;
124124 Decoder = decoder ?? throw new ArgumentNullException ( nameof ( decoder ) ) ;
125- TimeOut = timeOut ;
125+ Timeout = timeout ;
126126 _state = ParseLiveQueryState . Closed ;
127127 }
128128
@@ -360,17 +360,24 @@ private async Task OpenAsync(CancellationToken cancellationToken = default)
360360
361361 private void WebSocketClientOnMessageReceived ( object sender , MessageReceivedEventArgs args )
362362 {
363- object parsed = JsonUtilities . Parse ( args . Message ) ;
364- if ( parsed is IDictionary < string , object > message )
363+ try
365364 {
366- ProcessMessage ( message ) ;
365+ object parsed = JsonUtilities . Parse ( args . Message ) ;
366+ if ( parsed is IDictionary < string , object > message )
367+ {
368+ ProcessMessage ( message ) ;
369+ }
370+ else
371+ {
372+ Debug . WriteLine ( $ "Invalid message format received: { args . Message } ") ;
373+ }
367374 }
368- else
375+ catch ( ArgumentException ex )
369376 {
370- Debug . WriteLine ( $ "Invalid message format received: { args . Message } ") ;
377+ Debug . WriteLine ( $ "Error parsing message: { ex . Message } ") ;
378+ Error ? . Invoke ( this , new ParseLiveQueryErrorEventArgs ( 31 , $ "Failed to parse message: { ex . Message } ", true , ex ) ) ;
371379 }
372380 }
373-
374381 /// <summary>
375382 /// Establishes a connection to the live query server asynchronously.
376383 /// </summary>
@@ -385,6 +392,7 @@ private void WebSocketClientOnMessageReceived(object sender, MessageReceivedEven
385392 /// </exception>
386393 public async Task ConnectAsync ( CancellationToken cancellationToken = default )
387394 {
395+ ThrowIfDisposed ( ) ;
388396 if ( _state == ParseLiveQueryState . Closed )
389397 {
390398 _state = ParseLiveQueryState . Connecting ;
@@ -405,10 +413,9 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default)
405413 await SendMessage ( await AppendSessionToken ( message ) , cancellationToken ) ;
406414
407415 using CancellationTokenSource cts = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken ) ;
408- cts . CancelAfter ( TimeOut ) ;
416+ cts . CancelAfter ( Timeout ) ;
409417
410418 await ConnectionSignal . Task . WaitAsync ( cts . Token ) ;
411- _state = ParseLiveQueryState . Connected ;
412419 }
413420 catch ( OperationCanceledException )
414421 {
@@ -458,7 +465,7 @@ private async Task SendAndWaitForSignalAsync(IDictionary<string, object> message
458465 await SendMessage ( message , cancellationToken ) ;
459466
460467 using CancellationTokenSource cts = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken ) ;
461- cts . CancelAfter ( TimeOut ) ;
468+ cts . CancelAfter ( Timeout ) ;
462469
463470 await tcs . Task . WaitAsync ( cts . Token ) ;
464471 }
@@ -496,6 +503,7 @@ private async Task SendAndWaitForSignalAsync(IDictionary<string, object> message
496503 /// </exception>
497504 public async Task < IParseLiveQuerySubscription > SubscribeAsync < T > ( ParseLiveQuery < T > liveQuery , CancellationToken cancellationToken = default ) where T : ParseObject
498505 {
506+ ThrowIfDisposed ( ) ;
499507 if ( _state == ParseLiveQueryState . Closed )
500508 {
501509 throw new InvalidOperationException ( "Cannot subscribe to a live query when the connection is closed." ) ;
@@ -535,6 +543,7 @@ public async Task<IParseLiveQuerySubscription> SubscribeAsync<T>(ParseLiveQuery<
535543 /// </returns>
536544 public async Task UpdateSubscriptionAsync < T > ( ParseLiveQuery < T > liveQuery , int requestId , CancellationToken cancellationToken = default ) where T : ParseObject
537545 {
546+ ThrowIfDisposed ( ) ;
538547 Dictionary < string , object > message = new Dictionary < string , object >
539548 {
540549 { "op" , "update" } ,
@@ -561,6 +570,7 @@ public async Task UpdateSubscriptionAsync<T>(ParseLiveQuery<T> liveQuery, int re
561570 /// </exception>
562571 public async Task UnsubscribeAsync ( int requestId , CancellationToken cancellationToken = default )
563572 {
573+ ThrowIfDisposed ( ) ;
564574 Dictionary < string , object > message = new Dictionary < string , object >
565575 {
566576 { "op" , "unsubscribe" } ,
@@ -581,6 +591,7 @@ public async Task UnsubscribeAsync(int requestId, CancellationToken cancellation
581591 /// </returns>
582592 public async Task CloseAsync ( CancellationToken cancellationToken = default )
583593 {
594+ ThrowIfDisposed ( ) ;
584595 WebSocketClient . MessageReceived -= WebSocketClientOnMessageReceived ;
585596 WebSocketClient . WebsocketError -= WebSocketClientOnWebsocketError ;
586597 WebSocketClient . UnknownError -= WebSocketClientOnUnknownError ;
@@ -635,18 +646,17 @@ private void Dispose(bool disposing)
635646 if ( disposing )
636647 {
637648 // For sync disposal, the best effort cleanup without waiting
638- _ = Task . Run ( async ( ) =>
649+ try
650+ {
651+ CloseAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
652+ }
653+ catch ( Exception ex )
639654 {
640- try
641- {
642- await CloseAsync ( ) ;
643- }
644- catch ( Exception ex )
645- {
646- Debug . WriteLine ( $ "Error during disposal: { ex } ") ;
647- }
648- } ) ;
655+ Debug . WriteLine ( $ "Error during disposal: { ex } ") ;
656+ }
649657 }
650658 disposed = true ;
651659 }
660+
661+ private void ThrowIfDisposed ( ) => ObjectDisposedException . ThrowIf ( disposed , nameof ( ParseLiveQueryController ) ) ;
652662}
0 commit comments