2
0
Эх сурвалжийг харах

Merge pull request #61 from zmeyc/pr_cocoahttprequest

Cocoa HttpRequestTask improvements
Denis Muratshin 9 жил өмнө
parent
commit
8478e37d17

+ 6 - 1
oxygine/src/HttpRequestTask.cpp

@@ -12,7 +12,7 @@ namespace oxygine
     void HttpRequestTask::init() {}
     void HttpRequestTask::release() {}
 #endif
-    HttpRequestTask::HttpRequestTask() : _loaded(0)
+    HttpRequestTask::HttpRequestTask() : _loaded(0), _cacheEnabled(true)
     {
 
     }
@@ -39,6 +39,11 @@ namespace oxygine
         _setFileName(name);
     }
 
+	void HttpRequestTask::setCacheEnabled(bool enabled)
+	{
+		_cacheEnabled = enabled;
+		_setCacheEnabled(enabled);
+	}
 
     const std::vector<unsigned char>&   HttpRequestTask::getPostData() const
     {

+ 4 - 0
oxygine/src/HttpRequestTask.h

@@ -40,6 +40,7 @@ namespace oxygine
         const std::vector<unsigned char>&   getResponse() const;
         const std::vector<unsigned char>&   getPostData() const;
         const std::string&                  getFileName() const;
+		bool                                getCacheEnabled() const;
 
         /**swap version of getResponse if you want to modify result buffer inplace*/
         void getResponseSwap(std::vector<unsigned char>&);
@@ -47,6 +48,7 @@ namespace oxygine
         void setPostData(const std::vector<unsigned char>& data);
         void setUrl(const std::string& url);
         void setFileName(const std::string& name);
+		void setCacheEnabled(bool enabled);
 
 
     protected:
@@ -62,10 +64,12 @@ namespace oxygine
         virtual void _setFileName(const std::string& name) {}
         virtual void _setUrl(const std::string& url) {}
         virtual void _setPostData(const std::vector<unsigned char>& data) {}
+		virtual void _setCacheEnabled(bool enabled) {}
 
         int _loaded;
         std::string _url;
         std::string _fname;
+		bool _cacheEnabled;
         std::vector<unsigned char> _response;
         std::vector<unsigned char> _postData;
 

+ 1 - 1
oxygine/src/core/ios/HttpRequestCocoaTask.h

@@ -16,7 +16,7 @@ namespace oxygine
         HttpRequestCocoaTask();
         ~HttpRequestCocoaTask();
 
-        void complete_(NSData*);
+		void complete_(NSData *data, bool error);
         void progress_(int loaded, int total);
 
     protected:

+ 122 - 85
oxygine/src/core/ios/HttpRequestCocoaTask.mm

@@ -5,54 +5,27 @@
 #include "STDFileSystem.h"
 #include "core/log.h"
 using namespace oxygine;
-static char key;
+static char taskKey;
 
-@interface ObjectHolder:NSObject
+@interface HttpRequests:NSObject<NSURLSessionDownloadDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
 {
-    void* object;
-}
-
-@property(nonatomic, readwrite) void* object; // Property
-@end
-@implementation ObjectHolder
-@synthesize object;
--(instancetype)initWithObject: (void*) obj
-{
-    object = obj;
-    return self;
-}
-@end
-
-@interface HttpRequests:NSObject<NSURLSessionDownloadDelegate, NSURLSessionDataDelegate>
-{
-	NSURLSession *_session;
 }
 @end
 
 @implementation HttpRequests
--(id)init {
-    self = [super init];
-    
-    NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration ephemeralSessionConfiguration];
-    
-    sessionConfig.allowsCellularAccess = YES;
-    sessionConfig.timeoutIntervalForRequest = 30.0;
-    sessionConfig.timeoutIntervalForResource = 60.0;
-    sessionConfig.HTTPMaximumConnectionsPerHost = 10;
-    sessionConfig.URLCache = nil;
-    sessionConfig.URLCredentialStorage = nil;
-    sessionConfig.HTTPCookieStorage = nil;
 
-    
-    _session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
+- (id)init
+{
+    if (!(self = [super init]))
+		return nil;
     
     return self;
 }
 
 -(oxygine::HttpRequestCocoaTask*) getTask:(NSObject*)object remove:(BOOL)remove
 {
-    ObjectHolder *holder = objc_getAssociatedObject(object, &key);
-    oxygine::HttpRequestCocoaTask* task = (oxygine::HttpRequestCocoaTask*)([holder object]);
+    NSValue *taskValue = objc_getAssociatedObject(object, &taskKey);
+    oxygine::HttpRequestCocoaTask* task = (oxygine::HttpRequestCocoaTask*)taskValue.pointerValue;
     if (remove)
         objc_removeAssociatedObjects(object);
     if (!task)
@@ -60,6 +33,8 @@ static char key;
     return task;
 }
 
+#pragma mark - NSURLSessionDownloadDelegate
+
 -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
 {
     oxygine::HttpRequestCocoaTask* task = [self getTask:downloadTask remove:false];
@@ -80,38 +55,103 @@ static char key;
     NSError *fileManagerError;
     
     [fileManager removeItemAtURL:destUrl error:NULL];
-    //ключевая  строчка!
+    //key line!
     [fileManager copyItemAtURL:location toURL:destUrl error:&fileManagerError];
-    task->complete_(nil);
+    task->complete_(/* data */ nil, /* error */ false);
 }
 
-- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask  didReceiveData:(NSData *)data{
-    oxygine::HttpRequestCocoaTask* task = [self getTask:dataTask remove:true];
-    log::messageln("nssessiond complete %x", dataTask);
-    //if (!task)
-    //    return;
-    task->complete_(data);
+#pragma mark - NSURLSessionTaskDelegate
+
+- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
+{
+	if (!error) {
+		// didFinishDownloadingToURL will be called in this case,
+		// which will save the file and signal completion.
+	} else {
+	    oxygine::HttpRequestCocoaTask* httpRequestTask = [self getTask:task remove:true];
+		httpRequestTask->complete_(/* data */ nil, /* error */ true);
+	}
 }
 
+
+#pragma mark - NSURLSessionDataDelegate
+
+// Not used yet (using completion handler for data tasks)
+//- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask  didReceiveData:(NSData *)data{
+//    oxygine::HttpRequestCocoaTask* task = [self getTask:dataTask remove:true];
+//    log::messageln("nssessiond complete %x", dataTask);
+//    //if (!task)
+//    //    return;
+//    task->complete_(data);
+//}
+
+#pragma mark -
+
 @end
 
 namespace oxygine
 {
-    NSURLSession* _session = 0;
-    
+	int _httpRequestTaskInitialized = 0;
 
+	HttpRequests *_cls = nil;
+	
+	void _sessionConfigCommonInit(NSURLSessionConfiguration* config) {
+		config.allowsCellularAccess = YES;
+		config.timeoutIntervalForRequest = 30.0;
+		config.timeoutIntervalForResource = 60.0;
+		config.HTTPMaximumConnectionsPerHost = 10;
+	}
+	
+	NSURLSession* __defaultSession = nil;
+	NSURLSession* _getDefaultSession() {
+		if (!__defaultSession) {
+			OX_ASSERT(_cls); // Call HttpRequestTask::init()
+			NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
+			_sessionConfigCommonInit(config);
+			__defaultSession = [NSURLSession sessionWithConfiguration:config delegate:_cls delegateQueue:nil];
+			[__defaultSession retain];
+		}
+		return __defaultSession;
+	}
+	
+    NSURLSession* __ephemeralSession = nil;
+	NSURLSession* _getEphemeralSession() {
+		if (!__ephemeralSession) {
+			OX_ASSERT(_cls); // Call HttpRequestTask::init()
+			NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
+			_sessionConfigCommonInit(config);
+			config.URLCache = nil;
+			config.URLCredentialStorage = nil;
+			config.HTTPCookieStorage = nil;
+			
+			__ephemeralSession = [NSURLSession sessionWithConfiguration:config delegate:_cls delegateQueue:nil];
+			[__ephemeralSession retain];
+		}
+		return __ephemeralSession;
+	}
+	
     void HttpRequestTask::init()
     {
-        NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
-        HttpRequests *cls = [[HttpRequests alloc] init];
-        _session = [NSURLSession sessionWithConfiguration:config delegate:cls delegateQueue:[[NSOperationQueue alloc] init]];
-		[_session retain];
+		if (_httpRequestTaskInitialized++)
+			return;
+		
+        _cls = [[HttpRequests alloc] init];
     }
     
     void HttpRequestTask::release()
     {
-		[_session release];
-        _session = 0;
+		OX_ASSERT(_httpRequestTaskInitialized > 0);
+		if (--_httpRequestTaskInitialized)
+			return;
+		
+		[__defaultSession release];
+		__defaultSession = NULL;
+		
+		[__ephemeralSession release];
+		__ephemeralSession = NULL;
+		
+		[_cls release];
+		_cls = NULL;
     }
     
     spHttpRequestTask HttpRequestTask::create()
@@ -135,12 +175,9 @@ namespace oxygine
         progress(loaded, total);
     }
     
-    void HttpRequestCocoaTask::complete_(NSData *data)
+    void HttpRequestCocoaTask::complete_(NSData *data, bool error)
     {
-        NSUInteger statusCode = 200;//((NSHTTPURLResponse *)response).statusCode;
-        bool error = false;
-        
-        if (error || statusCode != 200)
+        if (error)
             onError();
         else
         {
@@ -162,10 +199,11 @@ namespace oxygine
         _mainThreadSync = true;
         
         addRef();
-        NSURL *url =[NSURL URLWithString:[NSString stringWithUTF8String:(_url).c_str()]];
-        //NSURL *url = [NSURL alloc];
-        //[url initWithString:[NSString stringWithUTF8String:_url.c_str()]];
-        
+		NSString *urlString = [NSString stringWithUTF8String:_url.c_str()];
+        NSURL *url =[NSURL URLWithString:urlString];
+		
+		NSURLSession *session = _cacheEnabled ? _getDefaultSession() : _getEphemeralSession();
+
         NSURLSessionTask *task = 0;
         if (_fname.empty())
         {
@@ -175,46 +213,45 @@ namespace oxygine
                 request.HTTPBody = [NSData dataWithBytes:_postData.data() length:_postData.size()];
                 request.HTTPMethod = @"POST";
             }
-            
-            task = [_session dataTaskWithRequest:request
+			
+            task = [session dataTaskWithRequest:request
                 completionHandler:^(NSData *data,
                                     NSURLResponse *response,
                                     NSError *error) {
                     // handle response
-                    
-                    NSUInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
-                    
-
-                    if (error || statusCode != 200)
+					
+					bool httpError = false;
+					
+					if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
+						NSHTTPURLResponse *httpResponse = ((NSHTTPURLResponse *)response);
+						NSInteger statusCode = httpResponse.statusCode;
+						if (statusCode != 200)
+							httpError = true;
+					}
+					
+                    if (error || httpError)
                     {
                         onError();
-                        releaseRef();
                     }
                     else
                     {
-                        complete_(data);
+						if (data)
+						{
+							const void *ptr = data.bytes;
+							size_t len = data.length;
+							_response.assign((const char*)ptr, (const char*)ptr + len);
+						}
+						onComplete();
                     }
+					releaseRef();
                 }];
         }
         else
         {
-            task = [_session downloadTaskWithURL:url];
-
-            /*
-                               completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error){
-                                   // handle response
-                                   NSUInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
-                                   if (error || statusCode != 200)
-                                       onError();
-                                   else
-                                   {
-                                       onComplete();
-                                   }
-                                   releaseRef();
-                               }];
-             */
+            task = [session downloadTaskWithURL:url];
         }
-        objc_setAssociatedObject(task, &key, [[ObjectHolder alloc] initWithObject:this], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+		NSValue *taskValue = [NSValue valueWithPointer:this];
+        objc_setAssociatedObject(task, &taskKey, taskValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
         log::messageln("created task session: %x", task);
         
         [task resume];