Skip to content

Commit

Permalink
Update RTL2 for 0.9 (#543)
Browse files Browse the repository at this point in the history
* Add Realtime Channel Suspended state

* Add ProtocolMessageActionToStr method

* Add ChannelStateChange type

* Update RTL2

* RTL2f: pending

 - functionality hasn't been deployed

* Use ChannelStateChange on channel event emitter

* Test suite: simulate client suspension with before suspension callback

* Update tests using channel events

* Fix RTL14

* Fix: Channel on suspended should transition to SUSPENDED state

* Remove RTN18

* Fix: set Suspended on all channels when Connection moves to Suspended

* RTL2g

* Fix RTL12

* Fix RTL3d

* Fix: channel should reattach when connection is Connected

* Fix: should resume connection when the connection is Suspended

* Fix RTN11

* Fix RTL3e

* Fix RTC8a1

* Remove testSuspendingDetachesChannel

* Fix RTL3d

* Fix: channel is SUSPENDED then operation will result in an error
  • Loading branch information
ricardopereira authored Dec 20, 2016
1 parent 0e10475 commit 7f1309b
Show file tree
Hide file tree
Showing 20 changed files with 619 additions and 560 deletions.
2 changes: 2 additions & 0 deletions Source/ARTProtocolMessage+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// Copyright (c) 2014 Ably. All rights reserved.
//

NSString *__art_nonnull ARTProtocolMessageActionToStr(ARTProtocolMessageAction action);

ART_ASSUME_NONNULL_BEGIN

@interface ARTProtocolMessage ()
Expand Down
2 changes: 2 additions & 0 deletions Source/ARTProtocolMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ typedef NS_ENUM(NSUInteger, ARTProtocolMessageAction) {
ARTProtocolMessageAuth = 17,
};

NSString *__art_nonnull ARTProtocolMessageActionToStr(ARTProtocolMessageAction action);

ART_ASSUME_NONNULL_BEGIN

/**
Expand Down
41 changes: 41 additions & 0 deletions Source/ARTProtocolMessage.m
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,44 @@ - (ARTConnectionDetails *)getConnectionDetails {
}

@end

NSString* ARTProtocolMessageActionToStr(ARTProtocolMessageAction action) {
switch(action) {
case ARTProtocolMessageHeartbeat:
return @"Heartbeat"; //0
case ARTProtocolMessageAck:
return @"Ack"; //1
case ARTProtocolMessageNack:
return @"Nack"; //2
case ARTProtocolMessageConnect:
return @"Connect"; //3
case ARTProtocolMessageConnected:
return @"Connected"; //4
case ARTProtocolMessageDisconnect:
return @"Disconnect"; //5
case ARTProtocolMessageDisconnected:
return @"Disconnected"; //6
case ARTProtocolMessageClose:
return @"Close"; //7
case ARTProtocolMessageClosed:
return @"Closed"; //8
case ARTProtocolMessageError:
return @"Error"; //9
case ARTProtocolMessageAttach:
return @"Attach"; //10
case ARTProtocolMessageAttached:
return @"Attached"; //11
case ARTProtocolMessageDetach:
return @"Detach"; //12
case ARTProtocolMessageDetached:
return @"Detached"; //13
case ARTProtocolMessagePresence:
return @"Presence"; //14
case ARTProtocolMessageMessage:
return @"Message"; //15
case ARTProtocolMessageSync:
return @"Sync"; //16
case ARTProtocolMessageAuth:
return @"Auth"; //17
}
}
3 changes: 1 addition & 2 deletions Source/ARTRealtime+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ ART_ASSUME_NONNULL_BEGIN
@property (readonly, strong, nonatomic) __GENERIC(ARTEventEmitter, NSNumber *, ARTConnectionStateChange *) *internalEventEmitter;
@property (readonly, strong, nonatomic) __GENERIC(ARTEventEmitter, NSNull *, NSNull *) *connectedEventEmitter;

+ (NSString *)protocolStr:(ARTProtocolMessageAction)action;

// State properties
- (BOOL)shouldSendEvents;
- (BOOL)shouldQueueEvents;
Expand All @@ -48,6 +46,7 @@ ART_ASSUME_NONNULL_BEGIN
@property (readonly, getter=getTransport, art_nullable) id<ARTRealtimeTransport> transport;
@property (readonly, strong, nonatomic, art_nonnull) id<ARTReachability> reachability;
@property (readonly, getter=getLogger) ARTLog *logger;
@property (nonatomic) NSTimeInterval connectionStateTtl;

/// Current protocol `msgSerial`. Starts at zero.
@property (readwrite, assign, nonatomic) int64_t msgSerial;
Expand Down
91 changes: 29 additions & 62 deletions Source/ARTRealtime.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ @implementation ARTRealtime {
BOOL _renewingToken;
__GENERIC(ARTEventEmitter, NSNull *, ARTErrorInfo *) *_pingEventEmitter;
NSDate *_startedReconnection;
NSTimeInterval _connectionStateTtl;
Class _transportClass;
Class _reachabilityClass;
id<ARTRealtimeTransport> _transport;
Expand Down Expand Up @@ -312,7 +311,7 @@ - (void)transitionSideEffects:(ARTConnectionStateChange *)stateChange usingEvent
if (!_transport) {
NSString *resumeKey = nil;
NSNumber *connectionSerial = nil;
if (stateChange.previous == ARTRealtimeFailed || stateChange.previous == ARTRealtimeDisconnected) {
if (stateChange.previous == ARTRealtimeFailed || stateChange.previous == ARTRealtimeDisconnected || stateChange.previous == ARTRealtimeSuspended) {
resumeKey = self.connection.key;
connectionSerial = [NSNumber numberWithLongLong:self.connection.serial];
_resuming = true;
Expand Down Expand Up @@ -432,6 +431,12 @@ - (void)transitionSideEffects:(ARTConnectionStateChange *)stateChange usingEvent

if ([self shouldSendEvents]) {
[self sendQueuedMessages];
// For every Channel
for (ARTRealtimeChannel* channel in self.channels) {
if (channel.state == ARTRealtimeChannelSuspended) {
[channel attach];
}
}
} else if (![self shouldQueueEvents]) {
[self failQueuedMessages:status];
ARTStatus *channelStatus = status;
Expand All @@ -440,22 +445,27 @@ - (void)transitionSideEffects:(ARTConnectionStateChange *)stateChange usingEvent
}
// For every Channel
for (ARTRealtimeChannel* channel in self.channels) {
if (channel.state == ARTRealtimeChannelInitialized || channel.state == ARTRealtimeChannelAttaching || channel.state == ARTRealtimeChannelAttached || channel.state == ARTRealtimeChannelFailed) {
if(stateChange.current == ARTRealtimeClosing) {
//do nothing. Closed state is coming.
}
else if(stateChange.current == ARTRealtimeClosed) {
[channel detachChannel:[ARTStatus state:ARTStateOk]];
}
else if(stateChange.current == ARTRealtimeSuspended) {
[channel detachChannel:channelStatus];
}
else {
[channel setFailed:channelStatus];
}
}
else {
[channel setSuspended:channelStatus];
switch (channel.state) {
case ARTRealtimeChannelInitialized:
case ARTRealtimeChannelAttaching:
case ARTRealtimeChannelAttached:
case ARTRealtimeChannelFailed:
if (stateChange.current == ARTRealtimeClosing) {
//do nothing. Closed state is coming.
}
else if (stateChange.current == ARTRealtimeClosed) {
[channel detachChannel:[ARTStatus state:ARTStateOk]];
}
else if (stateChange.current == ARTRealtimeSuspended) {
[channel setSuspended:channelStatus];
}
else {
[channel setFailed:channelStatus];
}
break;
default:
[channel setSuspended:channelStatus];
break;
}
}
}
Expand Down Expand Up @@ -942,49 +952,6 @@ - (void)setReachabilityClass:(Class)reachabilityClass {
_reachabilityClass = reachabilityClass;
}

+ (NSString *)protocolStr:(ARTProtocolMessageAction) action {
switch(action) {
case ARTProtocolMessageHeartbeat:
return @"Heartbeat"; //0
case ARTProtocolMessageAck:
return @"Ack"; //1
case ARTProtocolMessageNack:
return @"Nack"; //2
case ARTProtocolMessageConnect:
return @"Connect"; //3
case ARTProtocolMessageConnected:
return @"Connected"; //4
case ARTProtocolMessageDisconnect:
return @"Disconnect"; //5
case ARTProtocolMessageDisconnected:
return @"Disconnected"; //6
case ARTProtocolMessageClose:
return @"Close"; //7
case ARTProtocolMessageClosed:
return @"Closed"; //8
case ARTProtocolMessageError:
return @"Error"; //9
case ARTProtocolMessageAttach:
return @"Attach"; //10
case ARTProtocolMessageAttached:
return @"Attached"; //11
case ARTProtocolMessageDetach:
return @"Detach"; //12
case ARTProtocolMessageDetached:
return @"Detached"; //13
case ARTProtocolMessagePresence:
return @"Presence"; //14
case ARTProtocolMessageMessage:
return @"Message"; //15
case ARTProtocolMessageSync:
return @"Sync"; //16
case ARTProtocolMessageAuth:
return @"Auth"; //17
default:
return [NSString stringWithFormat: @"unknown protocol state %d", (int)action];
}
}

#pragma mark - ARTRealtimeTransportDelegate implementation

- (void)realtimeTransport:(id)transport didReceiveMessage:(ARTProtocolMessage *)message {
Expand All @@ -993,7 +960,7 @@ - (void)realtimeTransport:(id)transport didReceiveMessage:(ARTProtocolMessage *)
return;
}

[self.logger verbose:@"R:%p ARTRealtime didReceive Protocol Message %@ ", self, [ARTRealtime protocolStr:message.action]];
[self.logger verbose:@"R:%p ARTRealtime didReceive Protocol Message %@ ", self, ARTProtocolMessageActionToStr(message.action)];

if (message.error) {
[self.logger verbose:@"R:%p ARTRealtime Protocol Message with error %@ ", self, message.error];
Expand Down
2 changes: 1 addition & 1 deletion Source/ARTRealtimeChannel+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ART_ASSUME_NONNULL_BEGIN
@property (readwrite, strong, nonatomic) NSMutableArray *queuedMessages;
@property (readwrite, strong, nonatomic, art_nullable) NSString *attachSerial;
@property (readonly, getter=getClientId) NSString *clientId;
@property (readonly, strong, nonatomic) __GENERIC(ARTEventEmitter, NSNumber *, ARTErrorInfo *) *statesEventEmitter;
@property (readonly, strong, nonatomic) __GENERIC(ARTEventEmitter, NSNumber *, ARTChannelStateChange *) *statesEventEmitter;
@property (readonly, strong, nonatomic) __GENERIC(ARTEventEmitter, NSString *, ARTMessage *) *messagesEventEmitter;
@property (readonly, strong, nonatomic) __GENERIC(ARTEventEmitter, NSNumber *, ARTPresenceMessage *) *presenceEventEmitter;
@property (readwrite, strong, nonatomic) ARTPresenceMap *presenceMap;
Expand Down
2 changes: 1 addition & 1 deletion Source/ARTRealtimeChannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ ART_ASSUME_NONNULL_BEGIN

- (BOOL)history:(ARTRealtimeHistoryQuery *__art_nullable)query callback:(void(^)(__GENERIC(ARTPaginatedResult, ARTMessage *) *__art_nullable result, ARTErrorInfo *__art_nullable error))callback error:(NSError *__art_nullable *__art_nullable)errorPtr;

ART_EMBED_INTERFACE_EVENT_EMITTER(ARTChannelEvent, ARTErrorInfo *)
ART_EMBED_INTERFACE_EVENT_EMITTER(ARTChannelEvent, ARTChannelStateChange *)

@end

Expand Down
27 changes: 14 additions & 13 deletions Source/ARTRealtimeChannel.m
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ - (void)publishProtocolMessage:(ARTProtocolMessage *)pm callback:(void (^)(ARTSt
[self addToQueue:pm callback:cb];
break;
}
case ARTRealtimeChannelSuspended:
case ARTRealtimeChannelDetaching:
case ARTRealtimeChannelDetached:
case ARTRealtimeChannelFailed:
Expand All @@ -180,8 +181,6 @@ - (void)publishProtocolMessage:(ARTProtocolMessage *)pm callback:(void (^)(ARTSt
}
break;
}
default:
NSAssert(NO, @"Invalid State");
}
}

Expand Down Expand Up @@ -272,19 +271,19 @@ - (void)unsubscribe:(NSString *)name listener:(ARTEventListener<ARTMessage *> *)
[self.messagesEventEmitter off:name listener:listener];
}

- (__GENERIC(ARTEventListener, ARTErrorInfo *) *)on:(ARTChannelEvent)event callback:(void (^)(ARTErrorInfo *))cb {
- (__GENERIC(ARTEventListener, ARTChannelStateChange *) *)on:(ARTChannelEvent)event callback:(void (^)(ARTChannelStateChange *))cb {
return [self.statesEventEmitter on:[NSNumber numberWithInt:event] callback:cb];
}

- (__GENERIC(ARTEventListener, ARTErrorInfo *) *)on:(void (^)(ARTErrorInfo *))cb {
- (__GENERIC(ARTEventListener, ARTChannelStateChange *) *)on:(void (^)(ARTChannelStateChange *))cb {
return [self.statesEventEmitter on:cb];
}

- (__GENERIC(ARTEventListener, ARTErrorInfo *) *)once:(ARTChannelEvent)event callback:(void (^)(ARTErrorInfo *))cb {
- (__GENERIC(ARTEventListener, ARTChannelStateChange *) *)once:(ARTChannelEvent)event callback:(void (^)(ARTChannelStateChange *))cb {
return [self.statesEventEmitter once:[NSNumber numberWithInt:event] callback:cb];
}

- (__GENERIC(ARTEventListener, ARTErrorInfo *) *)once:(void (^)(ARTErrorInfo *))cb {
- (__GENERIC(ARTEventListener, ARTChannelStateChange *) *)once:(void (^)(ARTChannelStateChange *))cb {
return [self.statesEventEmitter once:cb];
}

Expand All @@ -295,11 +294,11 @@ - (void)off:(ARTChannelEvent)event listener:listener {
[self.statesEventEmitter off:[NSNumber numberWithInt:event] listener:listener];
}

- (void)off:(__GENERIC(ARTEventListener, ARTErrorInfo *) *)listener {
- (void)off:(__GENERIC(ARTEventListener, ARTChannelStateChange *) *)listener {
[self.statesEventEmitter off:listener];
}

- (void)emit:(ARTChannelEvent)event with:(ARTErrorInfo *)data {
- (void)emit:(ARTChannelEvent)event with:(ARTChannelStateChange *)data {
[self.statesEventEmitter emit:[NSNumber numberWithInt:event] with:data];
}

Expand All @@ -308,6 +307,7 @@ - (ARTEventListener *)timed:(ARTEventListener *)listener deadline:(NSTimeInterva
}

- (void)transition:(ARTRealtimeChannelState)state status:(ARTStatus *)status {
ARTChannelStateChange *stateChange = [[ARTChannelStateChange alloc] initWithCurrent:state previous:self.state reason:status.errorInfo];
self.state = state;
_errorReason = status.errorInfo;

Expand All @@ -321,7 +321,7 @@ - (void)transition:(ARTRealtimeChannelState)state status:(ARTStatus *)status {
[_attachedEventEmitter emit:[NSNull null] with:[ARTErrorInfo createWithCode:90000 message:msg]];
}

[self emit:(ARTChannelEvent)state with:status.errorInfo];
[self emit:(ARTChannelEvent)stateChange.current with:stateChange];
}

- (void)dealloc {
Expand All @@ -339,7 +339,8 @@ - (void)unlessStateChangesBefore:(NSTimeInterval)deadline do:(void(^)())callback
// Already changed; do nothing.
return;
}
[self timed:[self once:^(ARTErrorInfo *errorInfo) {
// FIXME: should not use the global listener for internal purpose
[self timed:[self once:^(ARTChannelStateChange *stateChange) {
// Any state change cancels the timeout.
}] deadline:deadline onTimeout:callback];
});
Expand Down Expand Up @@ -397,8 +398,8 @@ - (void)setAttached:(ARTProtocolMessage *)message {
if (self.state == ARTRealtimeChannelAttached) {
if (message.error != nil) {
_errorReason = message.error;
[self emit:ARTChannelEventUpdate with:message.error];
}
[self emit:ARTChannelEventUpdate with:[[ARTChannelStateChange alloc] initWithCurrent:self.state previous:self.state reason:message.error]];
return;
}

Expand Down Expand Up @@ -448,7 +449,7 @@ - (void)setFailed:(ARTStatus *)error {

- (void)setSuspended:(ARTStatus *)error {
[self failQueuedMessages:error];
[self transition:ARTRealtimeChannelDetached status:error];
[self transition:ARTRealtimeChannelSuspended status:error];
}

- (void)onMessage:(ARTProtocolMessage *)message {
Expand All @@ -463,7 +464,7 @@ - (void)onMessage:(ARTProtocolMessage *)message {
ARTErrorInfo *errorInfo = [ARTErrorInfo wrap:(ARTErrorInfo *)error.userInfo[NSLocalizedFailureReasonErrorKey] prepend:@"Failed to decode data: "];
[self.logger error:@"R:%p C:%p %@", _realtime, self, errorInfo.message];
_errorReason = errorInfo;
[self emit:ARTChannelEventUpdate with:errorInfo];
[self emit:ARTChannelEventUpdate with:[[ARTChannelStateChange alloc] initWithCurrent:self.state previous:self.state reason:errorInfo]];
}
}

Expand Down
25 changes: 25 additions & 0 deletions Source/ARTTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ typedef NS_ENUM(NSUInteger, ARTRealtimeChannelState) {
ARTRealtimeChannelAttached,
ARTRealtimeChannelDetaching,
ARTRealtimeChannelDetached,
ARTRealtimeChannelSuspended,
ARTRealtimeChannelFailed
};

Expand All @@ -90,12 +91,14 @@ typedef NS_ENUM(NSUInteger, ARTChannelEvent) {
ARTChannelEventAttached,
ARTChannelEventDetaching,
ARTChannelEventDetached,
ARTChannelEventSuspended,
ARTChannelEventFailed,
ARTChannelEventUpdate
};

NSString *__art_nonnull ARTChannelEventToStr(ARTChannelEvent event);


typedef NS_ENUM(NSInteger, ARTDataQueryError) {
ARTDataQueryErrorLimit = 1,
ARTDataQueryErrorTimestampRange = 2,
Expand Down Expand Up @@ -144,6 +147,28 @@ NSString *generateNonce();

@end

#pragma mark - ARTChannelStateChange

@interface ARTChannelStateChange : NSObject

- (instancetype)initWithCurrent:(ARTRealtimeChannelState)current
previous:(ARTRealtimeChannelState)previous
reason:(ARTErrorInfo *__art_nullable)reason;

- (instancetype)initWithCurrent:(ARTRealtimeChannelState)current
previous:(ARTRealtimeChannelState)previous
reason:(ARTErrorInfo *__art_nullable)reason
resumed:(BOOL)resumed;

@property (readonly, nonatomic) ARTRealtimeChannelState current;
@property (readonly, nonatomic) ARTRealtimeChannelState previous;
@property (readonly, nonatomic, art_nullable) ARTErrorInfo *reason;
@property (readonly, nonatomic) BOOL resumed;

@end

#pragma mark - ARTJsonCompatible

@protocol ARTJsonCompatible <NSObject>
- (NSDictionary *__art_nullable)toJSON:(NSError *__art_nullable *__art_nullable)error;
@end
Expand Down
Loading

0 comments on commit 7f1309b

Please sign in to comment.