From ebc91c29a9eaf9f94044c37216d74a2767c943d7 Mon Sep 17 00:00:00 2001 From: Marat Al Date: Tue, 16 May 2023 01:59:01 +0200 Subject: [PATCH] Updated presence map according to the new specs RTP17*. Co-authored-by: ikbalkaya --- Source/ARTPresenceMap.m | 22 +++++------ Source/ARTProtocolMessage.m | 1 + Source/ARTRealtimeChannel.m | 18 ++++++--- Source/ARTRealtimePresence.m | 38 +++++++++++++++++++ Source/PrivateHeaders/Ably/ARTPresenceMap.h | 2 + .../Ably/ARTRealtimePresence+Private.h | 2 + 6 files changed, 66 insertions(+), 17 deletions(-) diff --git a/Source/ARTPresenceMap.m b/Source/ARTPresenceMap.m index 8cfb372d0..ea66920e6 100644 --- a/Source/ARTPresenceMap.m +++ b/Source/ARTPresenceMap.m @@ -39,7 +39,7 @@ @interface ARTPresenceMap () { ARTPresenceSyncState _syncState; ARTEventEmitter *_syncEventEmitter; NSMutableDictionary *_members; - NSMutableSet *_localMembers; + NSMutableDictionary *_localMembers; // RTP17h } @end @@ -64,7 +64,7 @@ - (instancetype)initWithQueue:(_Nonnull dispatch_queue_t)queue logger:(ARTIntern return _members; } -- (NSMutableSet *)localMembers { +- (NSDictionary *)localMembers { return _localMembers; } @@ -102,7 +102,7 @@ - (void)internalAdd:(ARTPresenceMessage *)message withSessionId:(NSUInteger)sess [_members setObject:message forKey:message.memberKey]; // Local member if ([message.connectionId isEqualToString:self.delegate.connectionId]) { - [_localMembers addObject:message]; + _localMembers[message.clientId] = message; ARTLogDebug(_logger, @"local member %@ with action %@ has been added", message.memberKey, ARTPresenceActionToStr(message.action).uppercaseString); } } @@ -113,7 +113,7 @@ - (void)internalRemove:(ARTPresenceMessage *)message { - (void)internalRemove:(ARTPresenceMessage *)message force:(BOOL)force { if ([message.connectionId isEqualToString:self.delegate.connectionId] && !message.isSynthesized) { - [_localMembers removeObject:message]; + [_localMembers removeObjectForKey:message.clientId]; } const BOOL syncInProgress = self.syncInProgress; @@ -150,20 +150,18 @@ - (void)leaveMembersNotPresentInSync { } } -- (void)reenterLocalMembersMissingFromSync { - ARTLogDebug(_logger, @"%p reentering local members missed from sync (syncSessionId=%lu)", self, (unsigned long)_syncSessionId); - NSSet *filteredLocalMembers = [_localMembers filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"syncSessionId != %lu", (unsigned long)_syncSessionId]]; - for (ARTPresenceMessage *localMember in filteredLocalMembers) { +- (void)reenterLocalMembers { + ARTLogDebug(_logger, @"%p reentering local members", self); + for (ARTPresenceMessage *localMember in [_localMembers allValues]) { ARTPresenceMessage *reenter = [localMember copy]; - [self internalRemove:localMember]; [self.delegate map:self shouldReenterLocalMember:reenter]; } [self cleanUpAbsentMembers]; } - (void)reset { - _members = [NSMutableDictionary dictionary]; - _localMembers = [NSMutableSet set]; + _members = [NSMutableDictionary new]; + _localMembers = [NSMutableDictionary new]; } - (void)startSync { @@ -178,7 +176,7 @@ - (void)endSync { [self cleanUpAbsentMembers]; [self leaveMembersNotPresentInSync]; _syncState = ARTPresenceSyncEnded; - [self reenterLocalMembersMissingFromSync]; + [_syncEventEmitter emit:[ARTEvent newWithPresenceSyncState:ARTPresenceSyncEnded] with:[_members allValues]]; [_syncEventEmitter off]; ARTLogDebug(_logger, @"%p PresenceMap sync ended", self); diff --git a/Source/ARTProtocolMessage.m b/Source/ARTProtocolMessage.m index 55b9f1e85..e36d0bb1c 100644 --- a/Source/ARTProtocolMessage.m +++ b/Source/ARTProtocolMessage.m @@ -51,6 +51,7 @@ - (NSString *)description { [description appendFormat:@" flags.hasBacklog: %@,\n", NSStringFromBOOL(self.hasBacklog)]; [description appendFormat:@" flags.resumed: %@,\n", NSStringFromBOOL(self.resumed)]; [description appendFormat:@" messages: %@\n", self.messages]; + [description appendFormat:@" presence: %@\n", self.presence]; [description appendFormat:@" params: %@\n", self.params]; [description appendFormat:@"}"]; return description; diff --git a/Source/ARTRealtimeChannel.m b/Source/ARTRealtimeChannel.m index 644f44a35..2a6d20643 100644 --- a/Source/ARTRealtimeChannel.m +++ b/Source/ARTRealtimeChannel.m @@ -773,6 +773,7 @@ - (void)setAttached:(ARTProtocolMessage *)message { [_attachedEventEmitter emit:nil with:nil]; [self.presence sendPendingPresence]; + [self.presenceMap reenterLocalMembers]; // RTP17f, RTP17g } - (void)setDetached:(ARTProtocolMessage *)message { @@ -1232,11 +1233,18 @@ - (void)map:(ARTPresenceMap *)map didRemovedMemberNoLongerPresent:(ARTPresenceMe } - (void)map:(ARTPresenceMap *)map shouldReenterLocalMember:(ARTPresenceMessage *)presence { - [self.presence enterClient:presence.clientId data:presence.data callback:^(ARTErrorInfo *error) { - NSString *message = [NSString stringWithFormat:@"Re-entering member \"%@\" as failed with code %ld (%@)", presence.clientId, (long)error.code, error.message]; - ARTErrorInfo *reenterError = [ARTErrorInfo createWithCode:ARTErrorUnableToAutomaticallyReEnterPresenceChannel message:message]; - ARTChannelStateChange *stateChange = [[ARTChannelStateChange alloc] initWithCurrent:self.state_nosync previous:self.state_nosync event:ARTChannelEventUpdate reason:reenterError resumed:true]; - [self emit:stateChange.event with:stateChange]; + [self.presence reenterWithPresenceMessage:presence callback:^(ARTErrorInfo *error) { + if (error != nil) { + NSString *message = [NSString stringWithFormat:@"Re-entering member \"%@\" is failed with code %ld (%@)", presence.clientId, (long)error.code, error.message]; + ARTErrorInfo *reenterError = [ARTErrorInfo createWithCode:ARTErrorUnableToAutomaticallyReEnterPresenceChannel message:message]; + ARTLogError(self.logger, @"%@", reenterError); + ARTChannelStateChange *stateChange = [[ARTChannelStateChange alloc] initWithCurrent:self.state_nosync previous:self.state_nosync event:ARTChannelEventUpdate reason:reenterError resumed:true]; // RTP17e + [self emit:stateChange.event with:stateChange]; + ARTLogWarn(self.logger, @"RT:%p C:%p (%@) Re-entering member \"%@\" is failed with code %ld (%@)", self->_realtime, self, self.name, presence.memberKey, (long)error.code, error.message); + } + else { + ARTLogDebug(self.logger, @"RT:%p C:%p (%@) re-entered local member \"%@\"", self->_realtime, self, self.name, presence.memberKey); + } }]; ARTLogDebug(self.logger, @"RT:%p C:%p (%@) re-entering local member \"%@\"", _realtime, self, self.name, presence.memberKey); } diff --git a/Source/ARTRealtimePresence.m b/Source/ARTRealtimePresence.m index 7e308fe22..eeeb19254 100644 --- a/Source/ARTRealtimePresence.m +++ b/Source/ARTRealtimePresence.m @@ -283,6 +283,20 @@ - (void)enterClient:(NSString *)clientId data:(id)data callback:(ARTCallback)cb }); } +- (void)reenterWithPresenceMessage:(ARTPresenceMessage *)message callback:(ARTCallback)cb { + if (cb) { + ARTCallback userCallback = cb; + cb = ^(ARTErrorInfo *_Nullable error) { + dispatch_async(self->_userQueue, ^{ + userCallback(error); + }); + }; + } +dispatch_async(_queue, ^{ + [self reenterAfterChecksWithPresenceMessage:message callback:cb]; +}); +} + - (void)update:(id)data { [self update:data callback:nil]; } @@ -344,6 +358,30 @@ - (void)enterOrUpdateAfterChecks:(ARTPresenceAction)action clientId:(NSString *_ [self publishPresence:msg callback:cb]; } +- (void)reenterAfterChecksWithPresenceMessage:(ARTPresenceMessage *)message callback:(ARTCallback)cb { + switch (_channel.state_nosync) { + case ARTRealtimeChannelDetached: + case ARTRealtimeChannelFailed: { + if (cb) { + ARTErrorInfo *channelError = [ARTErrorInfo createWithCode:ARTErrorChannelOperationFailedInvalidState message:[NSString stringWithFormat:@"unable to enter presence channel (incompatible channel state: %@)", ARTRealtimeChannelStateToStr(_channel.state_nosync)]]; + cb(channelError); + } + return; + } + default: + break; + } + + ARTPresenceMessage *msg = [[ARTPresenceMessage alloc] init]; + msg.action = ARTPresenceEnter; + msg.id = message.id; // RTP17g + msg.clientId = message.clientId; + msg.data = message.data; + msg.connectionId = _channel.realtime.connection.id_nosync; + + [self publishPresence:msg callback:cb]; +} + - (void)leave:(id)data { [self leave:data callback:nil]; } diff --git a/Source/PrivateHeaders/Ably/ARTPresenceMap.h b/Source/PrivateHeaders/Ably/ARTPresenceMap.h index 55cb292a9..5917d4e01 100644 --- a/Source/PrivateHeaders/Ably/ARTPresenceMap.h +++ b/Source/PrivateHeaders/Ably/ARTPresenceMap.h @@ -49,6 +49,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)internalAdd:(ARTPresenceMessage *)message; - (void)internalAdd:(ARTPresenceMessage *)message withSessionId:(NSUInteger)sessionId; +- (void)reenterLocalMembers; + @end NS_ASSUME_NONNULL_END diff --git a/Source/PrivateHeaders/Ably/ARTRealtimePresence+Private.h b/Source/PrivateHeaders/Ably/ARTRealtimePresence+Private.h index c16b32a30..6c3caad5b 100644 --- a/Source/PrivateHeaders/Ably/ARTRealtimePresence+Private.h +++ b/Source/PrivateHeaders/Ably/ARTRealtimePresence+Private.h @@ -12,6 +12,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)sendPendingPresence; - (void)failPendingPresence:(ARTStatus *)status; +- (void)reenterWithPresenceMessage:(ARTPresenceMessage *)message callback:(ARTCallback)cb; + @property (nonatomic) dispatch_queue_t queue; @property (readwrite, nonatomic) ARTPresenceAction lastPresenceAction; @property (readonly, nonatomic) NSMutableArray *pendingPresence;