Files
youle_app_ios/Pods/Qiniu/QiniuSDK/Http/ServerRegion/QNUploadDomainRegion.m

445 lines
16 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// QNUploadServerDomainResolver.m
// AppTest
//
// Created by yangsen on 2020/4/23.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "QNUploadRequestState.h"
#import "QNUploadDomainRegion.h"
#import "QNResponseInfo.h"
#import "QNUploadServer.h"
#import "QNZoneInfo.h"
#import "QNUploadServerFreezeUtil.h"
#import "QNUploadServerFreezeManager.h"
#import "QNDnsPrefetch.h"
#import "QNLogUtil.h"
#import "QNUtils.h"
#import "QNDefine.h"
#import "QNUploadServerNetworkStatus.h"
@interface QNUploadIpGroup : NSObject
@property(nonatomic, assign)int ipIndex;
@property(nonatomic, copy, readonly)NSString *groupType;
@property(nonatomic, strong, readonly)NSArray <id <QNIDnsNetworkAddress> > *ipList;
@end
@implementation QNUploadIpGroup
- (instancetype)initWithGroupType:(NSString *)groupType
ipList:(NSArray <id <QNIDnsNetworkAddress> > *)ipList{
if (self = [super init]) {
_groupType = groupType;
_ipList = ipList;
_ipIndex = -1;
}
return self;
}
- (id <QNIDnsNetworkAddress>)getServerIP{
if (!self.ipList || self.ipList.count == 0) {
return nil;
} else {
if (_ipIndex < 0 || _ipIndex > (self.ipList.count - 1)) {
_ipIndex = arc4random()%self.ipList.count;
}
return self.ipList[_ipIndex];
}
}
@end
@interface QNUploadServerDomain: NSObject
@property(nonatomic, copy)NSString *host;
@property(nonatomic, strong)NSArray <QNUploadIpGroup *> *ipGroupList;
@end
@implementation QNUploadServerDomain
+ (QNUploadServerDomain *)domain:(NSString *)host{
QNUploadServerDomain *domain = [[QNUploadServerDomain alloc] init];
domain.host = host;
return domain;
}
- (QNUploadServer *)getServerWithCondition:(BOOL(^)(NSString *host, QNUploadServer *server, QNUploadServer *filterServer))condition {
@synchronized (self) {
if (!self.ipGroupList || self.ipGroupList.count == 0) {
[self createIpGroupList];
}
}
QNUploadServer *server = nil;
// Host解析出IP时:
if (self.ipGroupList && self.ipGroupList.count > 0) {
for (QNUploadIpGroup *ipGroup in self.ipGroupList) {
id <QNIDnsNetworkAddress> inetAddress = [ipGroup getServerIP];
QNUploadServer *filterServer = [QNUploadServer server:self.host
ip:inetAddress.ipValue
source:inetAddress.sourceValue
ipPrefetchedTime:inetAddress.timestampValue];
if (condition == nil || condition(self.host, server, filterServer)) {
server = filterServer;
}
if (condition == nil) {
break;
}
}
return server;
}
// Host未解析出IP时:
QNUploadServer *hostServer = [QNUploadServer server:self.host
ip:nil
source:nil
ipPrefetchedTime:nil];
if (condition == nil || condition(self.host, nil, hostServer)) {
// 未解析时,没有可比性,直接返回自身,自身即为最优
server = hostServer;
}
return server;
}
- (QNUploadServer *)getOneServer{
if (!self.host || self.host.length == 0) {
return nil;
}
if (self.ipGroupList && self.ipGroupList.count > 0) {
NSInteger index = arc4random()%self.ipGroupList.count;
QNUploadIpGroup *ipGroup = self.ipGroupList[index];
id <QNIDnsNetworkAddress> inetAddress = [ipGroup getServerIP];
QNUploadServer *server = [QNUploadServer server:self.host ip:inetAddress.ipValue source:inetAddress.sourceValue ipPrefetchedTime:inetAddress.timestampValue];;
return server;
} else {
return [QNUploadServer server:self.host ip:nil source:nil ipPrefetchedTime:nil];
}
}
- (void)clearIpGroupList {
@synchronized (self) {
self.ipGroupList = nil;
}
}
- (void)createIpGroupList {
@synchronized (self) {
if (self.ipGroupList && self.ipGroupList.count > 0) {
return;
}
// get address List of host
NSArray *inetAddresses = [kQNDnsPrefetch getInetAddressByHost:self.host];
if (!inetAddresses || inetAddresses.count == 0) {
return;
}
// address List to ipList of group & check ip network
NSMutableDictionary *ipGroupInfos = [NSMutableDictionary dictionary];
for (id <QNIDnsNetworkAddress> inetAddress in inetAddresses) {
NSString *ipValue = inetAddress.ipValue;
NSString *groupType = [QNUtils getIpType:ipValue host:self.host];
if (groupType) {
NSMutableArray *ipList = ipGroupInfos[groupType] ?: [NSMutableArray array];
[ipList addObject:inetAddress];
ipGroupInfos[groupType] = ipList;
}
}
// ipList of group to ipGroup List
NSMutableArray *ipGroupList = [NSMutableArray array];
for (NSString *groupType in ipGroupInfos.allKeys) {
NSArray *ipList = ipGroupInfos[groupType];
QNUploadIpGroup *ipGroup = [[QNUploadIpGroup alloc] initWithGroupType:groupType ipList:ipList];
[ipGroupList addObject:ipGroup];
}
self.ipGroupList = ipGroupList;
}
}
@end
@interface QNUploadDomainRegion()
// 是否支持http3
@property(nonatomic, assign)BOOL http3Enabled;
// 是否冻结过HostPS如果没有冻结过 Host,则当前 Region 上传也就不会有错误信息,可能会返回-9所以必须要再进行一次尝试
@property(atomic , assign)BOOL hasFreezeHost;
@property(atomic , assign)BOOL isAllFrozen;
@property(atomic , assign)BOOL enableAccelerateUpload;
// 局部http2冻结管理对象
@property(nonatomic, strong)QNUploadServerFreezeManager *partialHttp2Freezer;
@property(nonatomic, strong)QNUploadServerFreezeManager *partialHttp3Freezer;
@property(nonatomic, strong)NSArray <NSString *> *accDomainHostList;
@property(nonatomic, strong)NSDictionary <NSString *, QNUploadServerDomain *> *accDomainDictionary;
@property(nonatomic, strong)NSArray <NSString *> *domainHostList;
@property(nonatomic, strong)NSDictionary <NSString *, QNUploadServerDomain *> *domainDictionary;
@property(nonatomic, strong)NSArray <NSString *> *oldDomainHostList;
@property(nonatomic, strong)NSDictionary <NSString *, QNUploadServerDomain *> *oldDomainDictionary;
@property(nonatomic, strong, nullable)QNZoneInfo *zoneInfo;
@end
@implementation QNUploadDomainRegion
- (instancetype)initWithConfig:(QNConfiguration *)config {
if (self = [super init]) {
if (config) {
self.enableAccelerateUpload = config.accelerateUploading;
}
}
return self;
}
- (BOOL)isValid{
return !self.isAllFrozen &&
((self.enableAccelerateUpload && self.accDomainHostList > 0) ||
self.domainHostList.count > 0 || self.oldDomainHostList.count > 0);
}
- (void)setupRegionData:(QNZoneInfo *)zoneInfo{
_zoneInfo = zoneInfo;
self.isAllFrozen = NO;
self.hasFreezeHost = NO;
self.http3Enabled = zoneInfo.http3Enabled;
// 暂时屏蔽
self.http3Enabled = false;
NSMutableArray *serverGroups = [NSMutableArray array];
NSMutableArray *accDomainHostList = [NSMutableArray array];
if (zoneInfo.acc_domains) {
[serverGroups addObjectsFromArray:zoneInfo.acc_domains];
[accDomainHostList addObjectsFromArray:zoneInfo.acc_domains];
}
self.accDomainHostList = accDomainHostList;
self.accDomainDictionary = [self createDomainDictionary:serverGroups];
[serverGroups removeAllObjects];
NSMutableArray *domainHostList = [NSMutableArray array];
if (zoneInfo.domains) {
[serverGroups addObjectsFromArray:zoneInfo.domains];
[domainHostList addObjectsFromArray:zoneInfo.domains];
}
self.domainHostList = domainHostList;
self.domainDictionary = [self createDomainDictionary:serverGroups];
[serverGroups removeAllObjects];
NSMutableArray *oldDomainHostList = [NSMutableArray array];
if (zoneInfo.old_domains) {
[serverGroups addObjectsFromArray:zoneInfo.old_domains];
[oldDomainHostList addObjectsFromArray:zoneInfo.old_domains];
}
self.oldDomainHostList = oldDomainHostList;
self.oldDomainDictionary = [self createDomainDictionary:serverGroups];
QNLogInfo(@"region :%@",domainHostList);
QNLogInfo(@"region old:%@",oldDomainHostList);
}
- (NSDictionary *)createDomainDictionary:(NSArray <NSString *> *)hosts{
NSMutableDictionary *domainDictionary = [NSMutableDictionary dictionary];
for (NSString *host in hosts) {
QNUploadServerDomain *domain = [QNUploadServerDomain domain:host];
[domainDictionary setObject:domain forKey:host];
}
return [domainDictionary copy];
}
- (void)updateIpListFormHost:(NSString *)host {
if (host == nil) {
return;
}
[self.domainDictionary[host] clearIpGroupList];
[self.oldDomainDictionary[host] clearIpGroupList];
}
- (id<QNUploadServer> _Nullable)getNextServer:(QNUploadRequestState *)requestState
responseInfo:(QNResponseInfo *)responseInfo
freezeServer:(id <QNUploadServer> _Nullable)freezeServer{
if (self.isAllFrozen) {
return nil;
}
[self freezeServerIfNeed:responseInfo freezeServer:freezeServer];
BOOL accelerate = YES;
@synchronized (self) {
if (self.enableAccelerateUpload && responseInfo.isTransferAccelerationConfigureError) {
self.enableAccelerateUpload = NO;
}
accelerate = self.enableAccelerateUpload;
}
NSMutableArray *hostList = [NSMutableArray array];
NSMutableDictionary *domainInfo = [NSMutableDictionary dictionary];
if (requestState.isUseOldServer) {
if (self.oldDomainHostList.count > 0 && self.oldDomainDictionary.count > 0) {
[hostList addObjectsFromArray:self.oldDomainHostList];
[domainInfo addEntriesFromDictionary:self.oldDomainDictionary];
}
} else {
// 优先使用 acc
if (accelerate &&
self.accDomainHostList.count > 0 &&
self.accDomainDictionary.count > 0) {
[hostList addObjectsFromArray:self.accDomainHostList];
[domainInfo addEntriesFromDictionary:self.accDomainDictionary];
}
if (self.domainHostList.count > 0 &&
self.domainDictionary.count > 0){
[hostList addObjectsFromArray:self.domainHostList];
[domainInfo addEntriesFromDictionary:self.domainDictionary];
}
}
if (hostList.count == 0 || domainInfo.count == 0) {
return nil;
}
QNUploadServer *server = nil;
// 1. 优先使用http3
if (self.http3Enabled) {
for (NSString *host in hostList) {
QNUploadServer *domainServer = [domainInfo[host] getServerWithCondition:^BOOL(NSString *host, QNUploadServer *serverP, QNUploadServer *filterServer) {
// 1.1 剔除冻结对象
NSString *frozenType = QNUploadFrozenType(host, filterServer.ip);
BOOL isFrozen = [QNUploadServerFreezeUtil isType:frozenType
frozenByFreezeManagers:@[self.partialHttp3Freezer, kQNUploadGlobalHttp3Freezer]];
if (isFrozen) {
return NO;
}
// 1.2 挑选网络状态最优
return [QNUploadServerNetworkStatus isServerNetworkBetter:filterServer thanServerB:serverP];
}];
server = [QNUploadServerNetworkStatus getBetterNetworkServer:server serverB:domainServer];
if (server) {
break;
}
}
if (server) {
server.httpVersion = kQNHttpVersion3;
return server;
}
}
// 2. 挑选http2
for (NSString *host in hostList) {
kQNWeakSelf;
QNUploadServer *domainServer = [domainInfo[host] getServerWithCondition:^BOOL(NSString *host, QNUploadServer *serverP, QNUploadServer *filterServer) {
kQNStrongSelf;
// 2.1 剔除冻结对象
NSString *frozenType = QNUploadFrozenType(host, filterServer.ip);
BOOL isFrozen = [QNUploadServerFreezeUtil isType:frozenType
frozenByFreezeManagers:@[self.partialHttp2Freezer, kQNUploadGlobalHttp2Freezer]];
if (isFrozen) {
return NO;
}
// 2.2 挑选网络状态最优
return [QNUploadServerNetworkStatus isServerNetworkBetter:filterServer thanServerB:serverP];
}];
server = [QNUploadServerNetworkStatus getBetterNetworkServer:server serverB:domainServer];
if (server) {
break;
}
}
// 3. 无可用 server 且未冻结过 Host 则随机获取一个
if (server == nil && !self.hasFreezeHost && hostList.count > 0) {
NSInteger index = arc4random()%hostList.count;
NSString *host = hostList[index];
server = [domainInfo[host] getOneServer];
[self unfreezeServer:server];
}
if (server == nil) {
self.isAllFrozen = YES;
}
server.httpVersion = kQNHttpVersion2;
QNLogInfo(@"get server host:%@ ip:%@", server.host, server.ip);
return server;
}
- (void)freezeServerIfNeed:(QNResponseInfo *)responseInfo
freezeServer:(QNUploadServer *)freezeServer {
if (freezeServer == nil || freezeServer.serverId == nil || responseInfo == nil) {
return;
}
NSString *frozenType = QNUploadFrozenType(freezeServer.host, freezeServer.ip);
// 1. http3 冻结
if (kQNIsHttp3(freezeServer.httpVersion)) {
if (responseInfo.isNotQiniu) {
self.hasFreezeHost = YES;
[self.partialHttp3Freezer freezeType:frozenType frozenTime:kQNGlobalConfiguration.partialHostFrozenTime];
}
if (!responseInfo.canConnectToHost || responseInfo.isHostUnavailable) {
self.hasFreezeHost = YES;
[kQNUploadGlobalHttp3Freezer freezeType:frozenType frozenTime:kQNUploadHttp3FrozenTime];
}
return;
}
// 2. http2 冻结
// 2.1 无法连接到Host || Host不可用 局部冻结
if (responseInfo.isNotQiniu || !responseInfo.canConnectToHost || responseInfo.isHostUnavailable) {
QNLogInfo(@"partial freeze server host:%@ ip:%@", freezeServer.host, freezeServer.ip);
self.hasFreezeHost = YES;
[self.partialHttp2Freezer freezeType:frozenType frozenTime:kQNGlobalConfiguration.partialHostFrozenTime];
}
// 2.2 Host不可用全局冻结
if (responseInfo.isHostUnavailable) {
QNLogInfo(@"global freeze server host:%@ ip:%@", freezeServer.host, freezeServer.ip);
self.hasFreezeHost = YES;
[kQNUploadGlobalHttp2Freezer freezeType:frozenType frozenTime:kQNGlobalConfiguration.globalHostFrozenTime];
}
}
/// 仅仅解封局部的
- (void)unfreezeServer:(QNUploadServer *)freezeServer {
if (freezeServer == nil) {
return;
}
NSString *frozenType = QNUploadFrozenType(freezeServer.host, freezeServer.ip);
[self.partialHttp2Freezer unfreezeType:frozenType];
}
- (QNUploadServerFreezeManager *)partialHttp2Freezer{
if (!_partialHttp2Freezer) {
_partialHttp2Freezer = [[QNUploadServerFreezeManager alloc] init];
}
return _partialHttp2Freezer;
}
- (QNUploadServerFreezeManager *)partialHttp3Freezer{
if (!_partialHttp3Freezer) {
_partialHttp3Freezer = [[QNUploadServerFreezeManager alloc] init];
}
return _partialHttp3Freezer;
}
@end