diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f173fe6..1bd2387e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## XX.XX.XX +* Improved Content refresh mechanics. + ## 25.4.8 * Mitigated an issue where "giveAllConsent" did not include metrics consent. diff --git a/CountlyConnectionManager.h b/CountlyConnectionManager.h index e45e8e44..8d916263 100644 --- a/CountlyConnectionManager.h +++ b/CountlyConnectionManager.h @@ -49,6 +49,7 @@ extern const NSInteger kCountlyGETRequestMaxLength; - (void)sendEventsWithSaveIfNeeded; - (void)sendEvents; - (void)attemptToSendStoredRequests; +- (void)attemptToSendStoredRequestsSync; - (void)sendPushToken:(NSString *)token; - (void)sendLocationInfo; - (void)sendUserDetails:(NSString *)userDetails; diff --git a/CountlyConnectionManager.m b/CountlyConnectionManager.m index a55ad2f1..67a24fdd 100644 --- a/CountlyConnectionManager.m +++ b/CountlyConnectionManager.m @@ -171,9 +171,8 @@ - (void)addCustomNetworkRequestHeaders:(NSDictionary *_N _URLSession = nil; } -- (void)proceedOnQueue -{ - CLY_LOG_D(@"Proceeding on queue..."); +- (void)proceedOnQueue:(BOOL)sync { + CLY_LOG_D(@"%s, Proceeding on queue, sync:[%d]", __FUNCTION__, sync); if (!CountlyServerConfig.sharedInstance.networkingEnabled) { @@ -234,7 +233,7 @@ - (void)proceedOnQueue [CountlyPersistency.sharedInstance saveToFile]; - [self proceedOnQueue]; + [self proceedOnQueue:sync]; return; } @@ -309,6 +308,21 @@ - (void)proceedOnQueue request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData; NSDate *startTimeRequest = [NSDate date]; + if(sync){ + [self proceedOnQueueInnerSync:request startTimeRequest:startTimeRequest firstItemInQueue:firstItemInQueue queryString:queryString]; + } else { + [self proceedOnQueueInnerAsync:request startTimeRequest:startTimeRequest firstItemInQueue:firstItemInQueue queryString:queryString]; + } + + [self logRequest:request]; +} + +- (void)proceedOnQueue +{ + [self proceedOnQueue:NO]; +} + +- (void)proceedOnQueueInnerAsync:(NSMutableURLRequest*) request startTimeRequest:(NSDate *) startTimeRequest firstItemInQueue:(NSString*) firstItemInQueue queryString:(NSString*) queryString { self.connection = [self.URLSession dataTaskWithRequest:request completionHandler:^(NSData * data, NSURLResponse * response, NSError * error) { self.connection = nil; @@ -361,8 +375,74 @@ - (void)proceedOnQueue }]; [self.connection resume]; +} + +- (void)proceedOnQueueInnerSync:(NSMutableURLRequest*) request startTimeRequest:(NSDate *) startTimeRequest firstItemInQueue:(NSString*) firstItemInQueue queryString:(NSString*) queryString { + __block NSData *responseData = nil; + __block NSURLResponse *urlResponse = nil; + __block NSError *responseError = nil; + + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + + self.connection = [self.URLSession dataTaskWithRequest:request completionHandler:^(NSData * data, NSURLResponse * response, NSError * error) + { + responseData = data; + urlResponse = response; + responseError = error; + + dispatch_semaphore_signal(sem); // Signal that the task is complete + }]; + + [self.connection resume]; + + // Wait until the request completes + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + self.connection = nil; + + NSDate *endTimeRequest = [NSDate date]; + long duration = (long)[endTimeRequest timeIntervalSinceDate:startTimeRequest]; + + CLY_LOG_V(@"Approximate received data size for request <%p> is %ld bytes.", (id)request, (long)responseData.length); + + if(urlResponse) { + NSInteger code = ((NSHTTPURLResponse*)urlResponse).statusCode; + CLY_LOG_V(@"%s, Response received from server with status code:[ %ld ] request:[ %@ ]", __FUNCTION__, (long)code, ((NSHTTPURLResponse*)urlResponse).URL); + } + + if (!responseError) + { + if ([self isRequestSuccessful:urlResponse data:responseData]) + { + CLY_LOG_D(@"Request <%p> successfully completed.", request); + + [CountlyPersistency.sharedInstance removeFromQueue:firstItemInQueue]; + [CountlyPersistency.sharedInstance saveToFile]; + + if(CountlyServerConfig.sharedInstance.backoffMechanism && [self backoff:duration queryString:queryString]){ + CLY_LOG_D(@"%s, backed off dropping proceeding the queue", __FUNCTION__); + self.startTime = nil; + [self backoffCountdown]; + } else { + [self proceedOnQueue:YES]; + } + } + else + { + CLY_LOG_D(@"%s, request:[ <%p> ] failed! response:[ %@ ]", __FUNCTION__, request, [responseData cly_stringUTF8]); + [CountlyHealthTracker.sharedInstance logFailedNetworkRequestWithStatusCode:((NSHTTPURLResponse*)urlResponse).statusCode errorResponse: [responseData cly_stringUTF8]]; + [CountlyHealthTracker.sharedInstance saveState]; + self.startTime = nil; + } + } + else + { + CLY_LOG_D(@"%s, request:[ <%p> ] failed! error:[ %@ ]", __FUNCTION__, request, responseError); + #if (TARGET_OS_WATCH) + [CountlyPersistency.sharedInstance saveToFile]; + #endif + self.startTime = nil; + } - [self logRequest:request]; } - (void)recordMetrics:(nullable NSDictionary *)metricsOverride @@ -613,6 +693,13 @@ - (void)attemptToSendStoredRequests [self proceedOnQueue]; } +- (void)attemptToSendStoredRequestsSync +{ + [self addEventsToQueue]; + [CountlyPersistency.sharedInstance saveToFileSync]; + [self proceedOnQueue:YES]; +} + - (void)sendEventsInternal { [self addEventsToQueue]; diff --git a/CountlyContentBuilderInternal.m b/CountlyContentBuilderInternal.m index 6317d367..46b7d8eb 100644 --- a/CountlyContentBuilderInternal.m +++ b/CountlyContentBuilderInternal.m @@ -124,13 +124,13 @@ - (void)refreshContentZone { } [self exitContentZone]; - [CountlyConnectionManager.sharedInstance attemptToSendStoredRequests]; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^ - { - [self enterContentZone]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [CountlyConnectionManager.sharedInstance attemptToSendStoredRequestsSync]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self enterContentZone]; // this touches to UI so it needs to be handled in the main queue + }); }); - + } #pragma mark - Private Methods