2015-03-23 20:28:42 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*/
|
2015-02-20 04:10:52 +00:00
|
|
|
|
|
|
|
#import "RCTDataManager.h"
|
|
|
|
|
|
|
|
#import "RCTAssert.h"
|
2015-04-10 03:18:31 +00:00
|
|
|
#import "RCTConvert.h"
|
2015-06-05 22:23:30 +00:00
|
|
|
#import "RCTEventDispatcher.h"
|
2015-02-20 04:10:52 +00:00
|
|
|
#import "RCTLog.h"
|
|
|
|
#import "RCTUtils.h"
|
|
|
|
|
2015-06-05 22:23:30 +00:00
|
|
|
@interface RCTDataManager () <NSURLSessionDataDelegate>
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2015-02-20 04:10:52 +00:00
|
|
|
@implementation RCTDataManager
|
2015-06-05 22:23:30 +00:00
|
|
|
{
|
|
|
|
NSURLSession *_session;
|
|
|
|
NSOperationQueue *_callbackQueue;
|
|
|
|
}
|
|
|
|
|
|
|
|
@synthesize bridge = _bridge;
|
2015-02-20 04:10:52 +00:00
|
|
|
|
2015-04-08 12:42:43 +00:00
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
|
2015-02-20 04:10:52 +00:00
|
|
|
/**
|
|
|
|
* Executes a network request.
|
|
|
|
* The responseSender block won't be called on same thread as called.
|
|
|
|
*/
|
2015-04-08 15:52:48 +00:00
|
|
|
RCT_EXPORT_METHOD(queryData:(NSString *)queryType
|
2015-04-10 03:18:31 +00:00
|
|
|
withQuery:(NSDictionary *)query
|
2015-06-05 22:23:30 +00:00
|
|
|
sendIncrementalUpdates:(BOOL)incrementalUpdates
|
2015-04-08 15:52:48 +00:00
|
|
|
responseSender:(RCTResponseSenderBlock)responseSender)
|
2015-02-20 04:10:52 +00:00
|
|
|
{
|
|
|
|
if ([queryType isEqualToString:@"http"]) {
|
2015-03-23 20:28:42 +00:00
|
|
|
|
2015-02-20 04:10:52 +00:00
|
|
|
// Build request
|
2015-04-10 03:18:31 +00:00
|
|
|
NSURL *URL = [RCTConvert NSURL:query[@"url"]];
|
|
|
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
|
|
|
|
request.HTTPMethod = [RCTConvert NSString:query[@"method"]] ?: @"GET";
|
|
|
|
request.allHTTPHeaderFields = [RCTConvert NSDictionary:query[@"headers"]];
|
2015-05-26 20:29:41 +00:00
|
|
|
request.HTTPBody = [RCTConvert NSData:query[@"data"]];
|
2015-02-20 04:10:52 +00:00
|
|
|
|
2015-06-05 22:23:30 +00:00
|
|
|
// Create session if one doesn't already exist
|
|
|
|
if (!_session) {
|
|
|
|
_callbackQueue = [[NSOperationQueue alloc] init];
|
|
|
|
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
|
|
|
_session = [NSURLSession sessionWithConfiguration:configuration
|
|
|
|
delegate:self
|
|
|
|
delegateQueue:_callbackQueue];
|
|
|
|
}
|
|
|
|
|
|
|
|
__block NSURLSessionDataTask *task;
|
|
|
|
if (incrementalUpdates) {
|
|
|
|
task = [_session dataTaskWithRequest:request];
|
|
|
|
} else {
|
|
|
|
task = [_session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
|
|
RCTSendResponseEvent(_bridge, task);
|
|
|
|
if (!error) {
|
|
|
|
RCTSendDataEvent(_bridge, task, data);
|
2015-02-20 04:10:52 +00:00
|
|
|
}
|
2015-06-05 22:23:30 +00:00
|
|
|
RCTSendCompletionEvent(_bridge, task, error);
|
|
|
|
}];
|
|
|
|
}
|
2015-03-23 20:28:42 +00:00
|
|
|
|
2015-06-05 22:23:30 +00:00
|
|
|
// Build data task
|
|
|
|
responseSender(@[@(task.taskIdentifier)]);
|
2015-02-20 04:10:52 +00:00
|
|
|
[task resume];
|
2015-05-26 20:29:41 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
RCTLogError(@"unsupported query type %@", queryType);
|
|
|
|
}
|
2015-02-20 04:10:52 +00:00
|
|
|
}
|
|
|
|
|
2015-06-05 22:23:30 +00:00
|
|
|
#pragma mark - URLSession delegate
|
|
|
|
|
|
|
|
- (void)URLSession:(NSURLSession *)session
|
|
|
|
dataTask:(NSURLSessionDataTask *)task
|
|
|
|
didReceiveResponse:(NSURLResponse *)response
|
|
|
|
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
|
|
|
|
{
|
|
|
|
RCTSendResponseEvent(_bridge, task);
|
|
|
|
completionHandler(NSURLSessionResponseAllow);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)URLSession:(NSURLSession *)session
|
|
|
|
dataTask:(NSURLSessionDataTask *)task
|
|
|
|
didReceiveData:(NSData *)data
|
|
|
|
{
|
|
|
|
RCTSendDataEvent(_bridge, task, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
|
|
|
|
{
|
|
|
|
RCTSendCompletionEvent(_bridge, task, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - Build responses
|
|
|
|
|
|
|
|
static void RCTSendResponseEvent(RCTBridge *bridge, NSURLSessionTask *task)
|
|
|
|
{
|
|
|
|
NSURLResponse *response = task.response;
|
|
|
|
NSHTTPURLResponse *httpResponse = nil;
|
|
|
|
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
|
|
|
// Might be a local file request
|
|
|
|
httpResponse = (NSHTTPURLResponse *)response;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSArray *responseJSON = @[@(task.taskIdentifier),
|
|
|
|
@(httpResponse.statusCode ?: 200),
|
|
|
|
httpResponse.allHeaderFields ?: @{},
|
|
|
|
];
|
|
|
|
|
|
|
|
[bridge.eventDispatcher sendDeviceEventWithName:@"didReceiveNetworkResponse"
|
|
|
|
body:responseJSON];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RCTSendDataEvent(RCTBridge *bridge, NSURLSessionDataTask *task, NSData *data)
|
|
|
|
{
|
|
|
|
// Get text encoding
|
|
|
|
NSURLResponse *response = task.response;
|
|
|
|
NSStringEncoding encoding = NSUTF8StringEncoding;
|
|
|
|
if (response.textEncodingName) {
|
|
|
|
CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
|
|
|
|
encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString *responseText = [[NSString alloc] initWithData:data encoding:encoding];
|
|
|
|
if (!responseText && data.length) {
|
|
|
|
RCTLogError(@"Received data was invalid.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSArray *responseJSON = @[@(task.taskIdentifier), responseText ?: @""];
|
|
|
|
[bridge.eventDispatcher sendDeviceEventWithName:@"didReceiveNetworkData"
|
|
|
|
body:responseJSON];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RCTSendCompletionEvent(RCTBridge *bridge, NSURLSessionTask *task, NSError *error)
|
|
|
|
{
|
|
|
|
NSArray *responseJSON = @[@(task.taskIdentifier),
|
|
|
|
error.localizedDescription ?: [NSNull null],
|
|
|
|
];
|
|
|
|
|
|
|
|
[bridge.eventDispatcher sendDeviceEventWithName:@"didCompleteNetworkResponse"
|
|
|
|
body:responseJSON];
|
|
|
|
}
|
|
|
|
|
2015-02-20 04:10:52 +00:00
|
|
|
@end
|