解决了语音上传到问题,接下来要解决下载播放问题

This commit is contained in:
joywayer
2025-06-15 12:36:47 +08:00
parent bba3ed1cb4
commit c11fc62bf1
513 changed files with 31197 additions and 2969 deletions

41
Pods/Qiniu/QiniuSDK/Http/Dns/QNDns.h generated Normal file
View File

@@ -0,0 +1,41 @@
//
// QNDns.h
// QnDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol QNIDnsNetworkAddress <NSObject>
/// 域名
@property(nonatomic, copy, readonly)NSString *hostValue;
/// 地址IP信息
@property(nonatomic, copy, readonly)NSString *ipValue;
/// ip有效时间 单位:秒
@property(nonatomic, strong, readonly)NSNumber *ttlValue;
/// ip预取来源, 自定义dns返回 @"customized"
@property(nonatomic, copy, readonly)NSString *sourceValue;
/// 解析到host时的时间戳 单位:秒
@property(nonatomic, strong, readonly)NSNumber *timestampValue;
@end
@protocol QNDnsDelegate <NSObject>
/// 根据host获取解析结果
/// @param host 域名
- (NSArray < id <QNIDnsNetworkAddress> > *)query:(NSString *)host;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,29 @@
//
// QNDnsCacheFile.h
// QnDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "QNRecorderDelegate.h"
NS_ASSUME_NONNULL_BEGIN
@interface QNDnsCacheFile : NSObject<QNRecorderDelegate>
/// DNS解析信息本地缓存路径
@property(nonatomic, copy, readonly)NSString *directory;
/// 构造方法 路径不存在或进行创建创建失败返回为nil
/// @param directory 路径
/// @param error 构造错误时,会有值
+ (instancetype _Nullable)dnsCacheFile:(NSString *)directory
error:(NSError **)error;
- (void)clearCache:(NSError **)error;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,91 @@
//
// QNDnsCacheFile.m
// QnDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "QNDnsCacheFile.h"
@interface QNDnsCacheFile()
@property(nonatomic, copy)NSString *directory;
@end
@implementation QNDnsCacheFile
+ (instancetype)dnsCacheFile:(NSString *)directory
error:(NSError **)error{
NSError *err = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:&err];
if (err != nil) {
if (error != nil) *error = err;
return nil;
}
QNDnsCacheFile *f = [[QNDnsCacheFile alloc] init];
f.directory = directory;
return f;
}
- (NSError *)set:(NSString *)key data:(NSData *)value {
@synchronized (self) {
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *filePath = [self pathOfKey:key];
if ([fileManager fileExistsAtPath:filePath]) {
[fileManager removeItemAtPath:filePath error:&error];
}
[fileManager createFileAtPath:filePath contents:value attributes:nil];
return error;
}
}
- (NSData *)get:(NSString *)key {
return [NSData dataWithContentsOfFile:[self pathOfKey:key]];
}
- (NSError *)del:(NSString *)key {
@synchronized (self) {
NSError *error = nil;
NSString *path = [self pathOfKey:key];
if (path) {
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:path error:&error];
}
return error;
}
}
- (void)clearCache:(NSError *__autoreleasing _Nullable *)error {
@synchronized (self) {
NSError *err;
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:self.directory error:&err];
if (err != nil) {
if (error != nil) *error = err;
return;
}
[fileManager createDirectoryAtPath:self.directory withIntermediateDirectories:YES attributes:nil error:&err];
if (error != nil) {
*error = err;
}
}
}
- (NSString *)getFileName{
return @"dnsCache";
}
- (NSString *)pathOfKey:(NSString *)key {
return [QNDnsCacheFile pathJoin:key path:_directory];
}
+ (NSString *)pathJoin:(NSString *)key
path:(NSString *)path {
return [[NSString alloc] initWithFormat:@"%@/%@", path, key];
}
@end

View File

@@ -0,0 +1,41 @@
//
// QNDnsCacheKey.h
// QnDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface QNDnsCacheInfo : NSObject
/// 缓存时间戳
@property(nonatomic, copy, readonly)NSString *currentTime;
/// 缓存时本地IP
@property(nonatomic, copy, readonly)NSString *localIp;
/// 缓存信息
@property(nonatomic, copy, readonly)NSDictionary *info;
//MARK: -- 构造方法
/// 根据json构造对象
/// @param jsonData json数据
+ (instancetype)dnsCacheInfo:(NSData *)jsonData;
/// 根据属性构造对象
/// @param currentTime 缓存时间戳
/// @param localIp 缓存时本地IP
/// @param info 缓存信息
+ (instancetype)dnsCacheInfo:(NSString *)currentTime
localIp:(NSString *)localIp
info:(NSDictionary *)info;
/// 转化Json数据
- (NSData *)jsonData;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,58 @@
//
// QNDnsCacheKey.m
// QnDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "QNDnsCacheInfo.h"
@interface QNDnsCacheInfo()
///
@property(nonatomic, copy)NSString *currentTime;
/// IP
@property(nonatomic, copy)NSString *localIp;
///
@property(nonatomic, copy)NSDictionary *info;
@end
@implementation QNDnsCacheInfo
+ (instancetype)dnsCacheInfo:(NSData *)jsonData{
NSDictionary *info = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:nil];
if (!info || info.count == 0 ||
(!info[@"currentTime"] && !info[@"localIp"] && !info[@"info"])) {
return nil;
}
return [QNDnsCacheInfo dnsCacheInfo:info[@"currentTime"]
localIp:info[@"localIp"]
info:info[@"info"]];;
}
+ (instancetype)dnsCacheInfo:(NSString *)currentTime
localIp:(NSString *)localIp
info:(NSDictionary *)info{
QNDnsCacheInfo *cacheInfo = [[QNDnsCacheInfo alloc] init];
cacheInfo.currentTime = currentTime;
cacheInfo.localIp = localIp;
cacheInfo.info = info;
return cacheInfo;
}
- (NSData *)jsonData{
NSMutableDictionary *cacheInfo = [NSMutableDictionary dictionary];
if (self.currentTime) {
cacheInfo[@"currentTime"] = self.currentTime;
}
if (self.localIp) {
cacheInfo[@"localIp"] = self.localIp;
}
if (self.info) {
cacheInfo[@"info"] = self.info;
}
return [NSJSONSerialization dataWithJSONObject:cacheInfo options:NSJSONWritingPrettyPrinted error:nil];
}
@end

View File

@@ -0,0 +1,66 @@
//
// QNDnsPrefetch.h
// QnDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "QNDns.h"
#import "QNUpToken.h"
#import "QNConfiguration.h"
#import "QNTransactionManager.h"
NS_ASSUME_NONNULL_BEGIN
#define kQNDnsPrefetch [QNDnsPrefetch shared]
@interface QNDnsPrefetch : NSObject
/// 最近一次预取错误信息
@property(nonatomic, copy, readonly)NSString *lastPrefetchedErrorMessage;
+ (instancetype)shared;
/// 根据host从缓存中读取DNS信息
/// @param host 域名
- (NSArray <id <QNIDnsNetworkAddress> > *)getInetAddressByHost:(NSString *)host;
/// 通过安全的方式预取 dns
- (NSString *)prefetchHostBySafeDns:(NSString *)host error:(NSError **)error;
- (void)clearDnsCache:(NSError **)error;
@end
@interface QNTransactionManager(Dns)
/// 添加加载本地dns事务
- (void)addDnsLocalLoadTransaction;
/// 添加检测并预取dns事务 如果未开启DNS 或 事务队列中存在token对应的事务未处理则返回NO
/// @param currentZone 当前区域
/// @param token token信息
- (BOOL)addDnsCheckAndPrefetchTransaction:(QNZone *)currentZone token:(QNUpToken *)token;
- (BOOL)addDnsCheckAndPrefetchTransaction:(QNConfiguration *)config zone:(QNZone *)currentZone token:(QNUpToken *)token;
/// 设置定时事务检测已缓存DNS有效情况事务 无效会重新预取
- (void)setDnsCheckWhetherCachedValidTransactionAction;
@end
#define kQNDnsSourceDoh @"doh"
#define kQNDnsSourceUdp @"dns"
#define kQNDnsSourceDnspod @"dnspod"
#define kQNDnsSourceSystem @"system"
#define kQNDnsSourceCustom @"customized"
#define kQNDnsSourceNone @"none"
BOOL kQNIsDnsSourceDoh(NSString * _Nullable source);
BOOL kQNIsDnsSourceUdp(NSString * _Nullable source);
BOOL kQNIsDnsSourceDnsPod(NSString * _Nullable source);
BOOL kQNIsDnsSourceSystem(NSString * _Nullable source);
BOOL kQNIsDnsSourceCustom(NSString * _Nullable source);
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,874 @@
//
// QNDnsPrefetch.m
// QnDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "QNDnsPrefetch.h"
#import "QNInetAddress.h"
#import "QNDnsCacheInfo.h"
#import "QNZoneInfo.h"
#import "QNDefine.h"
#import "QNConfig.h"
#import "QNDnsCacheFile.h"
#import "QNUtils.h"
#import "QNAsyncRun.h"
#import "QNFixedZone.h"
#import "QNAutoZone.h"
#import <HappyDNS/HappyDNS.h>
//MARK: --
@interface QNDnsNetworkAddress : NSObject<QNIDnsNetworkAddress>
@property(nonatomic, copy)NSString *hostValue;
@property(nonatomic, copy)NSString *ipValue;
@property(nonatomic, strong)NSNumber *ttlValue;
@property(nonatomic, copy)NSString *sourceValue;
@property(nonatomic, strong)NSNumber *timestampValue;
/// addressDatajson String / Dictionary / Data / QNIDnsNetworkAddress
+ (instancetype)inetAddress:(id)addressInfo;
///
- (BOOL)isValid;
/// json
- (NSString *)toJsonInfo;
///
- (NSDictionary *)toDictionary;
@end
@implementation QNDnsNetworkAddress
+ (instancetype)inetAddress:(id)addressInfo{
NSDictionary *addressDic = nil;
if ([addressInfo isKindOfClass:[NSDictionary class]]) {
addressDic = (NSDictionary *)addressInfo;
} else if ([addressInfo isKindOfClass:[NSString class]]){
NSData *data = [(NSString *)addressInfo dataUsingEncoding:NSUTF8StringEncoding];
addressDic = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableLeaves
error:nil];
} else if ([addressInfo isKindOfClass:[NSData class]]) {
addressDic = [NSJSONSerialization JSONObjectWithData:(NSData *)addressInfo
options:NSJSONReadingMutableLeaves
error:nil];
} else if ([addressInfo conformsToProtocol:@protocol(QNIDnsNetworkAddress)]){
id <QNIDnsNetworkAddress> address = (id <QNIDnsNetworkAddress> )addressInfo;
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
if ([address respondsToSelector:@selector(hostValue)] && [address hostValue]) {
dic[@"hostValue"] = [address hostValue];
}
if ([address respondsToSelector:@selector(ipValue)] && [address ipValue]) {
dic[@"ipValue"] = [address ipValue];
}
if ([address respondsToSelector:@selector(ttlValue)] && [address ttlValue]) {
dic[@"ttlValue"] = [address ttlValue];
}
if ([address respondsToSelector:@selector(sourceValue)] && [address sourceValue]) {
dic[@"sourceValue"] = [address sourceValue];
} else {
dic[@"sourceValue"] = kQNDnsSourceCustom;
}
if ([address respondsToSelector:@selector(timestampValue)] && [address timestampValue]) {
dic[@"timestampValue"] = [address timestampValue];
}
addressDic = [dic copy];
}
if (addressDic) {
QNDnsNetworkAddress *address = [[QNDnsNetworkAddress alloc] init];
[address setValuesForKeysWithDictionary:addressDic];
return address;
} else {
return nil;
}
}
/// ttl
- (BOOL)needRefresh{
if (!self.timestampValue || !self.ipValue || self.ipValue.length == 0) {
return NO;
}
NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970];
return currentTimestamp > (self.timestampValue.doubleValue + self.ttlValue.doubleValue);
}
/// ttl
- (BOOL)isValid{
if (!self.timestampValue || !self.ipValue || self.ipValue.length == 0) {
return NO;
}
NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970];
return currentTimestamp < (self.timestampValue.doubleValue + kQNGlobalConfiguration.dnsCacheMaxTTL);
}
- (NSString *)toJsonInfo{
NSString *defaultString = @"{}";
NSDictionary *infoDic = [self toDictionary];
if (!infoDic) {
return defaultString;
}
NSData *infoData = [NSJSONSerialization dataWithJSONObject:infoDic
options:NSJSONWritingPrettyPrinted
error:nil];
if (!infoData) {
return defaultString;
}
NSString *infoStr = [[NSString alloc] initWithData:infoData encoding:NSUTF8StringEncoding];
if (!infoStr) {
return defaultString;
} else {
return infoStr;
}
}
- (NSDictionary *)toDictionary{
return [self dictionaryWithValuesForKeys:@[@"ipValue", @"hostValue", @"ttlValue", @"sourceValue", @"timestampValue"]];
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{}
@end
//MARK: -- HappyDNS
@interface QNRecord(DNS)<QNIDnsNetworkAddress>
@end
@implementation QNRecord(DNS)
- (NSString *)hostValue{
return nil;
}
- (NSString *)ipValue{
return self.value;
}
- (NSNumber *)ttlValue{
return @(self.ttl);
}
- (NSNumber *)timestampValue{
return @(self.timeStamp);
}
- (NSString *)sourceValue{
if (self.source == QNRecordSourceSystem) {
return kQNDnsSourceSystem;
} else if (self.source == QNRecordSourceDoh) {
return [NSString stringWithFormat:@"%@<%@>", kQNDnsSourceDoh, self.server];
} else if (self.source == QNRecordSourceUdp) {
return [NSString stringWithFormat:@"%@<%@>", kQNDnsSourceUdp, self.server];
} else if (self.source == QNRecordSourceDnspodEnterprise) {
return kQNDnsSourceDnspod;
} else if (self.ipValue == nil || self.ipValue.length == 0) {
return kQNDnsSourceNone;
} else {
return kQNDnsSourceCustom;
}
}
@end
@interface QNInternalDns : NSObject
@property(nonatomic, strong)id<QNDnsDelegate> dns;
@property(nonatomic, strong)id<QNResolverDelegate> resolver;
@end
@implementation QNInternalDns
+ (instancetype)dnsWithDns:(id<QNDnsDelegate>)dns {
QNInternalDns *interDns = [[QNInternalDns alloc] init];
interDns.dns = dns;
return interDns;
}
+ (instancetype)dnsWithResolver:(id<QNResolverDelegate>)resolver {
QNInternalDns *interDns = [[QNInternalDns alloc] init];
interDns.resolver = resolver;
return interDns;
}
- (NSArray < id <QNIDnsNetworkAddress> > *)query:(NSString *)host error:(NSError **)error {
if (self.dns && [self.dns respondsToSelector:@selector(query:)]) {
return [self.dns query:host];
} else if (self.resolver) {
NSArray <QNRecord *>* records = [self.resolver query:[[QNDomain alloc] init:host] networkInfo:nil error:error];
return [self filterRecords:records];
}
return nil;
}
- (NSArray <QNRecord *>*)filterRecords:(NSArray <QNRecord *>*)records {
NSMutableArray <QNRecord *> *newRecords = [NSMutableArray array];
for (QNRecord *record in records) {
if (record.type == kQNTypeA || record.type == kQNTypeAAAA) {
[newRecords addObject:record];
}
}
return [newRecords copy];
}
@end
//MARK: -- DNS Prefetcher
@interface QNDnsPrefetch()
// dns 3s
@property(nonatomic, assign)int dnsPrefetchTimeout;
//
@property(nonatomic, copy)NSString *lastPrefetchedErrorMessage;
///
@property(atomic, assign)BOOL isPrefetching;
/// AutoZone
@property(nonatomic, strong)dispatch_semaphore_t getAutoZoneSemaphore;
/// DNSkey
@property(nonatomic, strong)QNDnsCacheInfo *dnsCacheInfo;
// dns
@property(nonatomic, strong)QNInternalDns *customDns;
// dns
@property(nonatomic, strong)QNInternalDns *systemDns;
/// prefetch hosts
@property(nonatomic, strong)NSMutableSet *prefetchHosts;
/// DNS
/// 线线
@property(nonatomic, strong)NSMutableDictionary <NSString *, NSArray<QNDnsNetworkAddress *>*> *addressDictionary;
@property(nonatomic, strong)QNDnsCacheFile *diskCache;
@end
@implementation QNDnsPrefetch
+ (instancetype)shared{
static QNDnsPrefetch *prefetcher = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
prefetcher = [[QNDnsPrefetch alloc] init];
});
return prefetcher;
}
- (instancetype)init{
if (self = [super init]) {
_isPrefetching = NO;
_dnsPrefetchTimeout = 3;
}
return self;
}
//MARK: -- uploadManager
/// 使falsetrue
- (BOOL)recoverCache{
id <QNRecorderDelegate> recorder = nil;
NSError *error;
recorder = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir
error:&error];
if (error) {
return YES;
}
NSData *data = [recorder get:[QNIP local]];
if (!data) {
return YES;
}
QNDnsCacheInfo *cacheInfo = [QNDnsCacheInfo dnsCacheInfo:data];
if (!cacheInfo) {
return YES;
}
NSString *localIp = [QNIP local];
if (!localIp || localIp.length == 0 || ![cacheInfo.localIp isEqualToString:localIp]) {
return YES;
}
[self setDnsCacheInfo:cacheInfo];
return [self recoverDnsCache:cacheInfo.info];
}
/// DNS
- (void)localFetch{
if ([self prepareToPreFetch] == NO) {
return;
}
NSArray *hosts = [self getLocalPreHost];
@synchronized (self) {
[self.prefetchHosts addObjectsFromArray:hosts];
}
[self preFetchHosts:hosts];
[self recorderDnsCache];
[self endPreFetch];
}
//MARK: --
/// tokenDns YESNO
- (void)checkAndPrefetchDnsIfNeed:(QNConfiguration *)config zone:(QNZone *)currentZone token:(QNUpToken *)token{
if ([self prepareToPreFetch] == NO) {
return;
}
NSArray *hosts = [self getCurrentZoneHosts:config zone:currentZone token:token];
if (hosts == nil) {
return;
}
@synchronized (self) {
[self.prefetchHosts addObjectsFromArray:hosts];
}
[self preFetchHosts:hosts];
[self recorderDnsCache];
[self endPreFetch];
}
/// dns
- (void)checkWhetherCachedDnsValid{
if ([self prepareToPreFetch] == NO) {
return;
}
NSArray *hosts = nil;
@synchronized (self) {
hosts = [self.prefetchHosts allObjects];
}
[self preFetchHosts:hosts];
[self recorderDnsCache];
[self endPreFetch];
}
//MARK: -- DNS
/// hostDNS
- (NSArray <id <QNIDnsNetworkAddress> > *)getInetAddressByHost:(NSString *)host{
if ([self isDnsOpen] == NO) {
return nil;
}
[self clearDnsCacheIfNeeded];
NSArray <QNDnsNetworkAddress *> *addressList = nil;
@synchronized (self) {
addressList = self.addressDictionary[host];
}
if (addressList && addressList.count > 0 && [addressList.firstObject isValid]) {
return addressList;
} else {
return nil;
}
}
- (void)invalidNetworkAddressOfHost:(NSString *)host {
if (host == nil || host.length == 0) {
return;
}
@synchronized (self) {
[self.addressDictionary removeObjectForKey:host];
}
}
- (void)clearDnsCache:(NSError *__autoreleasing _Nullable *)error {
[self clearDnsMemoryCache];
[self clearDnsDiskCache:error];
}
//MARK: --
//MARK: -- dns
- (NSString *)prefetchHostBySafeDns:(NSString *)host error:(NSError * __autoreleasing *)error {
if (host == nil) {
return nil;
}
[self invalidNetworkAddressOfHost:host];
NSError *err = nil;
NSArray *nextFetchHosts = @[host];
nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:self.customDns error:&err];
if (nextFetchHosts.count == 0) {
return [self getInetAddressByHost:host].firstObject.sourceValue;
}
if (!kQNGlobalConfiguration.dohEnable) {
if (error != nil && err) {
*error = err;
}
return nil;
}
if (kQNGlobalConfiguration.dohIpv4Servers && [kQNGlobalConfiguration.dohIpv4Servers count] > 0) {
QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv4Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver];
nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:&err];
if (nextFetchHosts.count == 0) {
return [self getInetAddressByHost:host].firstObject.sourceValue;
}
if (error != nil && err) {
*error = err;
}
}
if ([QNIP isIpV6FullySupported] && kQNGlobalConfiguration.dohIpv6Servers && [kQNGlobalConfiguration.dohIpv6Servers count] > 0) {
QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv6Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver];
nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:&err];
if (error != nil && err) {
*error = err;
}
}
if (nextFetchHosts.count == 0) {
return [self getInetAddressByHost:host].firstObject.sourceValue;
} else {
return nil;
}
}
- (BOOL)prepareToPreFetch {
if ([self isDnsOpen] == NO) {
return NO;
}
self.lastPrefetchedErrorMessage = nil;
if (self.isPrefetching == YES) {
return NO;
}
[self clearDnsCacheIfNeeded];
self.isPrefetching = YES;
return YES;
}
- (void)endPreFetch{
self.isPrefetching = NO;
}
- (void)preFetchHosts:(NSArray <NSString *> *)fetchHosts {
NSError *err = nil;
[self preFetchHosts:fetchHosts error:&err];
self.lastPrefetchedErrorMessage = err.description;
}
- (void)preFetchHosts:(NSArray <NSString *> *)fetchHosts error:(NSError **)error {
NSArray *nextFetchHosts = fetchHosts;
//
nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:self.customDns error:error];
if (nextFetchHosts.count == 0) {
return;
}
//
nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:self.systemDns error:error];
if (nextFetchHosts.count == 0) {
return;
}
// doh
if (kQNGlobalConfiguration.dohEnable) {
if (kQNGlobalConfiguration.dohIpv4Servers && [kQNGlobalConfiguration.dohIpv4Servers count] > 0) {
QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv4Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver];
nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:error];
if (nextFetchHosts.count == 0) {
return;
}
}
if ([QNIP isIpV6FullySupported] && kQNGlobalConfiguration.dohIpv6Servers && [kQNGlobalConfiguration.dohIpv6Servers count] > 0) {
QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv6Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver];
nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:error];
if (nextFetchHosts.count == 0) {
return;
}
}
}
// udp
if (kQNGlobalConfiguration.udpDnsEnable) {
if (kQNGlobalConfiguration.udpDnsIpv4Servers && [kQNGlobalConfiguration.udpDnsIpv4Servers count] > 0) {
QNDnsUdpResolver *udpDnsResolver = [QNDnsUdpResolver resolverWithServerIPs:kQNGlobalConfiguration.udpDnsIpv4Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
QNInternalDns *udpDns = [QNInternalDns dnsWithResolver:udpDnsResolver];
[self preFetchHosts:nextFetchHosts dns:udpDns error:error];
}
if ([QNIP isIpV6FullySupported] && kQNGlobalConfiguration.udpDnsIpv6Servers && [kQNGlobalConfiguration.udpDnsIpv6Servers count] > 0) {
QNDnsUdpResolver *udpDnsResolver = [QNDnsUdpResolver resolverWithServerIPs:kQNGlobalConfiguration.udpDnsIpv6Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
QNInternalDns *udpDns = [QNInternalDns dnsWithResolver:udpDnsResolver];
[self preFetchHosts:nextFetchHosts dns:udpDns error:error];
}
}
}
- (NSArray *)preFetchHosts:(NSArray <NSString *> *)preHosts dns:(QNInternalDns *)dns error:(NSError **)error {
if (!preHosts || preHosts.count == 0) {
return nil;
}
if (!dns) {
return [preHosts copy];
}
int dnsRepreHostNum = kQNGlobalConfiguration.dnsRepreHostNum;
NSMutableArray *failHosts = [NSMutableArray array];
for (NSString *host in preHosts) {
int rePreNum = 0;
BOOL isSuccess = NO;
while (rePreNum < dnsRepreHostNum) {
if ([self preFetchHost:host dns:dns error:error]) {
isSuccess = YES;
break;
}
rePreNum += 1;
}
if (!isSuccess) {
[failHosts addObject:host];
}
}
return [failHosts copy];
}
- (BOOL)preFetchHost:(NSString *)preHost dns:(QNInternalDns *)dns error:(NSError **)error {
if (!preHost || preHost.length == 0) {
return NO;
}
NSDictionary *addressDictionary = nil;
@synchronized (self) {
addressDictionary = [self.addressDictionary copy];
}
NSArray<QNDnsNetworkAddress *>* preAddressList = addressDictionary[preHost];
if (preAddressList && ![preAddressList.firstObject needRefresh]) {
return YES;
}
NSArray <id <QNIDnsNetworkAddress> > * addressList = [dns query:preHost error:error];
if (addressList && addressList.count > 0) {
NSMutableArray *addressListP = [NSMutableArray array];
for (id <QNIDnsNetworkAddress>inetAddress in addressList) {
QNDnsNetworkAddress *address = [QNDnsNetworkAddress inetAddress:inetAddress];
if (address) {
address.hostValue = preHost;
if (!address.ttlValue) {
address.ttlValue = @(kQNDefaultDnsCacheTime);
}
if (!address.timestampValue) {
address.timestampValue = @([[NSDate date] timeIntervalSince1970]);
}
[addressListP addObject:address];
}
}
addressListP = [addressListP copy];
@synchronized (self) {
self.addressDictionary[preHost] = addressListP;
}
return YES;
} else {
return NO;
}
}
//MARK: --
- (BOOL)recoverDnsCache:(NSDictionary *)dataDic{
if (dataDic == nil) {
return NO;
}
NSMutableDictionary *records = [NSMutableDictionary dictionary];
for (NSString *key in dataDic.allKeys) {
NSArray *ips = dataDic[key];
if ([ips isKindOfClass:[NSArray class]]) {
NSMutableArray <QNDnsNetworkAddress *> * addressList = [NSMutableArray array];
for (NSDictionary *ipInfo in ips) {
if ([ipInfo isKindOfClass:[NSDictionary class]]) {
QNDnsNetworkAddress *address = [QNDnsNetworkAddress inetAddress:ipInfo];
if (address) {
[addressList addObject:address];
}
}
}
if (addressList.count > 0) {
records[key] = [addressList copy];
}
}
}
@synchronized (self) {
[self.addressDictionary setValuesForKeysWithDictionary:records];
}
return NO;
}
- (BOOL)recorderDnsCache{
NSTimeInterval currentTime = [QNUtils currentTimestamp];
NSString *localIp = [QNIP local];
if (localIp == nil || localIp.length == 0) {
return NO;
}
NSError *error;
id <QNRecorderDelegate> recorder = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir
error:&error];
if (error) {
return NO;
}
NSDictionary *addressDictionary = nil;
@synchronized (self) {
addressDictionary = [self.addressDictionary copy];
}
NSMutableDictionary *addressInfo = [NSMutableDictionary dictionary];
for (NSString *key in addressDictionary.allKeys) {
NSArray *addressModelList = addressDictionary[key];
NSMutableArray * addressDicList = [NSMutableArray array];
for (QNDnsNetworkAddress *ipInfo in addressModelList) {
NSDictionary *addressDic = [ipInfo toDictionary];
if (addressDic) {
[addressDicList addObject:addressDic];
}
}
if (addressDicList.count > 0) {
addressInfo[key] = addressDicList;
}
}
QNDnsCacheInfo *cacheInfo = [QNDnsCacheInfo dnsCacheInfo:[NSString stringWithFormat:@"%.0lf",currentTime]
localIp:localIp
info:addressInfo];
NSData *cacheData = [cacheInfo jsonData];
if (!cacheData) {
return NO;
}
[self setDnsCacheInfo:cacheInfo];
[recorder set:localIp data:cacheData];
return true;
}
- (void)clearDnsCacheIfNeeded{
NSString *localIp = [QNIP local];
if (localIp == nil || (self.dnsCacheInfo && ![localIp isEqualToString:self.dnsCacheInfo.localIp])) {
[self clearDnsMemoryCache];
}
}
- (void)clearDnsMemoryCache {
@synchronized (self) {
[self.addressDictionary removeAllObjects];
}
}
- (void)clearDnsDiskCache:(NSError **)error {
[self.diskCache clearCache:error];
}
//MARK: -- hosts
- (NSArray <NSString *> *)getLocalPreHost{
NSMutableArray *localHosts = [NSMutableArray array];
[localHosts addObject:kQNUpLogHost];
return [localHosts copy];
}
- (NSArray <NSString *> *)getCurrentZoneHosts:(QNConfiguration *)config
zone:(QNZone *)currentZone
token:(QNUpToken *)token{
if (!currentZone || !token || !token.token) {
return nil;
}
__block QNZonesInfo *zonesInfo = nil;
[currentZone query:config token:token on:^(QNResponseInfo * _Nullable httpResponseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, QNZonesInfo * _Nullable info) {
zonesInfo = info;
dispatch_semaphore_signal(self.semaphore);
}];
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
if (zonesInfo == nil) {
return nil;
}
QNZonesInfo *autoZonesInfo = [currentZone getZonesInfoWithToken:token];
NSMutableArray *autoHosts = [NSMutableArray array];
NSArray *zoneInfoList = autoZonesInfo.zonesInfo;
for (QNZoneInfo *info in zoneInfoList) {
if (info.allHosts) {
[autoHosts addObjectsFromArray:info.allHosts];
}
}
return [autoHosts copy];
}
//MARK: --
- (BOOL)isDnsOpen{
return [kQNGlobalConfiguration isDnsOpen];
}
- (QNDnsCacheInfo *)dnsCacheInfo{
if (_dnsCacheInfo == nil) {
_dnsCacheInfo = [[QNDnsCacheInfo alloc] init];
}
return _dnsCacheInfo;
}
- (NSMutableDictionary<NSString *,NSArray<QNDnsNetworkAddress *> *> *)addressDictionary{
if (_addressDictionary == nil) {
_addressDictionary = [NSMutableDictionary dictionary];
}
return _addressDictionary;
}
- (dispatch_semaphore_t)semaphore{
if (_getAutoZoneSemaphore == NULL) {
_getAutoZoneSemaphore = dispatch_semaphore_create(0);
}
return _getAutoZoneSemaphore;
}
- (QNDnsCacheFile *)diskCache {
if (!_diskCache) {
NSError *error;
QNDnsCacheFile *cache = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir error:&error];
if (!error) {
_diskCache = cache;
}
}
return _diskCache;
}
- (QNInternalDns *)customDns {
if (_customDns == nil && kQNGlobalConfiguration.dns) {
_customDns = [QNInternalDns dnsWithDns:kQNGlobalConfiguration.dns];
}
return _customDns;
}
- (QNInternalDns *)systemDns {
if (_systemDns == nil) {
_systemDns = [QNInternalDns dnsWithResolver:[[QNResolver alloc] initWithAddress:nil timeout:self.dnsPrefetchTimeout]];
}
return _systemDns;
}
- (NSMutableSet *)prefetchHosts {
if (!_prefetchHosts) {
_prefetchHosts = [NSMutableSet set];
}
return _prefetchHosts;
}
@end
//MARK: -- DNS
@implementation QNTransactionManager(Dns)
#define kQNLoadLocalDnsTransactionName @"QNLoadLocalDnsTransaction"
#define kQNDnsCheckAndPrefetchTransactionName @"QNDnsCheckAndPrefetchTransactionName"
- (void)addDnsLocalLoadTransaction{
if ([kQNDnsPrefetch isDnsOpen] == NO) {
return;
}
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
QNTransaction *transaction = [QNTransaction transaction:kQNLoadLocalDnsTransactionName after:0 action:^{
[kQNDnsPrefetch recoverCache];
[kQNDnsPrefetch localFetch];
}];
[[QNTransactionManager shared] addTransaction:transaction];
[self setDnsCheckWhetherCachedValidTransactionAction];
});
}
- (BOOL)addDnsCheckAndPrefetchTransaction:(QNZone *)currentZone token:(QNUpToken *)token {
return [self addDnsCheckAndPrefetchTransaction:[QNConfiguration defaultConfiguration] zone:currentZone token:token];
}
- (BOOL)addDnsCheckAndPrefetchTransaction:(QNConfiguration *)config zone:(QNZone *)currentZone token:(QNUpToken *)token {
if (!token) {
return NO;
}
if ([kQNDnsPrefetch isDnsOpen] == NO) {
return NO;
}
BOOL ret = NO;
@synchronized (kQNDnsPrefetch) {
QNTransactionManager *transactionManager = [QNTransactionManager shared];
if (![transactionManager existTransactionsForName:token.token]) {
QNTransaction *transaction = [QNTransaction transaction:token.token after:0 action:^{
[kQNDnsPrefetch checkAndPrefetchDnsIfNeed:config zone:currentZone token:token];
}];
[transactionManager addTransaction:transaction];
ret = YES;
}
}
return ret;
}
- (void)setDnsCheckWhetherCachedValidTransactionAction{
if ([kQNDnsPrefetch isDnsOpen] == NO) {
return;
}
@synchronized (kQNDnsPrefetch) {
QNTransactionManager *transactionManager = [QNTransactionManager shared];
QNTransaction *transaction = [transactionManager transactionsForName:kQNDnsCheckAndPrefetchTransactionName].firstObject;
if (!transaction) {
QNTransaction *transaction = [QNTransaction timeTransaction:kQNDnsCheckAndPrefetchTransactionName
after:10
interval:120
action:^{
[kQNDnsPrefetch checkWhetherCachedDnsValid];
}];
[transactionManager addTransaction:transaction];
} else {
[transactionManager performTransaction:transaction];
}
}
}
@end
BOOL kQNIsDnsSourceDoh(NSString * _Nullable source) {
return [source containsString:kQNDnsSourceDoh];
}
BOOL kQNIsDnsSourceUdp(NSString * _Nullable source) {
return [source containsString:kQNDnsSourceUdp];
}
BOOL kQNIsDnsSourceDnsPod(NSString * _Nullable source) {
return [source containsString:kQNDnsSourceDnspod];
}
BOOL kQNIsDnsSourceSystem(NSString * _Nullable source) {
return [source containsString:kQNDnsSourceSystem];
}
BOOL kQNIsDnsSourceCustom(NSString * _Nullable source) {
return [source containsString:kQNDnsSourceCustom];
}

View File

@@ -0,0 +1,37 @@
//
// QNInetAddress.h
// QiniuSDK
//
// Created by 杨森 on 2020/7/27.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "QNDns.h"
NS_ASSUME_NONNULL_BEGIN
@interface QNInetAddress : NSObject <QNIDnsNetworkAddress>
@property(nonatomic, copy)NSString *hostValue;
@property(nonatomic, copy)NSString *ipValue;
@property(nonatomic, strong)NSNumber *ttlValue;
@property(nonatomic, strong)NSNumber *timestampValue;
@property(nonatomic, copy)NSString *sourceValue;
/// 构造方法 addressData为json
/// @param addressInfo 地址信息类型可能为String / Dictionary / Data / 遵循 QNInetAddressDelegate的实例
+ (instancetype)inetAddress:(id)addressInfo;
/// 是否有效,根据时间戳判断
- (BOOL)isValid;
/// 对象转json
- (NSString *)toJsonInfo;
/// 对象转字典
- (NSDictionary *)toDictionary;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,95 @@
//
// QNInetAddress.m
// QiniuSDK
//
// Created by on 2020/7/27.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "QNInetAddress.h"
@interface QNInetAddress()
@end
@implementation QNInetAddress
+ (instancetype)inetAddress:(id)addressInfo{
NSDictionary *addressDic = nil;
if ([addressInfo isKindOfClass:[NSDictionary class]]) {
addressDic = (NSDictionary *)addressInfo;
} else if ([addressInfo isKindOfClass:[NSString class]]){
NSData *data = [(NSString *)addressInfo dataUsingEncoding:NSUTF8StringEncoding];
addressDic = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableLeaves
error:nil];
} else if ([addressInfo isKindOfClass:[NSData class]]) {
addressDic = [NSJSONSerialization JSONObjectWithData:(NSData *)addressInfo
options:NSJSONReadingMutableLeaves
error:nil];
} else if ([addressInfo conformsToProtocol:@protocol(QNIDnsNetworkAddress)]){
id <QNIDnsNetworkAddress> address = (id <QNIDnsNetworkAddress> )addressInfo;
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
if ([address respondsToSelector:@selector(hostValue)] && [address hostValue]) {
dic[@"hostValue"] = [address hostValue];
}
if ([address respondsToSelector:@selector(ipValue)] && [address ipValue]) {
dic[@"ipValue"] = [address ipValue];
}
if ([address respondsToSelector:@selector(ttlValue)] && [address ttlValue]) {
dic[@"ttlValue"] = [address ttlValue];
}
if ([address respondsToSelector:@selector(timestampValue)] && [address timestampValue]) {
dic[@"timestampValue"] = [address timestampValue];
}
addressDic = [dic copy];
}
if (addressDic) {
QNInetAddress *address = [[QNInetAddress alloc] init];
[address setValuesForKeysWithDictionary:addressDic];
return address;
} else {
return nil;
}
}
- (BOOL)isValid{
if (!self.timestampValue || !self.ipValue || self.ipValue.length == 0) {
return NO;
}
NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970];
if (currentTimestamp > self.timestampValue.doubleValue + self.ttlValue.doubleValue) {
return NO;
} else {
return YES;
}
}
- (NSString *)toJsonInfo{
NSString *defaultString = @"{}";
NSDictionary *infoDic = [self toDictionary];
if (!infoDic) {
return defaultString;
}
NSData *infoData = [NSJSONSerialization dataWithJSONObject:infoDic
options:NSJSONWritingPrettyPrinted
error:nil];
if (!infoData) {
return defaultString;
}
NSString *infoStr = [[NSString alloc] initWithData:infoData encoding:NSUTF8StringEncoding];
if (!infoStr) {
return defaultString;
} else {
return infoStr;
}
}
- (NSDictionary *)toDictionary{
return [self dictionaryWithValuesForKeys:@[@"ipValue", @"hostValue", @"ttlValue", @"timestampValue"]];
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{}
@end