diff --git a/Source/ARTRealtime.m b/Source/ARTRealtime.m index cf67b2dc1..1cb9c1690 100644 --- a/Source/ARTRealtime.m +++ b/Source/ARTRealtime.m @@ -289,7 +289,7 @@ - (void)transitionSideEffects:(ARTConnectionStateChange *)stateChange { switch (stateChange.current) { case ARTRealtimeConnecting: { [self unlessStateChangesBefore:[ARTDefault realtimeRequestTimeout] do:^{ - [weakSelf onConnectionTimeOut]; + [[weakSelf getTransport] timeOut]; }]; if (!_reachability) { @@ -450,24 +450,6 @@ - (void)transitionSideEffects:(ARTConnectionStateChange *)stateChange { [self.connection emit:stateChange.current with:stateChange]; } -- (void)onConnectionTimeOut { - NSInteger errorCode; - if (self.auth.authorizing && (self.options.authUrl || self.options.authCallback)) { - errorCode = ARTCodeErrorAuthConfiguredProviderFailure; - } - else { - errorCode = ARTCodeErrorConnectionTimedOut; - } - switch (self.connection.state) { - case ARTRealtimeConnected: - [self transition:ARTRealtimeConnected withErrorInfo:[ARTErrorInfo createWithCode:errorCode status:ARTStateConnectionFailed message:@"timed out"]]; - break; - default: - [self transition:ARTRealtimeDisconnected withErrorInfo:[ARTErrorInfo createWithCode:errorCode status:ARTStateConnectionFailed message:@"timed out"]]; - break; - } -} - - (void)unlessStateChangesBefore:(NSTimeInterval)deadline do:(void(^)())callback { // Defer until next event loop execution so that any event emitted in the current // one doesn't cancel the timeout. @@ -615,43 +597,12 @@ - (void)transportReconnectWithHost:(NSString *)host { [self.transport connect]; } -- (void)transportReconnectWithTokenDetails:(ARTTokenDetails *)tokenDetails error:(NSError *)error { - if (error && (self.options.authUrl || self.options.authCallback)) { - [self.connection setErrorReason:[ARTErrorInfo createWithCode:ARTCodeErrorAuthConfiguredProviderFailure message:error.localizedDescription]]; - return; - } +- (void)transportReconnectWithRenewedToken { + _renewingToken = true; [_transport close]; _transport = [[_transportClass alloc] initWithRest:self.rest options:self.options resumeKey:_transport.resumeKey connectionSerial:_transport.connectionSerial]; _transport.delegate = self; - [_transport connectWithToken:tokenDetails.token error:error]; -} - -- (void)transportReconnectWithRenewedToken { - self.auth.delegate = nil; - @try { - _renewingToken = true; - __weak __typeof(self) weakSelf = self; - dispatch_block_t work = artDispatchScheduled([ARTDefault realtimeRequestTimeout], ^{ - [weakSelf onConnectionTimeOut]; - }); - [self.auth authorize:nil options:self.options callback:^(ARTTokenDetails *tokenDetails, NSError *error) { - // Cancel scheduled work - artDispatchCancel(work); - // It's still valid? - switch ([[weakSelf connection] state]) { - case ARTRealtimeClosing: - case ARTRealtimeClosed: - return; - default: - break; - } - [[weakSelf getLogger] debug:__FILE__ line:__LINE__ message:@"R:%p WS:%p authorised: %@ error: %@", weakSelf, [weakSelf getTransport], tokenDetails, error]; - [weakSelf transportReconnectWithTokenDetails:tokenDetails error:error]; - }]; - } - @finally { - self.auth.delegate = self; - } + [_transport connectForcingNewToken:true]; } - (void)onAck:(ARTProtocolMessage *)message { diff --git a/Source/ARTRealtimeTransport.h b/Source/ARTRealtimeTransport.h index 006d6e137..c02b596dc 100644 --- a/Source/ARTRealtimeTransport.h +++ b/Source/ARTRealtimeTransport.h @@ -78,7 +78,8 @@ typedef NS_ENUM(NSUInteger, ARTRealtimeTransportState) { - (void)receive:(ARTProtocolMessage *)msg; - (void)connect; - (void)connectWithToken:(NSString *)token; -- (void)connectWithToken:(NSString *)token error:(art_nullable NSError *)error; +- (void)connectForcingNewToken:(BOOL)forceNewToken; +- (void)timeOut; - (void)sendClose; - (void)sendPing; - (void)close; diff --git a/Source/ARTWebSocketTransport.m b/Source/ARTWebSocketTransport.m index bc7a2628a..15cfb809f 100644 --- a/Source/ARTWebSocketTransport.m +++ b/Source/ARTWebSocketTransport.m @@ -19,6 +19,7 @@ #import "ARTEncoder.h" #import "ARTDefault.h" #import "ARTRealtimeTransport.h" +#import "ARTGCD.h" enum { ARTWsNeverConnected = -1, @@ -108,11 +109,25 @@ - (void)connectForcingNewToken:(BOOL)forceNewToken { } else { // New Token + // Transport instance couldn't exist anymore when `authorize` completes or reaches time out. + __weak __typeof(self) weakSelf = self; + + dispatch_block_t work = artDispatchScheduled([ARTDefault realtimeRequestTimeout], ^{ + [weakSelf timeOut]; + }); + + // Deactivate use of `ARTAuthDelegate`: `authorize` should complete without waiting for a CONNECTED state. id delegate = self.auth.delegate; self.auth.delegate = nil; @try { - __weak __typeof(self) weakSelf = self; [self.auth authorize:nil options:options callback:^(ARTTokenDetails *tokenDetails, NSError *error) { + // Cancel scheduled work + artDispatchCancel(work); + // It's still valid? + if (_state != ARTRealtimeTransportStateOpening && + _state != ARTRealtimeTransportStateOpened) { + return; + } [[weakSelf logger] debug:__FILE__ line:__LINE__ message:@"R:%p WS:%p authorised: %@ error: %@", _delegate, self, tokenDetails, error]; if (error) { [weakSelf handleAuthTokenError:error]; @@ -128,6 +143,22 @@ - (void)connectForcingNewToken:(BOOL)forceNewToken { } } +- (void)timeOut { + ARTErrorInfo *error; + if (self.auth.authorizing && (self.options.authUrl || self.options.authCallback)) { + error = [ARTErrorInfo createWithCode:ARTCodeErrorAuthConfiguredProviderFailure status:ARTStateConnectionFailed message:@"timed out"]; + } + else { + error = [ARTErrorInfo createWithCode:ARTCodeErrorConnectionTimedOut status:ARTStateConnectionFailed message:@"timed out"]; + } + if (_state == ARTRealtimeTransportStateOpened) { + [self.delegate realtimeTransportFailed:self withError:[[ARTRealtimeTransportError alloc] initWithError:error type:ARTRealtimeTransportErrorTypeAuth url:self.websocketURL]]; + } + else { + [self.delegate realtimeTransportFailed:self withError:[[ARTRealtimeTransportError alloc] initWithError:error type:ARTRealtimeTransportErrorTypeAuth url:self.websocketURL]]; + } +} + - (void)handleAuthTokenError:(NSError *)error { [self.logger error:@"R:%p WS:%p ARTWebSocketTransport: token auth failed with %@", self.delegate, self, error.description]; if (error.code == 40102 /*incompatible credentials*/) {