123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- //
- // QNConnectChecker.m
- // QiniuSDK_Mac
- //
- // Created by yangsen on 2021/1/8.
- // Copyright © 2021 Qiniu. All rights reserved.
- //
- #import "QNDefine.h"
- #import "QNLogUtil.h"
- #import "QNConfiguration.h"
- #import "QNSingleFlight.h"
- #import "QNConnectChecker.h"
- #import "QNUploadSystemClient.h"
- @interface QNConnectChecker()
- @end
- @implementation QNConnectChecker
- + (QNSingleFlight *)singleFlight {
- static QNSingleFlight *singleFlight = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- singleFlight = [[QNSingleFlight alloc] init];
- });
- return singleFlight;
- }
- + (dispatch_queue_t)checkQueue {
- static dispatch_queue_t queue;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- queue = dispatch_queue_create("com.qiniu.NetworkCheckQueue", DISPATCH_QUEUE_CONCURRENT);
- });
- return queue;
- }
- + (BOOL)isConnected:(QNUploadSingleRequestMetrics *)metrics {
- return metrics && ((NSHTTPURLResponse *)metrics.response).statusCode > 99;
- }
- + (QNUploadSingleRequestMetrics *)check {
- __block QNUploadSingleRequestMetrics *metrics = nil;
- dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
- [self check:^(QNUploadSingleRequestMetrics *metricsP) {
- metrics = metricsP;
- dispatch_semaphore_signal(semaphore);
- }];
- dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
- return metrics;
- }
- + (void)check:(void (^)(QNUploadSingleRequestMetrics *))complete {
- QNSingleFlight *singleFlight = [self singleFlight];
-
- kQNWeakSelf;
- [singleFlight perform:@"connect_check" action:^(QNSingleFlightComplete _Nonnull singleFlightComplete) {
- kQNStrongSelf;
-
- [self checkAllHosts:^(QNUploadSingleRequestMetrics *metrics) {
- singleFlightComplete(metrics, nil);
- }];
-
- } complete:^(id _Nullable value, NSError * _Nullable error) {
- if (complete) {
- complete(value);
- }
- }];
- }
- + (void)checkAllHosts:(void (^)(QNUploadSingleRequestMetrics *metrics))complete {
-
- __block int completeCount = 0;
- __block BOOL isCompleted = false;
- kQNWeakSelf;
- NSArray *allHosts = [kQNGlobalConfiguration.connectCheckURLStrings copy];
- if (allHosts.count == 0) {
- QNUploadSingleRequestMetrics *metrics = [QNUploadSingleRequestMetrics emptyMetrics];
- [metrics start];
- [metrics end];
- metrics.error = [NSError errorWithDomain:@"com.qiniu.NetworkCheck" code:NSURLErrorUnsupportedURL userInfo:@{@"user_info":@"check host is empty"}];
- complete(metrics);
- return;
- }
-
- for (NSString *host in allHosts) {
- [self checkHost:host complete:^(QNUploadSingleRequestMetrics *metrics) {
- kQNStrongSelf;
-
- BOOL isHostConnected = [self isConnected:metrics];
- @synchronized (self) {
- completeCount += 1;
- }
- if (isHostConnected || completeCount == allHosts.count) {
- @synchronized (self) {
- if (isCompleted) {
- QNLogInfo(@"== check all hosts has completed totalCount:%d completeCount:%d", allHosts.count, completeCount);
- return;
- } else {
- QNLogInfo(@"== check all hosts completed totalCount:%d completeCount:%d", allHosts.count, completeCount);
- isCompleted = true;
- }
- }
- complete(metrics);
- } else {
- QNLogInfo(@"== check all hosts not completed totalCount:%d completeCount:%d", allHosts.count, completeCount);
- }
- }];
- }
- }
- + (void)checkHost:(NSString *)host complete:(void (^)(QNUploadSingleRequestMetrics *metrics))complete {
-
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- request.URL = [NSURL URLWithString:host];
- request.HTTPMethod = @"HEAD";
- request.timeoutInterval = kQNGlobalConfiguration.connectCheckTimeout;
-
- __block BOOL hasCallback = false;
-
- QNUploadSingleRequestMetrics *timeoutMetric = [QNUploadSingleRequestMetrics emptyMetrics];
- [timeoutMetric start];
-
- QNUploadSystemClient *client = [[QNUploadSystemClient alloc] init];
- [client request:request server:nil connectionProxy:nil progress:nil complete:^(NSURLResponse *response, QNUploadSingleRequestMetrics * metrics, NSData * _Nullable data, NSError * error) {
- @synchronized (self) {
- if (hasCallback) {
- return;
- }
- hasCallback = true;
- }
- QNLogInfo(@"== checkHost:%@ responseInfo:%@", host, response);
- complete(metrics);
- }];
-
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * kQNGlobalConfiguration.connectCheckTimeout), [self checkQueue], ^{
- @synchronized (self) {
- if (hasCallback) {
- return;
- }
- hasCallback = true;
- }
- [client cancel];
- [timeoutMetric end];
- timeoutMetric.error = [NSError errorWithDomain:@"com.qiniu.NetworkCheck" code:NSURLErrorTimedOut userInfo:nil];
- complete(timeoutMetric);
- });
- }
- @end
|