Skip to content

Added NSNotifications being posted on every network request being sent/finished. #82

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

Merged
merged 2 commits into from
Aug 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 24 additions & 0 deletions Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,27 @@ extern NSString *const PFCommandHeaderNameSessionToken;
///--------------------------------------

extern NSString *const PFCommandParameterNameMethodOverride;

///--------------------------------------
/// @name Notifications
///--------------------------------------

/*!
@abstract The name of the notification that is going to be sent before any URL request is sent.
*/
extern NSString *const PFCommandRunnerWillSendURLRequestNotification;

/*!
@abstract The name of the notification that is going to be sent after any URL response is received.
*/
extern NSString *const PFCommandRunnerDidReceiveURLResponseNotification;

/*!
@abstract The key of request(NSURLRequest) in the userInfo dictionary of a notification.
*/
extern NSString *const PFCommandRunnerNotificationURLRequestUserInfoKey;

/*!
@abstract The key of response(NSHTTPURLResponse) in the userInfo dictionary of a notification.
*/
extern NSString *const PFCommandRunnerNotificationURLResponseUserInfoKey;
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,12 @@
NSString *const PFCommandHeaderNameSessionToken = @"X-Parse-Session-Token";

NSString *const PFCommandParameterNameMethodOverride = @"_method";

///--------------------------------------
#pragma mark - Notifications
///--------------------------------------

NSString *const PFCommandRunnerWillSendURLRequestNotification = @"PFCommandRunnerWillSendURLRequestNotification";
NSString *const PFCommandRunnerDidReceiveURLResponseNotification = @"PFCommandRunnerDidReceiveURLResponseNotification";
NSString *const PFCommandRunnerNotificationURLRequestUserInfoKey = @"PFCommandRunnerNotificationURLRequestUserInfoKey";
NSString *const PFCommandRunnerNotificationURLResponseUserInfoKey = @"PFCommandRunnerNotificationURLResponseUserInfoKey";
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
#import "PFURLConstructor.h"
#import "PFURLSession.h"

@interface PFURLSessionCommandRunner () <PFURLSessionDelegate>

@property (nonatomic, strong) NSNotificationCenter *notificationCenter;

@end

@implementation PFURLSessionCommandRunner

@synthesize applicationId = _applicationId;
Expand All @@ -49,11 +55,12 @@ - (instancetype)initWithDataSource:(id<PFInstallationIdentifierStoreProvider>)da
clientKey:(NSString *)clientKey {
NSURLSessionConfiguration *configuration = [[self class] _urlSessionConfigurationForApplicationId:applicationId
clientKey:clientKey];
PFURLSession *session = [PFURLSession sessionWithConfiguration:configuration];
PFURLSession *session = [PFURLSession sessionWithConfiguration:configuration delegate:self];
Copy link
Contributor

Choose a reason for hiding this comment

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

This is bad. Self may be re-assigned by init, and then we have a dead delegate value. We should think about how to improve this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, the possibility of that happening is really really close to 0, so better testability (with injected everything) vs rare edge case scenario.

PFCommandURLRequestConstructor *constructor = [PFCommandURLRequestConstructor constructorWithDataSource:dataSource];
self = [self initWithDataSource:dataSource
session:session
requestConstructor:constructor];
requestConstructor:constructor
notificationCenter:[NSNotificationCenter defaultCenter]];
if (!self) return nil;

_applicationId = [applicationId copy];
Expand All @@ -64,14 +71,16 @@ - (instancetype)initWithDataSource:(id<PFInstallationIdentifierStoreProvider>)da

- (instancetype)initWithDataSource:(id<PFInstallationIdentifierStoreProvider>)dataSource
session:(PFURLSession *)session
requestConstructor:(PFCommandURLRequestConstructor *)requestConstructor {
requestConstructor:(PFCommandURLRequestConstructor *)requestConstructor
notificationCenter:(NSNotificationCenter *)notificationCenter {
self = [super init];
if (!self) return nil;

_initialRetryDelay = PFCommandRunningDefaultRetryDelay;

_requestConstructor = requestConstructor;
_session = session;
_notificationCenter = notificationCenter;

return self;
}
Expand Down Expand Up @@ -237,4 +246,30 @@ + (NSURLSessionConfiguration *)_urlSessionConfigurationForApplicationId:(NSStrin
return configuration;
}

///--------------------------------------
#pragma mark - PFURLSessionDelegate
///--------------------------------------

- (void)urlSession:(PFURLSession *)session willPerformURLRequest:(NSURLRequest *)request {
[[BFExecutor defaultPriorityBackgroundExecutor] execute:^{
NSDictionary *userInfo = @{ PFCommandRunnerNotificationURLRequestUserInfoKey : request };
[self.notificationCenter postNotificationName:PFCommandRunnerWillSendURLRequestNotification
object:self
userInfo:userInfo];
}];
}

- (void)urlSession:(PFURLSession *)session didPerformURLRequest:(NSURLRequest *)request withURLResponse:(nullable NSURLResponse *)response {
[[BFExecutor defaultPriorityBackgroundExecutor] execute:^{
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[PFCommandRunnerNotificationURLRequestUserInfoKey] = request;
if (response) {
userInfo[PFCommandRunnerNotificationURLResponseUserInfoKey] = response;
}
[self.notificationCenter postNotificationName:PFCommandRunnerDidReceiveURLResponseNotification
object:self
userInfo:userInfo];
}];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ NS_ASSUME_NONNULL_BEGIN

- (instancetype)initWithDataSource:(id<PFInstallationIdentifierStoreProvider>)dataSource
session:(PFURLSession *)session
requestConstructor:(PFCommandURLRequestConstructor *)requestConstructor NS_DESIGNATED_INITIALIZER;
requestConstructor:(PFCommandURLRequestConstructor *)requestConstructor
notificationCenter:(NSNotificationCenter *)notificationCenter NS_DESIGNATED_INITIALIZER;

@end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,29 @@

NS_ASSUME_NONNULL_BEGIN

@class PFURLSession;

@protocol PFURLSessionDelegate <NSObject>

- (void)urlSession:(PFURLSession *)session willPerformURLRequest:(NSURLRequest *)request;
- (void)urlSession:(PFURLSession *)session didPerformURLRequest:(NSURLRequest *)request withURLResponse:(nullable NSURLResponse *)response;
Copy link
Contributor

Choose a reason for hiding this comment

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

If we fail below the protocol level (e.g. user switches wifi off), this will be called without a URL Response, and no way to get the error out. Thoughts on having a way to get the underlying network error if one exists here?

There's also no good way to track cancelled requests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For this specific case - we don't really care about the result/error/cancellation, only about when the request is about to be sent and when request succeeded.
We don't really need an error right now, or a result, or cancelled status - that's why these are not implemented.

We can expand from here though at any given point of time.


@end

@interface PFURLSession : NSObject

@property (nonatomic, weak, readonly) id<PFURLSessionDelegate> delegate;

///--------------------------------------
/// @name Init
///--------------------------------------

- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithConfiguration:(NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
+ (instancetype)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
- (instancetype)initWithConfiguration:(NSURLSessionConfiguration *)configuration
delegate:(id<PFURLSessionDelegate>)delegate NS_DESIGNATED_INITIALIZER;

+ (instancetype)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
delegate:(id<PFURLSessionDelegate>)delegate;

///--------------------------------------
/// @name Teardown
Expand All @@ -52,7 +66,6 @@ NS_ASSUME_NONNULL_BEGIN
withCancellationToken:(nullable BFCancellationToken *)cancellationToken
progressBlock:(nullable PFProgressBlock)progressBlock;


@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,21 @@ - (instancetype)init {
PFNotDesignatedInitializer();
}

- (instancetype)initWithConfiguration:(NSURLSessionConfiguration *)configuration {
- (instancetype)initWithConfiguration:(NSURLSessionConfiguration *)configuration
delegate:(id<PFURLSessionDelegate>)delegate {
// NOTE: cast to id suppresses warning about designated initializer.
return [(id)self initWithURLSession:[NSURLSession sessionWithConfiguration:configuration
delegate:self
delegateQueue:nil]];
delegateQueue:nil]
delegate:delegate];
}

- (instancetype)initWithURLSession:(NSURLSession *)session {
- (instancetype)initWithURLSession:(NSURLSession *)session
delegate:(id<PFURLSessionDelegate>)delegate {
self = [super init];
if (!self) return nil;

_delegate = delegate;
_urlSession = session;

_sessionTaskQueue = dispatch_queue_create("com.parse.urlSession.tasks", DISPATCH_QUEUE_SERIAL);
Expand All @@ -62,12 +66,14 @@ - (instancetype)initWithURLSession:(NSURLSession *)session {
return self;
}

+ (instancetype)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration {
return [[self alloc] initWithConfiguration:configuration];
+ (instancetype)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
delegate:(id<PFURLSessionDelegate>)delegate {
return [[self alloc] initWithConfiguration:configuration delegate:delegate];
}

+ (instancetype)sessionWithURLSession:(nonnull NSURLSession *)session {
return [[self alloc] initWithURLSession:session];
+ (instancetype)sessionWithURLSession:(nonnull NSURLSession *)session
delegate:(id<PFURLSessionDelegate>)delegate {
return [[self alloc] initWithURLSession:session delegate:delegate];
}

///--------------------------------------
Expand Down Expand Up @@ -161,6 +167,8 @@ - (BFTask *)performFileDownloadURLRequestAsync:(NSURLRequest *)request
}

- (BFTask *)_performDataTask:(NSURLSessionDataTask *)dataTask withDelegate:(PFURLSessionDataTaskDelegate *)delegate {
[self.delegate urlSession:self willPerformURLRequest:dataTask.originalRequest];

@weakify(self);
return [BFTask taskFromExecutor:[BFExecutor defaultExecutor] withBlock:^id{
@strongify(self);
Expand All @@ -169,6 +177,8 @@ - (BFTask *)_performDataTask:(NSURLSessionDataTask *)dataTask withDelegate:(PFUR

BFTask *resultTask = [delegate.resultTask continueWithBlock:^id(BFTask *task) {
@strongify(self);
[self.delegate urlSession:self didPerformURLRequest:dataTask.originalRequest withURLResponse:delegate.response];

[self _removeDelegateForTaskWithIdentifier:taskIdentifier];
return task;
}];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ NS_ASSUME_NONNULL_BEGIN

@interface PFURLSession ()

- (instancetype)initWithURLSession:(NSURLSession *)session NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithURLSession:(NSURLSession *)session
delegate:(id<PFURLSessionDelegate>)delegate NS_DESIGNATED_INITIALIZER;

+ (instancetype)sessionWithURLSession:(NSURLSession *)session;
+ (instancetype)sessionWithURLSession:(NSURLSession *)session
delegate:(id<PFURLSessionDelegate>)delegate;

@end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, readonly) NSURLSessionDataTask *dataTask;
@property (nonatomic, strong, readonly) BFTask *resultTask;

@property (nonatomic, strong, readonly) NSHTTPURLResponse *response;

- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initForDataTask:(NSURLSessionDataTask *)dataTask
withCancellationToken:(nullable BFCancellationToken *)cancellationToken NS_DESIGNATED_INITIALIZER;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

@property (nonatomic, strong, readonly) dispatch_queue_t dataQueue;

@property (nonatomic, strong, readonly) NSHTTPURLResponse *response;

/*!
@abstract Defaults to to-memory output stream if not overwritten.
*/
Expand Down
20 changes: 15 additions & 5 deletions Tests/Unit/URLSessionCommandRunnerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ - (void)testRunCommand {
id mockedDataSource = PFStrictProtocolMock(@protocol(PFInstallationIdentifierStoreProvider));
id mockedSession = PFStrictClassMock([PFURLSession class]);
id mockedRequestConstructor = PFStrictClassMock([PFCommandURLRequestConstructor class]);
id mockedNotificationCenter = PFStrictClassMock([NSNotificationCenter class]);

id mockedCommand = PFStrictClassMock([PFRESTCommand class]);
id mockedCommandResult = PFStrictClassMock([PFCommandResult class]);
Expand All @@ -71,7 +72,8 @@ - (void)testRunCommand {

PFURLSessionCommandRunner *commandRunner = [[PFURLSessionCommandRunner alloc] initWithDataSource:mockedDataSource
session:mockedSession
requestConstructor:mockedRequestConstructor];
requestConstructor:mockedRequestConstructor
notificationCenter:mockedNotificationCenter];

XCTestExpectation *expecatation = [self currentSelectorTestExpectation];
[[commandRunner runCommandAsync:mockedCommand withOptions:0] continueWithBlock:^id(BFTask *task) {
Expand All @@ -89,14 +91,16 @@ - (void)testRunCommandCancel {
id mockedDataSource = PFStrictProtocolMock(@protocol(PFInstallationIdentifierStoreProvider));
id mockedSession = PFStrictClassMock([PFURLSession class]);
id mockedRequestConstructor = PFStrictClassMock([PFCommandURLRequestConstructor class]);
id mockedNotificationCenter = PFStrictClassMock([NSNotificationCenter class]);

id mockedCommand = PFStrictClassMock([PFRESTCommand class]);

OCMStub([mockedSession invalidateAndCancel]);

PFURLSessionCommandRunner *commandRunner = [[PFURLSessionCommandRunner alloc] initWithDataSource:mockedDataSource
session:mockedSession
requestConstructor:mockedRequestConstructor];
requestConstructor:mockedRequestConstructor
notificationCenter:mockedNotificationCenter];

BFCancellationTokenSource *cancellationToken = [BFCancellationTokenSource cancellationTokenSource];
[cancellationToken cancel];
Expand All @@ -117,6 +121,7 @@ - (void)testRunCommandRetry {
id mockedDataSource = PFStrictProtocolMock(@protocol(PFInstallationIdentifierStoreProvider));
id mockedSession = PFStrictClassMock([PFURLSession class]);
id mockedRequestConstructor = PFStrictClassMock([PFCommandURLRequestConstructor class]);
id mockedNotificationCenter = PFStrictClassMock([NSNotificationCenter class]);

id mockedCommand = PFStrictClassMock([PFRESTCommand class]);

Expand All @@ -140,7 +145,8 @@ - (void)testRunCommandRetry {

PFURLSessionCommandRunner *commandRunner = [[PFURLSessionCommandRunner alloc] initWithDataSource:mockedDataSource
session:mockedSession
requestConstructor:mockedRequestConstructor];
requestConstructor:mockedRequestConstructor
notificationCenter:mockedNotificationCenter];
commandRunner.initialRetryDelay = DBL_MIN; // Lets not needlessly sleep here.

XCTestExpectation *expecatation = [self currentSelectorTestExpectation];
Expand All @@ -162,6 +168,7 @@ - (void)testRunFileUpload {
id mockedDataSource = PFStrictProtocolMock(@protocol(PFInstallationIdentifierStoreProvider));
id mockedSession = PFStrictClassMock([PFURLSession class]);
id mockedRequestConstructor = PFStrictClassMock([PFCommandURLRequestConstructor class]);
id mockedNotificationCenter = PFStrictClassMock([NSNotificationCenter class]);

id mockedCommand = PFStrictClassMock([PFRESTCommand class]);
id mockedCommandResult = PFStrictClassMock([PFCommandResult class]);
Expand Down Expand Up @@ -191,7 +198,8 @@ - (void)testRunFileUpload {

PFURLSessionCommandRunner *commandRunner = [[PFURLSessionCommandRunner alloc] initWithDataSource:mockedDataSource
session:mockedSession
requestConstructor:mockedRequestConstructor];
requestConstructor:mockedRequestConstructor
notificationCenter:mockedNotificationCenter];

XCTestExpectation *expecatation = [self currentSelectorTestExpectation];
[[commandRunner runFileUploadCommandAsync:mockedCommand
Expand All @@ -213,6 +221,7 @@ - (void)testLocalIdResolution {
id mockedDataSource = PFStrictProtocolMock(@protocol(PFInstallationIdentifierStoreProvider));
id mockedSession = PFStrictClassMock([PFURLSession class]);
id mockedRequestConstructor = PFStrictClassMock([PFCommandURLRequestConstructor class]);
id mockedNotificationCenter = PFStrictClassMock([NSNotificationCenter class]);

id mockedCommand = PFStrictClassMock([PFRESTCommand class]);
id mockedCommandResult = PFStrictClassMock([PFCommandResult class]);
Expand All @@ -230,7 +239,8 @@ - (void)testLocalIdResolution {

PFURLSessionCommandRunner *commandRunner = [[PFURLSessionCommandRunner alloc] initWithDataSource:mockedDataSource
session:mockedSession
requestConstructor:mockedRequestConstructor];
requestConstructor:mockedRequestConstructor
notificationCenter:mockedNotificationCenter];

XCTestExpectation *expecatation = [self currentSelectorTestExpectation];
[[commandRunner runCommandAsync:mockedCommand withOptions:0] continueWithBlock:^id(BFTask *task) {
Expand Down
Loading