From e1cb005f799b8873c737b991ef6e047031fd539a Mon Sep 17 00:00:00 2001 From: Ricardo Pereira Date: Thu, 12 Nov 2015 18:49:31 +0000 Subject: [PATCH] ARTPresence wasn't working. Fixed recursive cicle ... - (Conflicts) Separated base ARTPresence: ARTRealtimePresence and ARTRestPresence - ARTRestPresence has base class for ARTRealtimePresence --- ably-ios/ARTChannel+Private.h | 5 +- ably-ios/ARTChannel.h | 7 +- ably-ios/ARTChannel.m | 5 +- ably-ios/ARTPresence.h | 19 +-- ably-ios/ARTPresence.m | 124 ++--------------- ably-ios/ARTPresenceMap.h | 4 +- ably-ios/ARTRealtimeChannel.h | 8 +- ably-ios/ARTRealtimeChannel.m | 5 +- ably-ios/ARTRealtimeChannelSubscription.h | 3 + ably-ios/ARTRealtimeChannelSubscription.m | 7 +- ably-ios/ARTRealtimePresence.h | 32 +++++ ably-ios/ARTRealtimePresence.m | 129 ++++++++++++++++++ ably-ios/ARTRestChannel+Private.h | 16 +++ ably-ios/ARTRestChannel.h | 1 - ably-ios/ARTRestChannel.m | 11 +- ably-ios/ARTRestPresence.h | 22 +++ ably-ios/ARTRestPresence.m | 63 +++++++++ ably-ios/ably.h | 2 + ably-ios/ably.modulemap | 6 +- ably-iosTests/ARTRealtimeAttachTest.m | 5 +- .../ARTRealtimePresenceHistoryTest.m | 2 +- ably-iosTests/ARTRealtimePresenceTest.m | 2 +- ably-iosTests/ARTTestUtil.m | 2 +- ably.xcodeproj/project.pbxproj | 28 +++- 24 files changed, 340 insertions(+), 168 deletions(-) create mode 100644 ably-ios/ARTRealtimePresence.h create mode 100644 ably-ios/ARTRealtimePresence.m create mode 100644 ably-ios/ARTRestChannel+Private.h create mode 100644 ably-ios/ARTRestPresence.h create mode 100644 ably-ios/ARTRestPresence.m diff --git a/ably-ios/ARTChannel+Private.h b/ably-ios/ARTChannel+Private.h index ca5e94271..5121f3eb9 100644 --- a/ably-ios/ARTChannel+Private.h +++ b/ably-ios/ARTChannel+Private.h @@ -13,10 +13,7 @@ ART_ASSUME_NONNULL_BEGIN -@interface ARTChannel() { -@public - id _payloadEncoder; -} +@interface ARTChannel() @property (nonatomic, strong, art_null_resettable) ARTChannelOptions *options; diff --git a/ably-ios/ARTChannel.h b/ably-ios/ARTChannel.h index d0e1ad371..118519a99 100644 --- a/ably-ios/ARTChannel.h +++ b/ably-ios/ARTChannel.h @@ -9,6 +9,8 @@ #import #import "ARTTypes.h" +@protocol ARTPayloadEncoder; + @class ARTChannelOptions; @class ARTMessage; @class ARTPaginatedResult; @@ -20,6 +22,8 @@ ART_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, readonly) NSString *name; +@property (readonly, strong, nonatomic) id payloadEncoder; + - (instancetype)initWithName:(NSString *)name andOptions:(ARTChannelOptions *)options; - (void)publish:(art_nullable id)payload callback:(art_nullable ARTErrorCallback)callback; @@ -30,9 +34,6 @@ ART_ASSUME_NONNULL_BEGIN - (void)history:(art_nullable ARTDataQuery *)query callback:(void(^)(ARTPaginatedResult /* */ *__art_nullable result, NSError *__art_nullable error))callback; -// TODO: -//- (void)presence - @end ART_ASSUME_NONNULL_END diff --git a/ably-ios/ARTChannel.m b/ably-ios/ARTChannel.m index 59e304065..3b014193f 100644 --- a/ably-ios/ARTChannel.m +++ b/ably-ios/ARTChannel.m @@ -19,6 +19,7 @@ - (instancetype)initWithName:(NSString *)name andOptions:(ARTChannelOptions *)op if (self = [super init]) { _name = name; _options = options; + _payloadEncoder = [ARTPayload defaultPayloadEncoder:options.cipherParams]; } return self; } @@ -42,14 +43,14 @@ - (void)publish:(id)data name:(NSString *)name callback:(ARTErrorCallback)callba - (void)publishMessages:(NSArray *)messages callback:(ARTErrorCallback)callback { messages = [messages artMap:^(ARTMessage *message) { - return [message encode:_payloadEncoder]; + return [message encode:self.payloadEncoder]; }]; [self internalPostMessages:messages callback:callback]; } - (void)publishMessage:(ARTMessage *)message callback:(ARTErrorCallback)callback { - [self internalPostMessages:[message encode:_payloadEncoder] callback:callback]; + [self internalPostMessages:[message encode:self.payloadEncoder] callback:callback]; } - (void)history:(ARTDataQuery *)query callback:(void (^)(ARTPaginatedResult *, NSError *))callback { diff --git a/ably-ios/ARTPresence.h b/ably-ios/ARTPresence.h index 0f267b5e1..c9011d918 100644 --- a/ably-ios/ARTPresence.h +++ b/ably-ios/ARTPresence.h @@ -13,7 +13,6 @@ @protocol ARTSubscription; @class ARTChannel; -@class ARTRealtimeChannel; @class ARTPaginatedResult; @class ARTDataQuery; @@ -24,7 +23,9 @@ ART_ASSUME_NONNULL_BEGIN */ @interface ARTPresence : NSObject -- (instancetype)initWithChannel:(ARTRealtimeChannel *)channel; +@property (readonly, getter=getChannel) ARTChannel *channel; + +- (instancetype)initWithChannel:(ARTChannel *)channel; /** Get the presence state for one channel @@ -36,20 +37,6 @@ ART_ASSUME_NONNULL_BEGIN */ - (void)history:(art_nullable ARTDataQuery *)query callback:(void (^)(ARTPaginatedResult /* */ *__art_nullable result, NSError *__art_nullable error))callback; -- (void)enter:(id)data cb:(ARTStatusCallback)cb; -- (void)update:(id)data cb:(ARTStatusCallback)cb; -- (void)leave:(id) data cb:(ARTStatusCallback)cb; - -- (void)enterClient:(NSString *) clientId data:(id) data cb:(ARTStatusCallback) cb; -- (void)updateClient:(NSString *) clientId data:(id) data cb:(ARTStatusCallback) cb; -- (void)leaveClient:(NSString *) clientId data:(id) data cb:(ARTStatusCallback) cb; -- (BOOL)isSyncComplete; - -- (id)subscribe:(ARTRealtimeChannelPresenceCb)cb; -- (id)subscribe:(ARTPresenceAction)action cb:(ARTRealtimeChannelPresenceCb)cb; -- (void)unsubscribe:(id)subscription; -- (void)unsubscribe:(id)subscription action:(ARTPresenceAction)action; - @end ART_ASSUME_NONNULL_END diff --git a/ably-ios/ARTPresence.m b/ably-ios/ARTPresence.m index 6f339ff71..14c059026 100644 --- a/ably-ios/ARTPresence.m +++ b/ably-ios/ARTPresence.m @@ -8,135 +8,33 @@ #import "ARTPresence.h" -#import "ARTLog.h" -#import "ARTRealtime.h" -#import "ARTRealtimeChannel+Private.h" -#import "ARTPresenceMap.h" -#import "ARTStatus.h" -#import "ARTRealtimeChannelSubscription.h" -#import "ARTDataQuery+Private.h" -#import "ARTRest.h" -#import "ARTAuth.h" +#import "ARTChannel.h" -@interface ARTPresence () - -@property (readonly, weak, nonatomic) ARTRealtimeChannel *channel; +@interface ARTPresence () { + ARTChannel *_channel; +} @end @implementation ARTPresence -- (instancetype) initWithChannel:(ARTRealtimeChannel *) channel { +- (instancetype) initWithChannel:(ARTChannel *) channel { if (self = [super init]) { _channel = channel; } return self; } -- (void)get:(void (^)(ARTPaginatedResult /* */ *result, NSError *error))callback { - [self.channel throwOnDisconnectedOrFailed]; - [self.channel.presence get:callback]; +- (ARTChannel *)getChannel { + return _channel; } -- (void)history:(ARTDataQuery *)query callback:(void (^)(ARTPaginatedResult /* */ *result, NSError *error))callback { - [self.channel throwOnDisconnectedOrFailed]; - [self.channel.presence history:query callback:callback]; -} - -- (void)enter:(id)data cb:(ARTStatusCallback)cb { - [self enterClient:self.channel.clientId data:data cb:cb]; -} - -- (void)enterClient:(NSString *)clientId data:(id)data cb:(ARTStatusCallback)cb { - if (!clientId) { - [NSException raise:@"Cannot publish presence without a clientId" format:@""]; - } - ARTPresenceMessage *msg = [[ARTPresenceMessage alloc] init]; - msg.action = ARTPresenceEnter; - msg.clientId = clientId; - if(data) { - msg.payload = [ARTPayload payloadWithPayload:data encoding:@""]; - } - - msg.connectionId = self.channel.realtime.connectionId; - [self.channel publishPresence:msg cb:cb]; -} - -- (void)update:(id)data cb:(ARTStatusCallback)cb { - [self updateClient:self.channel.clientId data:data cb:cb]; -} - -- (void)updateClient:(NSString *) clientId data:(id) data cb:(ARTStatusCallback) cb { - ARTPresenceMessage *msg = [[ARTPresenceMessage alloc] init]; - msg.action = ARTPresenceUpdate; - msg.clientId = clientId; - if(!msg.clientId) { - cb([ARTStatus state:ARTStateNoClientId]); - return; - } - if(data) { - msg.payload = [ARTPayload payloadWithPayload:data encoding:@""]; - } - msg.connectionId = self.channel.realtime.connectionId; - - [self.channel publishPresence:msg cb:cb]; - -} - -- (void)leave:(id) data cb:(ARTStatusCallback)cb { - [self leaveClient:self.channel.clientId data:data cb:cb]; -} - -- (void) leaveClient:(NSString *) clientId data:(id) data cb:(ARTStatusCallback) cb { - - if([clientId isEqualToString:self.channel.clientId]) { - if(self.channel.lastPresenceAction != ARTPresenceEnter && self.channel.lastPresenceAction != ARTPresenceUpdate) { - [NSException raise:@"Cannot leave a channel before you've entered it" format:@""]; - } - } - ARTPresenceMessage *msg = [[ARTPresenceMessage alloc] init]; - msg.action = ARTPresenceLeave; - - if(data) { - msg.payload= [ARTPayload payloadWithPayload:data encoding:@""]; - } - msg.clientId = clientId; - msg.connectionId = self.channel.realtime.connectionId; - if(!msg.clientId) { - cb([ARTStatus state:ARTStateNoClientId]); - return; - } - [self.channel publishPresence:msg cb:cb]; - -} - -- (BOOL)isSyncComplete { - return [self.channel.presenceMap isSyncComplete]; -} - -- (id)subscribe:(ARTRealtimeChannelPresenceCb)cb { - ARTRealtimeChannelPresenceSubscription *subscription = [[ARTRealtimeChannelPresenceSubscription alloc] initWithChannel:self.channel cb:cb]; - [self.channel.presenceSubscriptions addObject:subscription]; - [self.channel attach]; - return subscription; -} - -- (id)subscribe:(ARTPresenceAction) action cb:(ARTRealtimeChannelPresenceCb)cb { - ARTRealtimeChannelPresenceSubscription *subscription = (ARTRealtimeChannelPresenceSubscription *) [self subscribe:cb]; - [subscription excludedActions]; - //[subscription excludeAllActionsExcept:action]; - return subscription; -} - -- (void)unsubscribe:(id)subscription action:(ARTPresenceAction) action { - ARTRealtimeChannelPresenceSubscription * s = (ARTRealtimeChannelPresenceSubscription *) subscription; - [s excludedActions]; - //[s excludeAction:action]; +- (void)get:(void (^)(ARTPaginatedResult /* */ *result, NSError *error))callback { + NSAssert(false, @"-[%@ %@] should always be overriden.", self.class, NSStringFromSelector(_cmd)); } -- (void)unsubscribe:(ARTRealtimeChannelPresenceSubscription *)subscription { - ARTRealtimeChannelPresenceSubscription *s = (ARTRealtimeChannelPresenceSubscription *) subscription; - [self.channel.presenceSubscriptions removeObject:s]; +- (void)history:(ARTDataQuery *)query callback:(void (^)(ARTPaginatedResult /* */ *result, NSError *error))callback { + NSAssert(false, @"-[%@ %@] should always be overriden.", self.class, NSStringFromSelector(_cmd)); } @end diff --git a/ably-ios/ARTPresenceMap.h b/ably-ios/ARTPresenceMap.h index 6743c6c63..c227241bb 100644 --- a/ably-ios/ARTPresenceMap.h +++ b/ably-ios/ARTPresenceMap.h @@ -26,10 +26,10 @@ - (void)startSync; - (void)endSync; - (BOOL)isSyncComplete; -- (BOOL) stillSyncing; +- (BOOL)stillSyncing; typedef void(^VoidCb)(); -- (void) syncMessageProcessed; +- (void)syncMessageProcessed; - (void)onSync:(VoidCb) cb; @end diff --git a/ably-ios/ARTRealtimeChannel.h b/ably-ios/ARTRealtimeChannel.h index 490371a33..a8dee58b8 100644 --- a/ably-ios/ARTRealtimeChannel.h +++ b/ably-ios/ARTRealtimeChannel.h @@ -13,11 +13,10 @@ #import "ARTPresenceMessage.h" @protocol ARTSubscription; -@protocol ARTPayloadEncoder; @class ARTRealtime; @class ARTDataQuery; -@class ARTPresence; +@class ARTRealtimePresence; @class ARTPresenceMap; @class ARTMessage; @class ARTPaginatedResult; @@ -28,7 +27,7 @@ @interface ARTRealtimeChannel : ARTRestChannel @property (readonly, strong, nonatomic) ARTRealtime *realtime; -@property (readonly, strong, nonatomic) ARTPresence *presence; +@property (readonly, strong, nonatomic) ARTRealtimePresence *presence; @property (readwrite, assign, nonatomic) ARTRealtimeChannelState state; @property (readwrite, strong, nonatomic) NSMutableArray *queuedMessages; @property (readwrite, strong, nonatomic) NSString *attachSerial; @@ -37,8 +36,7 @@ @property (readonly, strong, nonatomic) NSMutableDictionary *presenceDict; @property (readonly, getter=getClientId) NSString *clientId; @property (readonly, strong, nonatomic) NSMutableArray *stateSubscriptions; -@property (readonly, strong, nonatomic) id payloadEncoder; -@property (readwrite, strong, nonatomic) ARTPresenceMap * presenceMap; +@property (readwrite, strong, nonatomic) ARTPresenceMap *presenceMap; @property (readwrite, assign, nonatomic) ARTPresenceAction lastPresenceAction; - (instancetype)initWithRealtime:(ARTRealtime *)realtime andName:(NSString *)name withOptions:(ARTChannelOptions *)options; diff --git a/ably-ios/ARTRealtimeChannel.m b/ably-ios/ARTRealtimeChannel.m index 3118769d7..7e6d4587f 100644 --- a/ably-ios/ARTRealtimeChannel.m +++ b/ably-ios/ARTRealtimeChannel.m @@ -11,7 +11,7 @@ #import "ARTRealtime+Private.h" #import "ARTMessage.h" #import "ARTAuth.h" -#import "ARTPresence.h" +#import "ARTRealtimePresence.h" #import "ARTChannel.h" #import "ARTChannelOptions.h" #import "ARTProtocolMessage.h" @@ -30,14 +30,13 @@ - (instancetype)initWithRealtime:(ARTRealtime *)realtime andName:(NSString *)nam self = [super initWithName:name withOptions:options andRest:realtime.rest]; if (self) { _realtime = realtime; - _presence = [[ARTPresence alloc] initWithChannel:self]; + _presence = [[ARTRealtimePresence alloc] initWithChannel:self]; _state = ARTRealtimeChannelInitialised; _queuedMessages = [NSMutableArray array]; _attachSerial = nil; _subscriptions = [NSMutableDictionary dictionary]; _presenceSubscriptions = [NSMutableArray array]; _stateSubscriptions = [NSMutableArray array]; - _payloadEncoder = [ARTPayload defaultPayloadEncoder:options.cipherParams]; _presenceMap =[[ARTPresenceMap alloc] init]; _lastPresenceAction = ARTPresenceAbsent; } diff --git a/ably-ios/ARTRealtimeChannelSubscription.h b/ably-ios/ARTRealtimeChannelSubscription.h index 3d7811d62..351a32863 100644 --- a/ably-ios/ARTRealtimeChannelSubscription.h +++ b/ably-ios/ARTRealtimeChannelSubscription.h @@ -34,6 +34,9 @@ - (instancetype)initWithChannel:(ARTRealtimeChannel *)channel cb:(ARTRealtimeChannelPresenceCb)cb; +- (void)excludeAction:(ARTPresenceAction)action; +- (void)excludeAllActionsExcept:(ARTPresenceAction)action; + - (void)unsubscribe; @end diff --git a/ably-ios/ARTRealtimeChannelSubscription.m b/ably-ios/ARTRealtimeChannelSubscription.m index d23310f3e..3511f2a32 100644 --- a/ably-ios/ARTRealtimeChannelSubscription.m +++ b/ably-ios/ARTRealtimeChannelSubscription.m @@ -10,7 +10,7 @@ #import "ARTRealtime.h" #import "ARTRealtimeChannel.h" -#import "ARTPresence.h" +#import "ARTRealtimePresence.h" #pragma mark - ARTRealtimeChannelSubscription @@ -47,10 +47,11 @@ - (instancetype)initWithChannel:(ARTRealtimeChannel *)channel cb:(ARTRealtimeCha return self; } -- (void)excludeAction:(ARTPresenceAction) action { +- (void)excludeAction:(ARTPresenceAction)action { [_excludedActions addObject:[NSNumber numberWithInt:(int) action]]; } -- (void)excludeAllActionsExcept:(ARTPresenceAction) action { + +- (void)excludeAllActionsExcept:(ARTPresenceAction)action { for(int i=0; i<(int) ARTPresenceLast; i++) { if(i != (int) action) { [_excludedActions addObject:[NSNumber numberWithInt:(int) i]]; diff --git a/ably-ios/ARTRealtimePresence.h b/ably-ios/ARTRealtimePresence.h new file mode 100644 index 000000000..a8a9494fd --- /dev/null +++ b/ably-ios/ARTRealtimePresence.h @@ -0,0 +1,32 @@ +// +// ARTRealtimePresence.h +// ably +// +// Created by Ricardo Pereira on 12/11/15. +// Copyright © 2015 Ably. All rights reserved. +// + +#import +#import "ARTRestPresence.h" + +@class ARTRealtimeChannel; + +@interface ARTRealtimePresence : ARTRestPresence + +- (instancetype)initWithChannel:(ARTRealtimeChannel *)channel; + +- (void)enter:(id)data cb:(ARTStatusCallback)cb; +- (void)update:(id)data cb:(ARTStatusCallback)cb; +- (void)leave:(id)data cb:(ARTStatusCallback)cb; + +- (void)enterClient:(NSString *)clientId data:(id)data cb:(ARTStatusCallback)cb; +- (void)updateClient:(NSString *)clientId data:(id)data cb:(ARTStatusCallback)cb; +- (void)leaveClient:(NSString *)clientId data:(id)data cb:(ARTStatusCallback)cb; +- (BOOL)isSyncComplete; + +- (id)subscribe:(ARTRealtimeChannelPresenceCb)cb; +- (id)subscribe:(ARTPresenceAction)action cb:(ARTRealtimeChannelPresenceCb)cb; +- (void)unsubscribe:(id)subscription; +- (void)unsubscribe:(id)subscription action:(ARTPresenceAction)action; + +@end diff --git a/ably-ios/ARTRealtimePresence.m b/ably-ios/ARTRealtimePresence.m new file mode 100644 index 000000000..cda9b6c9c --- /dev/null +++ b/ably-ios/ARTRealtimePresence.m @@ -0,0 +1,129 @@ +// +// ARTRealtimePresence.m +// ably +// +// Created by Ricardo Pereira on 12/11/15. +// Copyright © 2015 Ably. All rights reserved. +// + +#import "ARTRealtimePresence.h" + +#import "ARTRealtime.h" +#import "ARTRealtimeChannel+Private.h" +#import "ARTPresenceMap.h" +#import "ARTPresenceMessage.h" +#import "ARTRealtimeChannelSubscription.h" + +@implementation ARTRealtimePresence + +- (instancetype)initWithChannel:(ARTRealtimeChannel *)channel { + return [super initWithChannel:channel]; +} + +- (ARTRealtimeChannel *)channel { + return (ARTRealtimeChannel *)super.channel; +} + +- (void)get:(ARTDataQuery *)query callback:(void (^)(ARTPaginatedResult *result, NSError *error))callback { + [[self channel] throwOnDisconnectedOrFailed]; + [super get:callback]; +} + +- (void)history:(ARTDataQuery *)query callback:(void (^)(ARTPaginatedResult *result, NSError *error))callback { + [[self channel] throwOnDisconnectedOrFailed]; + [super history:query callback:callback]; +} + +- (void)enter:(id)data cb:(ARTStatusCallback)cb { + [self enterClient:[self channel].clientId data:data cb:cb]; +} + +- (void)enterClient:(NSString *)clientId data:(id)data cb:(ARTStatusCallback)cb { + if(!clientId) { + [NSException raise:@"Cannot publish presence without a clientId" format:@""]; + } + ARTPresenceMessage *msg = [[ARTPresenceMessage alloc] init]; + msg.action = ARTPresenceEnter; + msg.clientId = clientId; + if(data) { + msg.payload = [ARTPayload payloadWithPayload:data encoding:@""]; + } + + msg.connectionId = [self channel].realtime.connectionId; + [[self channel] publishPresence:msg cb:cb]; +} + +- (void)update:(id)data cb:(ARTStatusCallback)cb { + [self updateClient:[self channel].clientId data:data cb:cb]; +} + +- (void)updateClient:(NSString *)clientId data:(id)data cb:(ARTStatusCallback)cb { + ARTPresenceMessage *msg = [[ARTPresenceMessage alloc] init]; + msg.action = ARTPresenceUpdate; + msg.clientId = clientId; + if(!msg.clientId) { + cb([ARTStatus state:ARTStateNoClientId]); + return; + } + if(data) { + msg.payload = [ARTPayload payloadWithPayload:data encoding:@""]; + } + msg.connectionId = [self channel].realtime.connectionId; + + [[self channel] publishPresence:msg cb:cb]; +} + +- (void)leave:(id) data cb:(ARTStatusCallback)cb { + [self leaveClient:[self channel].clientId data:data cb:cb]; +} + +- (void) leaveClient:(NSString *) clientId data:(id) data cb:(ARTStatusCallback) cb { + + if([clientId isEqualToString:[self channel].clientId]) { + if([self channel].lastPresenceAction != ARTPresenceEnter && [self channel].lastPresenceAction != ARTPresenceUpdate) { + [NSException raise:@"Cannot leave a channel before you've entered it" format:@""]; + } + } + ARTPresenceMessage *msg = [[ARTPresenceMessage alloc] init]; + msg.action = ARTPresenceLeave; + + if(data) { + msg.payload= [ARTPayload payloadWithPayload:data encoding:@""]; + } + msg.clientId = clientId; + msg.connectionId = [self channel].realtime.connectionId; + if(!msg.clientId) { + cb([ARTStatus state:ARTStateNoClientId]); + return; + } + [[self channel] publishPresence:msg cb:cb]; +} + +- (BOOL)isSyncComplete { + return [[self channel].presenceMap isSyncComplete]; +} + +- (id)subscribe:(ARTRealtimeChannelPresenceCb)cb { + ARTRealtimeChannelPresenceSubscription *subscription = [[ARTRealtimeChannelPresenceSubscription alloc] initWithChannel:[self channel] cb:cb]; + [[self channel].presenceSubscriptions addObject:subscription]; + [[self channel] attach]; + return subscription; +} + +- (id)subscribe:(ARTPresenceAction)action cb:(ARTRealtimeChannelPresenceCb)cb { + ARTRealtimeChannelPresenceSubscription *subscription = (ARTRealtimeChannelPresenceSubscription *) [self subscribe:cb]; + [subscription excludeAllActionsExcept:action]; + return subscription; +} + +- (void)unsubscribe:(id)subscription action:(ARTPresenceAction) action { + ARTRealtimeChannelPresenceSubscription * s = (ARTRealtimeChannelPresenceSubscription *)subscription; + [s excludeAction:action]; +} + +- (void)unsubscribe:(ARTRealtimeChannelPresenceSubscription *)subscription { + ARTRealtimeChannelPresenceSubscription *s = (ARTRealtimeChannelPresenceSubscription *)subscription; + [[self channel].presenceSubscriptions removeObject:s]; +} + +@end diff --git a/ably-ios/ARTRestChannel+Private.h b/ably-ios/ARTRestChannel+Private.h new file mode 100644 index 000000000..9046943ba --- /dev/null +++ b/ably-ios/ARTRestChannel+Private.h @@ -0,0 +1,16 @@ + +// +// ARTRestChannel+Private.h +// ably-ios +// +// Created by Ricardo Pereira on 30/09/2015. +// Copyright (c) 2015 Ably. All rights reserved. +// + +#import "ARTRestChannel.h" + +@interface ARTRestChannel (Private) + +@property (readonly, getter=getBasePath) NSString *basePath; + +@end diff --git a/ably-ios/ARTRestChannel.h b/ably-ios/ARTRestChannel.h index 505a70f4e..f87dc9b76 100644 --- a/ably-ios/ARTRestChannel.h +++ b/ably-ios/ARTRestChannel.h @@ -11,7 +11,6 @@ #import "ARTLog.h" @class ARTRest; -@class ARTPresence; ART_ASSUME_NONNULL_BEGIN diff --git a/ably-ios/ARTRestChannel.m b/ably-ios/ARTRestChannel.m index 67ccb71b5..fa28227bb 100644 --- a/ably-ios/ARTRestChannel.m +++ b/ably-ios/ARTRestChannel.m @@ -6,16 +6,15 @@ // Copyright (c) 2015 Ably. All rights reserved. // -#import "ARTRestChannel.h" +#import "ARTRestChannel+Private.h" #import "ARTRest+Private.h" #import "ARTChannel+Private.h" #import "ARTChannelOptions.h" -#import "ARTPresence.h" #import "ARTMessage.h" #import "ARTPaginatedResult+Private.h" #import "ARTDataQuery+Private.h" -#import "ARTEncoder.h" +#import "ARTJsonEncoder.h" #import "ARTAuth.h" #import "ARTNSArray+ARTFunctional.h" @@ -37,6 +36,10 @@ - (ARTLog *)getLogger { return _rest.logger; } +- (NSString *)getBasePath { + return _basePath; +} + - (void)history:(ARTDataQuery *)query callback:(void(^)(ARTPaginatedResult *result, NSError *error))callback { NSParameterAssert(query.limit < 1000); NSParameterAssert([query.start compare:query.end] != NSOrderedDescending); @@ -48,7 +51,7 @@ - (void)history:(ARTDataQuery *)query callback:(void(^)(ARTPaginatedResult *resu ARTPaginatedResultResponseProcessor responseProcessor = ^NSArray *(NSHTTPURLResponse *response, NSData *data) { id encoder = [_rest.encoders objectForKey:response.MIMEType]; return [[encoder decodeMessages:data] artMap:^(ARTMessage *message) { - return [message decode:_payloadEncoder]; + return [message decode:self.payloadEncoder]; }]; }; diff --git a/ably-ios/ARTRestPresence.h b/ably-ios/ARTRestPresence.h new file mode 100644 index 000000000..db87a9468 --- /dev/null +++ b/ably-ios/ARTRestPresence.h @@ -0,0 +1,22 @@ +// +// ARTRestPresence.h +// ably +// +// Created by Ricardo Pereira on 12/11/15. +// Copyright © 2015 Ably. All rights reserved. +// + +#import +#import "ARTPresence.h" + +@class ARTRestChannel; + +ART_ASSUME_NONNULL_BEGIN + +@interface ARTRestPresence : ARTPresence + +- (instancetype)initWithChannel:(ARTRestChannel *)channel; + +@end + +ART_ASSUME_NONNULL_END diff --git a/ably-ios/ARTRestPresence.m b/ably-ios/ARTRestPresence.m new file mode 100644 index 000000000..79f106652 --- /dev/null +++ b/ably-ios/ARTRestPresence.m @@ -0,0 +1,63 @@ +// +// ARTRestPresence.m +// ably +// +// Created by Ricardo Pereira on 12/11/15. +// Copyright © 2015 Ably. All rights reserved. +// + +#import "ARTRestPresence.h" + +#import "ARTPresence.h" +#import "ARTRest+Private.h" +#import "ARTRestChannel+Private.h" +#import "ARTPaginatedResult+Private.h" +#import "ARTDataQuery+Private.h" +#import "ARTJsonEncoder.h" +#import "ARTNSArray+ARTFunctional.h" + +@implementation ARTRestPresence + +- (instancetype)initWithChannel:(ARTRestChannel *)channel { + return [super initWithChannel:channel]; +} + +- (ARTRestChannel *)channel { + return (ARTRestChannel *)super.channel; +} + +- (void)get:(void (^)(ARTPaginatedResult /* */ *result, NSError *error))callback { + NSURL *requestUrl = [NSURL URLWithString:[[self channel].basePath stringByAppendingPathComponent:@"presence"]]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestUrl]; + + ARTPaginatedResultResponseProcessor responseProcessor = ^(NSHTTPURLResponse *response, NSData *data) { + id encoder = [[self channel].rest.encoders objectForKey:response.MIMEType]; + NSArray *messages = [encoder decodePresenceMessages:data]; + return [messages artMap:^id(ARTPresenceMessage *pm) { + return [pm decode:[self channel].payloadEncoder]; + }]; + }; + + [ARTPaginatedResult executePaginatedRequest:request executor:[self channel].rest.httpExecutor responseProcessor:responseProcessor callback:callback]; +} + +- (void)history:(ARTDataQuery *)query callback:(void (^)(ARTPaginatedResult /* */ *result, NSError *error))callback { + NSParameterAssert(query.limit < 1000); + NSParameterAssert([query.start compare:query.end] != NSOrderedDescending); + + NSURLComponents *requestUrl = [NSURLComponents componentsWithString:[[self channel].basePath stringByAppendingPathComponent:@"presence/history"]]; + requestUrl.queryItems = [query asQueryItems]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestUrl.URL]; + + ARTPaginatedResultResponseProcessor responseProcessor = ^(NSHTTPURLResponse *response, NSData *data) { + id encoder = [[self channel].rest.encoders objectForKey:response.MIMEType]; + NSArray *messages = [encoder decodePresenceMessages:data]; + return [messages artMap:^id(ARTPresenceMessage *pm) { + return [pm decode:[self channel].payloadEncoder]; + }]; + }; + + [ARTPaginatedResult executePaginatedRequest:request executor:[self channel].rest.httpExecutor responseProcessor:responseProcessor callback:callback]; +} + +@end diff --git a/ably-ios/ably.h b/ably-ios/ably.h index 54e2a9759..0a8de6494 100644 --- a/ably-ios/ably.h +++ b/ably-ios/ably.h @@ -40,8 +40,10 @@ FOUNDATION_EXPORT const unsigned char ablyVersionString[]; #import #import #import +#import #import #import +#import #import #import #import diff --git a/ably-ios/ably.modulemap b/ably-ios/ably.modulemap index efff5cd50..b6545f861 100644 --- a/ably-ios/ably.modulemap +++ b/ably-ios/ably.modulemap @@ -5,11 +5,13 @@ framework module ably { module * { export * } explicit module Private { + header "ARTRest+Private.h" + header "ARTRestChannel+Private.h" + header "ARTRealtime+Private.h" + header "ARTRealtimeChannel+Private.h" header "ARTChannel+Private.h" header "ARTDataQuery+Private.h" header "ARTPayload+Private.h" - header "ARTRest+Private.h" - header "ARTRealtime+Private.h" header "ARTAuth+Private.h" header "ARTPaginatedResult+Private.h" header "ARTEncoder.h" diff --git a/ably-iosTests/ARTRealtimeAttachTest.m b/ably-iosTests/ARTRealtimeAttachTest.m index 67b48375e..fcbac2344 100644 --- a/ably-iosTests/ARTRealtimeAttachTest.m +++ b/ably-iosTests/ARTRealtimeAttachTest.m @@ -9,14 +9,13 @@ #import #import -#import "ARTRealtime.h" #import "ARTRealtime+Private.h" -#import "ARTRealtimeChannel+Private.h" +#import "ARTRealtimePresence.h" +#import "ARTRealtimeChannel.h" #import "ARTTestUtil.h" #import "ARTLog.h" #import "ARTEventEmitter.h" #import "ARTStatus.h" -#import "ARTPresence.h" @interface ARTRealtimeAttachTest : XCTestCase { ARTRealtime *_realtime; diff --git a/ably-iosTests/ARTRealtimePresenceHistoryTest.m b/ably-iosTests/ARTRealtimePresenceHistoryTest.m index ef2fd8b6f..8753cf8f0 100644 --- a/ably-iosTests/ARTRealtimePresenceHistoryTest.m +++ b/ably-iosTests/ARTRealtimePresenceHistoryTest.m @@ -15,7 +15,7 @@ #import "ARTTestUtil.h" #import "ARTRest.h" #import "ARTLog.h" -#import "ARTPresence.h" +#import "ARTRealtimePresence.h" #import "ARTRealtimeChannel.h" #import "ARTEventEmitter.h" #import "ARTPaginatedResult.h" diff --git a/ably-iosTests/ARTRealtimePresenceTest.m b/ably-iosTests/ARTRealtimePresenceTest.m index 7909f9905..3b299436b 100644 --- a/ably-iosTests/ARTRealtimePresenceTest.m +++ b/ably-iosTests/ARTRealtimePresenceTest.m @@ -19,7 +19,7 @@ #import "ARTRest.h" #import "ARTRealtime+Private.h" #import "ARTRealtimeChannel.h" -#import "ARTPresence.h" +#import "ARTRealtimePresence.h" #import "ARTPresenceMap.h" #import "ARTLog.h" #import "ARTCrypto.h" diff --git a/ably-iosTests/ARTTestUtil.m b/ably-iosTests/ARTTestUtil.m index d1f623600..11b384209 100644 --- a/ably-iosTests/ARTTestUtil.m +++ b/ably-iosTests/ARTTestUtil.m @@ -12,7 +12,7 @@ #import "ARTRest.h" #import "ARTRealtime.h" #import "ARTRealtimeChannel.h" -#import "ARTPresence.h" +#import "ARTRealtimePresence.h" #import "ARTPayload.h" @implementation ARTTestUtil diff --git a/ably.xcodeproj/project.pbxproj b/ably.xcodeproj/project.pbxproj index a36974b0d..0e52b5422 100644 --- a/ably.xcodeproj/project.pbxproj +++ b/ably.xcodeproj/project.pbxproj @@ -133,6 +133,11 @@ D7D8F82C1BC2C706009718F2 /* ARTAuthTokenRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = D7D8F8281BC2C706009718F2 /* ARTAuthTokenRequest.m */; }; D7D8F82D1BC2C706009718F2 /* ARTAuthTokenParams.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D8F8291BC2C706009718F2 /* ARTAuthTokenParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; D7D8F82E1BC2C706009718F2 /* ARTAuthTokenParams.m in Sources */ = {isa = PBXBuildFile; fileRef = D7D8F82A1BC2C706009718F2 /* ARTAuthTokenParams.m */; }; + D7F1D3731BF4DE07001A4B5E /* ARTRestPresence.h in Headers */ = {isa = PBXBuildFile; fileRef = D7F1D3711BF4DE07001A4B5E /* ARTRestPresence.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D7F1D3741BF4DE07001A4B5E /* ARTRestPresence.m in Sources */ = {isa = PBXBuildFile; fileRef = D7F1D3721BF4DE07001A4B5E /* ARTRestPresence.m */; settings = {ASSET_TAGS = (); }; }; + D7F1D3771BF4DE72001A4B5E /* ARTRealtimePresence.h in Headers */ = {isa = PBXBuildFile; fileRef = D7F1D3751BF4DE72001A4B5E /* ARTRealtimePresence.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D7F1D3781BF4DE72001A4B5E /* ARTRealtimePresence.m in Sources */ = {isa = PBXBuildFile; fileRef = D7F1D3761BF4DE72001A4B5E /* ARTRealtimePresence.m */; settings = {ASSET_TAGS = (); }; }; + D7F1D37A1BF4E33A001A4B5E /* ARTRestChannel+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D7F1D3791BF4E33A001A4B5E /* ARTRestChannel+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; FC78549C1BCD5688539CCBE4 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FDA6E099E4BC04FC80F845C0 /* libPods.a */; }; /* End PBXBuildFile section */ @@ -314,6 +319,11 @@ D7D8F8281BC2C706009718F2 /* ARTAuthTokenRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTAuthTokenRequest.m; sourceTree = ""; }; D7D8F8291BC2C706009718F2 /* ARTAuthTokenParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTAuthTokenParams.h; sourceTree = ""; }; D7D8F82A1BC2C706009718F2 /* ARTAuthTokenParams.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTAuthTokenParams.m; sourceTree = ""; }; + D7F1D3711BF4DE07001A4B5E /* ARTRestPresence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRestPresence.h; sourceTree = ""; }; + D7F1D3721BF4DE07001A4B5E /* ARTRestPresence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRestPresence.m; sourceTree = ""; }; + D7F1D3751BF4DE72001A4B5E /* ARTRealtimePresence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRealtimePresence.h; sourceTree = ""; }; + D7F1D3761BF4DE72001A4B5E /* ARTRealtimePresence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRealtimePresence.m; sourceTree = ""; }; + D7F1D3791BF4E33A001A4B5E /* ARTRestChannel+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTRestChannel+Private.h"; sourceTree = ""; }; DF8DF755839D59574B7B795F /* Pods-ablySpec.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ablySpec.release.xcconfig"; path = "Pods/Target Support Files/Pods-ablySpec/Pods-ablySpec.release.xcconfig"; sourceTree = ""; }; FDA6E099E4BC04FC80F845C0 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -487,10 +497,13 @@ 960D07951A46FFC300ED8C8C /* ARTRest+Private.h */, 96BF61521A35B39C004CF2B3 /* ARTRest.m */, D70EAAEB1BC3376200CD8B9E /* ARTRestChannel.h */, + D7F1D3791BF4E33A001A4B5E /* ARTRestChannel+Private.h */, D70EAAEC1BC3376200CD8B9E /* ARTRestChannel.m */, 96BF616E1A35FB7C004CF2B3 /* ARTAuth.h */, D7C1B8781BBF5F460087B55F /* ARTAuth+Private.h */, 96BF616F1A35FB7C004CF2B3 /* ARTAuth.m */, + D7F1D3711BF4DE07001A4B5E /* ARTRestPresence.h */, + D7F1D3721BF4DE07001A4B5E /* ARTRestPresence.m */, ); name = REST; sourceTree = ""; @@ -504,6 +517,8 @@ D746AE3A1BBC5AE1003ECEF8 /* ARTRealtimeChannel.h */, D746AE421BBC5CD0003ECEF8 /* ARTRealtimeChannel+Private.h */, D746AE3B1BBC5AE1003ECEF8 /* ARTRealtimeChannel.m */, + D7F1D3751BF4DE72001A4B5E /* ARTRealtimePresence.h */, + D7F1D3761BF4DE72001A4B5E /* ARTRealtimePresence.m */, D746AE321BBC29EB003ECEF8 /* Transport */, D746AE3E1BBC5B14003ECEF8 /* ARTEventEmitter.h */, D746AE3F1BBC5B14003ECEF8 /* ARTEventEmitter.m */, @@ -511,10 +526,6 @@ D746AE461BBD6FE9003ECEF8 /* ARTQueuedMessage.m */, D746AE491BBD70F0003ECEF8 /* ARTRealtimeChannelSubscription.h */, D746AE4A1BBD70F0003ECEF8 /* ARTRealtimeChannelSubscription.m */, - D746AE261BBB61C9003ECEF8 /* ARTPresence.h */, - D746AE271BBB61C9003ECEF8 /* ARTPresence.m */, - 1C2B0FFB1B136A6D00E3633C /* ARTPresenceMap.h */, - 1C2B0FFC1B136A6D00E3633C /* ARTPresenceMap.m */, ); name = Realtime; sourceTree = ""; @@ -556,8 +567,12 @@ 96BF61631A35CDE1004CF2B3 /* ARTBaseMessage.m */, D746AE361BBC3201003ECEF8 /* ARTMessage.h */, D746AE371BBC3201003ECEF8 /* ARTMessage.m */, + D746AE261BBB61C9003ECEF8 /* ARTPresence.h */, + D746AE271BBB61C9003ECEF8 /* ARTPresence.m */, 96A5079F1A377AA50077CDF8 /* ARTPresenceMessage.h */, 96A507A01A377AA50077CDF8 /* ARTPresenceMessage.m */, + 1C2B0FFB1B136A6D00E3633C /* ARTPresenceMap.h */, + 1C2B0FFC1B136A6D00E3633C /* ARTPresenceMap.m */, 961343E61A432E7C006DC822 /* ARTPayload.h */, 1C8065041AE7C8FA00D49357 /* ARTPayload+Private.h */, 961343E71A432E7C006DC822 /* ARTPayload.m */, @@ -650,6 +665,7 @@ D746AE401BBC5B14003ECEF8 /* ARTEventEmitter.h in Headers */, D746AE531BBD85C5003ECEF8 /* ARTChannelCollection.h in Headers */, D7D8F82D1BC2C706009718F2 /* ARTAuthTokenParams.h in Headers */, + D7F1D3771BF4DE72001A4B5E /* ARTRealtimePresence.h in Headers */, 1C578E1F1B3435CA00EF46EC /* ARTFallback.h in Headers */, 96E408471A3895E800087F77 /* ARTWebSocketTransport.h in Headers */, 96E4083F1A3892C700087F77 /* ARTRealtimeTransport.h in Headers */, @@ -662,9 +678,11 @@ D746AE2F1BBBE7D7003ECEF8 /* ARTPaginatedResult+Private.h in Headers */, D746AE431BBC5CD0003ECEF8 /* ARTRealtimeChannel+Private.h in Headers */, D746AE251BBB611C003ECEF8 /* ARTChannel+Private.h in Headers */, + D7F1D3731BF4DE07001A4B5E /* ARTRestPresence.h in Headers */, 1C8065051AE7C8FA00D49357 /* ARTPayload+Private.h in Headers */, 960D07971A46FFC300ED8C8C /* ARTRest+Private.h in Headers */, 1C05CF201AC1D7EB00687AC9 /* ARTRealtime+Private.h in Headers */, + D7F1D37A1BF4E33A001A4B5E /* ARTRestChannel+Private.h in Headers */, 85B2C2191B6FE8DE00EA5254 /* CompatibilityMacros.h in Headers */, 961343E81A432E7C006DC822 /* ARTPayload.h in Headers */, 96A507A91A37806A0077CDF8 /* ARTEncoder.h in Headers */, @@ -913,6 +931,7 @@ D746AE481BBD6FE9003ECEF8 /* ARTQueuedMessage.m in Sources */, D746AE3D1BBC5AE1003ECEF8 /* ARTRealtimeChannel.m in Sources */, 96A507A21A377AA50077CDF8 /* ARTPresenceMessage.m in Sources */, + D7F1D3741BF4DE07001A4B5E /* ARTRestPresence.m in Sources */, D746AE541BBD85C5003ECEF8 /* ARTChannelCollection.m in Sources */, 96BF61541A35B39C004CF2B3 /* ARTRest.m in Sources */, D7D8F82C1BC2C706009718F2 /* ARTAuthTokenRequest.m in Sources */, @@ -938,6 +957,7 @@ 96BF61711A35FB7C004CF2B3 /* ARTAuth.m in Sources */, 96E408441A38939E00087F77 /* ARTProtocolMessage.m in Sources */, 96BF61651A35CDE1004CF2B3 /* ARTBaseMessage.m in Sources */, + D7F1D3781BF4DE72001A4B5E /* ARTRealtimePresence.m in Sources */, 1CD8DCA01B1C7315007EAF36 /* ARTDefault.m in Sources */, D746AE501BBD84E7003ECEF8 /* ARTChannelOptions.m in Sources */, 1C6C18A41ADFDAB100AB79E4 /* ARTLog.m in Sources */,