153 lines
5.1 KiB
Objective-C
153 lines
5.1 KiB
Objective-C
//
|
|
// 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
|