Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thread safety #586

Merged
merged 27 commits into from
Mar 23, 2017
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
04ba309
New EventEmitter (using NSNotificationCenter)
ricardopereira Mar 10, 2017
f344825
Events for the EventEmitter
ricardopereira Mar 10, 2017
4260a4c
Fix: should cancel timers when connection times out
ricardopereira Mar 10, 2017
6f4787a
Fix: new state change can occur before receiving publishing acknowled…
ricardopereira Mar 10, 2017
b38fa55
Test suite: async forced transitions
ricardopereira Mar 10, 2017
2cfc1b1
Test suite: ack order
ricardopereira Mar 10, 2017
fa43d00
Test suite: stop when there's no internet
ricardopereira Mar 10, 2017
1dc13f0
Fix: instance objects released to soon
ricardopereira Mar 10, 2017
44bf0fe
Performed a static analysis from Xcode
ricardopereira Mar 12, 2017
345f16d
fixup! Test suite: ack order
ricardopereira Mar 12, 2017
676c26b
Memory leak: call session invalidate to dispose of its strong referen…
ricardopereira Mar 12, 2017
8bdb646
fixup! Test suite: ack order
ricardopereira Mar 15, 2017
39d8b20
Fix RTN19a: guarantee of a new transport (check transport reference)
ricardopereira Mar 15, 2017
7fa81ec
Fix: ACK or NACK has not yet been received for a message, the client …
ricardopereira Mar 15, 2017
98c9a2f
Enhance RTN14b: better timings
ricardopereira Mar 15, 2017
388d6b2
Fix: REST and Realtime, wait for last operation to release the object
ricardopereira Mar 15, 2017
5de21e9
fixup! Test suite: ack order
ricardopereira Mar 16, 2017
17bca96
Fix: cancel timers when a connection gets closed
ricardopereira Mar 17, 2017
d533e20
fixup! Test suite: ack order
ricardopereira Mar 17, 2017
b68b806
Test suite: timings
ricardopereira Mar 17, 2017
e812cda
fixup! Enhance RTN14b: better timings
ricardopereira Mar 21, 2017
3f9558e
Test suite: close connections
ricardopereira Mar 22, 2017
8ad250f
Fix: turn off immediately reachability when close occurs
ricardopereira Mar 22, 2017
49efb8a
Fix RTC1d: wait for host is not reachable error
ricardopereira Mar 22, 2017
3501f43
fixup! Test suite: ack order
ricardopereira Mar 22, 2017
b0e5f94
Travis update
ricardopereira Mar 22, 2017
257454a
Fix RTN19a
ricardopereira Mar 23, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Examples/Tests/TestsTests/TestsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,19 @@ class TestsTests: XCTestCase {
self.waitForExpectationsWithTimeout(10, handler: nil)

let backgroundRealtimeExpectation = self.expectationWithDescription("Realtime in a Background Queue")
var realtime: ARTRealtime! //strong reference
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? We don't use the object outside. Is it because attach doesn't hold itself strong references to what it needs from its ARTRealtime? If so, why not? Maybe we should fix that instead, if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a look 👍

Copy link
Contributor Author

@ricardopereira ricardopereira Mar 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: 388d6b2

NSURLSession.sharedSession().dataTaskWithURL(NSURL(string:"https://ably.io")!) { _ in
let realtime = ARTRealtime(key: key as String)
realtime = ARTRealtime(key: key as String)
realtime.channels.get("foo").attach { _ in
defer { backgroundRealtimeExpectation.fulfill() }
}
}.resume()
self.waitForExpectationsWithTimeout(10, handler: nil)

let backgroundRestExpectation = self.expectationWithDescription("Rest in a Background Queue")
var rest: ARTRest! //strong reference
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string:"https://ably.io")!) { _ in
let rest = ARTRest(key: key as String)
rest = ARTRest(key: key as String)
rest.channels.get("foo").history { _ in
defer { backgroundRestExpectation.fulfill() }
}
Expand Down
11 changes: 9 additions & 2 deletions Source/ARTAuth+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ART_ASSUME_NONNULL_BEGIN

/// Messages related to the ARTAuth
@protocol ARTAuthDelegate <NSObject>
@property (nonatomic, readonly) __GENERIC(ARTEventEmitter, NSNumber * /*ARTAuthorizationState*/, id) *authorizationEmitter;
@property (nonatomic, readonly) ARTEventEmitter<ARTEvent *, id> *authorizationEmitter;
- (void)auth:(ARTAuth *)auth didAuthorize:(ARTTokenDetails *)tokenDetails;
@end

Expand All @@ -42,7 +42,7 @@ ART_ASSUME_NONNULL_BEGIN
- (ARTTokenParams *)mergeParams:(ARTTokenParams *)customParams;

- (NSURL *)buildURL:(ARTAuthOptions *)options withParams:(ARTTokenParams *)params;
- (NSMutableURLRequest *)buildRequest:(ARTAuthOptions *)options withParams:(ARTTokenParams *)params;
- (NSMutableURLRequest *)buildRequest:(nullable ARTAuthOptions *)options withParams:(nullable ARTTokenParams *)params;

// Execute the received ARTTokenRequest
- (void)executeTokenRequest:(ARTTokenRequest *)tokenRequest callback:(void (^)(ARTTokenDetails *__art_nullable tokenDetails, NSError *__art_nullable error))callback;
Expand Down Expand Up @@ -70,4 +70,11 @@ ART_ASSUME_NONNULL_BEGIN

@end

#pragma mark - ARTEvent

@interface ARTEvent (AuthorizationState)
- (instancetype)initWithAuthorizationState:(ARTAuthorizationState)value;
+ (instancetype)newWithAuthorizationState:(ARTAuthorizationState)value;
@end

ART_ASSUME_NONNULL_END
32 changes: 29 additions & 3 deletions Source/ARTAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,11 @@ - (void)authorize:(ARTTokenParams *)tokenParams options:(ARTAuthOptions *)authOp
if (lastDelegate) {
// Only the last request should remain
[lastDelegate.authorizationEmitter off];
[lastDelegate.authorizationEmitter once:[NSNumber numberWithInt:ARTAuthorizationSucceeded] callback:^(id null) {
[lastDelegate.authorizationEmitter once:[ARTEvent newWithAuthorizationState:ARTAuthorizationSucceeded] callback:^(id null) {
successBlock(_tokenDetails);
[lastDelegate.authorizationEmitter off];
}];
[lastDelegate.authorizationEmitter once:[NSNumber numberWithInt:ARTAuthorizationFailed] callback:^(NSError *error) {
[lastDelegate.authorizationEmitter once:[ARTEvent newWithAuthorizationState:ARTAuthorizationFailed] callback:^(NSError *error) {
failureBlock(error);
[lastDelegate.authorizationEmitter off];
}];
Expand All @@ -402,7 +402,10 @@ - (void)authorize:(ARTTokenParams *)tokenParams options:(ARTAuthOptions *)authOp
_tokenDetails = tokenDetails;
_method = ARTAuthMethodToken;

if (lastDelegate) {
if (!tokenDetails) {
failureBlock([ARTErrorInfo createWithCode:0 message:@"Token details are empty"]);
}
else if (lastDelegate) {
[lastDelegate auth:self didAuthorize:tokenDetails];
}
else {
Expand Down Expand Up @@ -506,3 +509,26 @@ - (void)toTokenDetails:(ARTAuth *)auth callback:(void (^)(ARTTokenDetails * _Nul
}

@end

NSString *ARTAuthorizationStateToStr(ARTAuthorizationState state) {
switch (state) {
case ARTAuthorizationSucceeded:
return @"Succeeded"; //0
case ARTAuthorizationFailed:
return @"Failed"; //1
}
}

#pragma mark - ARTEvent

@implementation ARTEvent (AuthorizationState)

- (instancetype)initWithAuthorizationState:(ARTAuthorizationState)value {
return [self initWithString:[NSString stringWithFormat:@"ARTAuthorizationState%@", ARTAuthorizationStateToStr(value)]];
}

+ (instancetype)newWithAuthorizationState:(ARTAuthorizationState)value {
return [[self alloc] initWithAuthorizationState:value];
}

@end
2 changes: 1 addition & 1 deletion Source/ARTChannels+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extern NSString* (^__art_nullable ARTChannels_getChannelNamePrefix)();

@protocol ARTChannelsDelegate <NSObject>

- (id)makeChannel:(NSString *)channel options:(ARTChannelOptions *)options;
- (id)makeChannel:(NSString *)channel options:(nullable ARTChannelOptions *)options;

@end

Expand Down
2 changes: 1 addition & 1 deletion Source/ARTConnection+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ ART_ASSUME_NONNULL_BEGIN

@interface ARTConnection ()

@property (readonly, strong, nonatomic) __GENERIC(ARTEventEmitter, NSNumber *, ARTConnectionStateChange *) *eventEmitter;
@property (readonly, strong, nonatomic) ARTEventEmitter<ARTEvent *, ARTConnectionStateChange *> *eventEmitter;
@property(weak, nonatomic) ARTRealtime* realtime;

@end
Expand Down
7 changes: 7 additions & 0 deletions Source/ARTConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,11 @@ ART_EMBED_INTERFACE_EVENT_EMITTER(ARTRealtimeConnectionEvent, ARTConnectionState

@end

#pragma mark - ARTEvent

@interface ARTEvent (ConnectionEvent)
- (instancetype)initWithConnectionEvent:(ARTRealtimeConnectionEvent)value;
+ (instancetype)newWithConnectionEvent:(ARTRealtimeConnectionEvent)value;
@end

ART_ASSUME_NONNULL_END
36 changes: 23 additions & 13 deletions Source/ARTConnection.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ @implementation ARTConnection {
}

- (instancetype)initWithRealtime:(ARTRealtime *)realtime {
if (self == [super init]) {
if (self = [super init]) {
_queue = dispatch_queue_create("io.ably.realtime.connection", DISPATCH_QUEUE_SERIAL);
_eventEmitter = [[ARTEventEmitter alloc] initWithQueue:_queue];
_realtime = realtime;
Expand Down Expand Up @@ -78,39 +78,49 @@ - (NSString *)getRecoveryKey {
}
}

- (__GENERIC(ARTEventListener, ARTConnectionStateChange *) *)on:(ARTRealtimeConnectionEvent)event callback:(void (^)(ARTConnectionStateChange *))cb {
return [_eventEmitter on:[NSNumber numberWithInt:event] callback:cb];
- (ARTEventListener *)on:(ARTRealtimeConnectionEvent)event callback:(void (^)(ARTConnectionStateChange *))cb {
return [_eventEmitter on:[ARTEvent newWithConnectionEvent:event] callback:cb];
}

- (__GENERIC(ARTEventListener, ARTConnectionStateChange *) *)on:(void (^)(ARTConnectionStateChange *))cb {
- (ARTEventListener *)on:(void (^)(ARTConnectionStateChange *))cb {
return [_eventEmitter on:cb];
}

- (__GENERIC(ARTEventListener, ARTConnectionStateChange *) *)once:(ARTRealtimeConnectionEvent)event callback:(void (^)(ARTConnectionStateChange *))cb {
return [_eventEmitter once:[NSNumber numberWithInt:event] callback:cb];
- (ARTEventListener *)once:(ARTRealtimeConnectionEvent)event callback:(void (^)(ARTConnectionStateChange *))cb {
return [_eventEmitter once:[ARTEvent newWithConnectionEvent:event] callback:cb];
}

- (__GENERIC(ARTEventListener, ARTConnectionStateChange *) *)once:(void (^)(ARTConnectionStateChange *))cb {
- (ARTEventListener *)once:(void (^)(ARTConnectionStateChange *))cb {
return [_eventEmitter once:cb];
}

- (void)off {
[_eventEmitter off];
}
- (void)off:(ARTRealtimeConnectionEvent)event listener:listener {
[_eventEmitter off:[NSNumber numberWithInt:event] listener:listener];
- (void)off:(ARTRealtimeConnectionEvent)event listener:(ARTEventListener *)listener {
[_eventEmitter off:[ARTEvent newWithConnectionEvent:event] listener:listener];
}

- (void)off:(__GENERIC(ARTEventListener, ARTConnectionStateChange *) *)listener {
- (void)off:(ARTEventListener *)listener {
[_eventEmitter off:listener];
}

- (void)emit:(ARTRealtimeConnectionEvent)event with:(ARTConnectionStateChange *)data {
[_eventEmitter emit:[NSNumber numberWithInt:event] with:data];
[_eventEmitter emit:[ARTEvent newWithConnectionEvent:event] with:data];
}

- (ARTEventListener *)timed:(ARTEventListener *)listener deadline:(NSTimeInterval)deadline onTimeout:(void (^)())onTimeout {
return [_eventEmitter timed:listener deadline:deadline onTimeout:onTimeout];
@end

#pragma mark - ARTEvent

@implementation ARTEvent (ConnectionEvent)

- (instancetype)initWithConnectionEvent:(ARTRealtimeConnectionEvent)value {
return [self initWithString:[NSString stringWithFormat:@"ARTRealtimeConnectionEvent%@", ARTRealtimeConnectionEventToStr(value)]];
}

+ (instancetype)newWithConnectionEvent:(ARTRealtimeConnectionEvent)value {
return [[self alloc] initWithConnectionEvent:value];
}

@end
2 changes: 1 addition & 1 deletion Source/ARTConnectionDetails.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ - (instancetype)initWithClientId:(NSString *__art_nullable)clientId
maxInboundRate:(NSInteger)maxInboundRate
connectionStateTtl:(NSTimeInterval)connectionStateTtl
serverId:(NSString *)serverId {
if (self == [super init]) {
if (self = [super init]) {
_clientId = clientId;
_connectionKey = connectionKey;
_maxMessageSize = maxMessageSize;
Expand Down
2 changes: 1 addition & 1 deletion Source/ARTCrypto+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ ART_ASSUME_NONNULL_BEGIN
+ (int)defaultKeyLength;
+ (int)defaultBlockLength;

+ (NSData *)generateSecureRandomData:(size_t)length;
+ (nullable NSData *)generateSecureRandomData:(size_t)length;

+ (id<ARTChannelCipher>)cipherWithParams:(ARTCipherParams *)params;

Expand Down
2 changes: 1 addition & 1 deletion Source/ARTDataEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ ART_ASSUME_NONNULL_BEGIN

+ (NSString *)artAddEncoding:(NSString *)encoding toString:(NSString *__art_nullable)s;
- (NSString *)artLastEncoding;
- (NSString *)artRemoveLastEncoding;
- (nullable NSString *)artRemoveLastEncoding;

@end

Expand Down
20 changes: 7 additions & 13 deletions Source/ARTEventEmitter+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,18 @@
//

#include "ARTEventEmitter.h"
#include "CompatibilityMacros.h"

ART_ASSUME_NONNULL_BEGIN
NS_ASSUME_NONNULL_BEGIN

@interface __GENERIC(ARTEventEmitterEntry, ItemType) : NSObject
@interface ARTEventEmitter<EventType, ItemType> ()

@property (readwrite, strong, nonatomic) __GENERIC(ARTEventListener, ItemType) *listener;
@property (readwrite, nonatomic) BOOL once;
@property (nonatomic, readonly) NSNotificationCenter *notificationCenter;
@property (nonatomic, readonly) dispatch_queue_t queue;

- (instancetype)initWithListener:(__GENERIC(ARTEventListener, ItemType) *)listener once:(BOOL)once;
@property (readonly, atomic) NSMutableDictionary<NSString *, NSMutableArray<ARTEventListener *> *> *listeners;
@property (readonly, atomic) NSMutableArray<ARTEventListener *> *anyListeners;

@end

@interface __GENERIC(ARTEventEmitter, EventType, ItemType) ()
NS_ASSUME_NONNULL_END

@property (readwrite, atomic) __GENERIC(NSMutableDictionary, EventType, __GENERIC(NSMutableArray, __GENERIC(ARTEventEmitterEntry, ItemType) *) *) *listeners;
@property (readwrite, atomic) __GENERIC(NSMutableArray, __GENERIC(ARTEventEmitterEntry, ItemType) *) *anyListeners;

@end

ART_ASSUME_NONNULL_END
Loading