QNDnsPrefetch.m 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. //
  2. // QNDnsPrefetch.m
  3. // QnDNS
  4. //
  5. // Created by yangsen on 2020/3/26.
  6. // Copyright © 2020 com.qiniu. All rights reserved.
  7. //
  8. #import "QNDnsPrefetch.h"
  9. #import "QNInetAddress.h"
  10. #import "QNDnsCacheInfo.h"
  11. #import "QNZoneInfo.h"
  12. #import "QNDefine.h"
  13. #import "QNConfig.h"
  14. #import "QNDnsCacheFile.h"
  15. #import "QNUtils.h"
  16. #import "QNAsyncRun.h"
  17. #import "QNFixedZone.h"
  18. #import "QNAutoZone.h"
  19. #import <HappyDNS/HappyDNS.h>
  20. //MARK: -- 缓存模型
  21. @interface QNDnsNetworkAddress : NSObject<QNIDnsNetworkAddress>
  22. @property(nonatomic, copy)NSString *hostValue;
  23. @property(nonatomic, copy)NSString *ipValue;
  24. @property(nonatomic, strong)NSNumber *ttlValue;
  25. @property(nonatomic, copy)NSString *sourceValue;
  26. @property(nonatomic, strong)NSNumber *timestampValue;
  27. /// 构造方法 addressData为json String / Dictionary / Data / 遵循 QNIDnsNetworkAddress的实例
  28. + (instancetype)inetAddress:(id)addressInfo;
  29. /// 是否有效,根据时间戳判断
  30. - (BOOL)isValid;
  31. /// 对象转json
  32. - (NSString *)toJsonInfo;
  33. /// 对象转字典
  34. - (NSDictionary *)toDictionary;
  35. @end
  36. @implementation QNDnsNetworkAddress
  37. + (instancetype)inetAddress:(id)addressInfo{
  38. NSDictionary *addressDic = nil;
  39. if ([addressInfo isKindOfClass:[NSDictionary class]]) {
  40. addressDic = (NSDictionary *)addressInfo;
  41. } else if ([addressInfo isKindOfClass:[NSString class]]){
  42. NSData *data = [(NSString *)addressInfo dataUsingEncoding:NSUTF8StringEncoding];
  43. addressDic = [NSJSONSerialization JSONObjectWithData:data
  44. options:NSJSONReadingMutableLeaves
  45. error:nil];
  46. } else if ([addressInfo isKindOfClass:[NSData class]]) {
  47. addressDic = [NSJSONSerialization JSONObjectWithData:(NSData *)addressInfo
  48. options:NSJSONReadingMutableLeaves
  49. error:nil];
  50. } else if ([addressInfo conformsToProtocol:@protocol(QNIDnsNetworkAddress)]){
  51. id <QNIDnsNetworkAddress> address = (id <QNIDnsNetworkAddress> )addressInfo;
  52. NSMutableDictionary *dic = [NSMutableDictionary dictionary];
  53. if ([address respondsToSelector:@selector(hostValue)] && [address hostValue]) {
  54. dic[@"hostValue"] = [address hostValue];
  55. }
  56. if ([address respondsToSelector:@selector(ipValue)] && [address ipValue]) {
  57. dic[@"ipValue"] = [address ipValue];
  58. }
  59. if ([address respondsToSelector:@selector(ttlValue)] && [address ttlValue]) {
  60. dic[@"ttlValue"] = [address ttlValue];
  61. }
  62. if ([address respondsToSelector:@selector(source)] && [address sourceValue]) {
  63. dic[@"sourceValue"] = [address sourceValue];
  64. }
  65. if ([address respondsToSelector:@selector(timestampValue)] && [address timestampValue]) {
  66. dic[@"timestampValue"] = [address timestampValue];
  67. }
  68. addressDic = [dic copy];
  69. }
  70. if (addressDic) {
  71. QNDnsNetworkAddress *address = [[QNDnsNetworkAddress alloc] init];
  72. [address setValuesForKeysWithDictionary:addressDic];
  73. return address;
  74. } else {
  75. return nil;
  76. }
  77. }
  78. - (BOOL)isValid{
  79. if (!self.timestampValue || !self.ipValue || self.ipValue.length == 0) {
  80. return NO;
  81. }
  82. NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970];
  83. return currentTimestamp > self.timestampValue.doubleValue + self.ttlValue.doubleValue;
  84. }
  85. - (NSString *)toJsonInfo{
  86. NSString *defaultString = @"{}";
  87. NSDictionary *infoDic = [self toDictionary];
  88. if (!infoDic) {
  89. return defaultString;
  90. }
  91. NSData *infoData = [NSJSONSerialization dataWithJSONObject:infoDic
  92. options:NSJSONWritingPrettyPrinted
  93. error:nil];
  94. if (!infoData) {
  95. return defaultString;
  96. }
  97. NSString *infoStr = [[NSString alloc] initWithData:infoData encoding:NSUTF8StringEncoding];
  98. if (!infoStr) {
  99. return defaultString;
  100. } else {
  101. return infoStr;
  102. }
  103. }
  104. - (NSDictionary *)toDictionary{
  105. return [self dictionaryWithValuesForKeys:@[@"ipValue", @"hostValue", @"ttlValue", @"sourceValue", @"timestampValue"]];
  106. }
  107. - (void)setValue:(id)value forUndefinedKey:(NSString *)key{}
  108. @end
  109. //MARK: -- HappyDNS 适配
  110. @interface QNRecord(DNS)<QNIDnsNetworkAddress>
  111. @end
  112. @implementation QNRecord(DNS)
  113. - (NSString *)hostValue{
  114. return nil;
  115. }
  116. - (NSString *)ipValue{
  117. return self.value;
  118. }
  119. - (NSNumber *)ttlValue{
  120. return @(self.ttl);
  121. }
  122. - (NSNumber *)timestampValue{
  123. return @(self.timeStamp);
  124. }
  125. - (NSString *)sourceValue{
  126. if (self.source == QNRecordSourceSystem) {
  127. return @"system";
  128. } else if (self.source == QNRecordSourceDnspodFree || self.source == QNRecordSourceDnspodEnterprise) {
  129. return @"httpdns";
  130. } else {
  131. return @"none";
  132. }
  133. }
  134. @end
  135. @interface QNDnsManager(DNS)<QNDnsDelegate>
  136. @end
  137. @implementation QNDnsManager(DNS)
  138. - (NSArray<id<QNIDnsNetworkAddress>> *)lookup:(NSString *)host{
  139. return [self queryRecords:host];
  140. }
  141. @end
  142. //MARK: -- DNS Prefetcher
  143. @interface QNDnsPrefetch()
  144. // 最近一次预取错误信息
  145. @property(nonatomic, copy)NSString *lastPrefetchedErrorMessage;
  146. /// 是否正在预取,正在预取会直接取消新的预取操作请求
  147. @property(atomic, assign)BOOL isPrefetching;
  148. /// 获取AutoZone时的同步锁
  149. @property(nonatomic, strong)dispatch_semaphore_t getAutoZoneSemaphore;
  150. /// DNS信息本地缓存key
  151. @property(nonatomic, strong)QNDnsCacheInfo *dnsCacheInfo;
  152. /// happy的dns解析对象列表,会使用多个dns解析对象 包括系统解析
  153. @property(nonatomic, strong)QNDnsManager * httpDns;
  154. /// 缓存DNS解析结果
  155. /// 线程安全:内部方法均是在同一线程执行,读写不必加锁,对外开放接口读操作 需要和内部写操作枷锁
  156. @property(nonatomic, strong)NSMutableDictionary <NSString *, NSArray<QNDnsNetworkAddress *>*> *addressDictionary;
  157. @end
  158. @implementation QNDnsPrefetch
  159. + (instancetype)shared{
  160. static QNDnsPrefetch *prefetcher = nil;
  161. static dispatch_once_t onceToken;
  162. dispatch_once(&onceToken, ^{
  163. prefetcher = [[QNDnsPrefetch alloc] init];
  164. });
  165. return prefetcher;
  166. }
  167. - (instancetype)init{
  168. if (self = [super init]) {
  169. _isPrefetching = NO;
  170. }
  171. return self;
  172. }
  173. //MARK: -- uploadManager初始化时,加载本地缓存到内存
  174. /// 同步本地预取缓存 如果存在且满足使用返回false,反之为true
  175. - (BOOL)recoverCache{
  176. id <QNRecorderDelegate> recorder = nil;
  177. NSError *error;
  178. recorder = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir
  179. error:&error];
  180. if (error) {
  181. return YES;
  182. }
  183. NSData *data = [recorder get:[QNIP local]];
  184. if (!data) {
  185. return YES;
  186. }
  187. QNDnsCacheInfo *cacheInfo = [QNDnsCacheInfo dnsCacheInfo:data];
  188. if (!cacheInfo) {
  189. return YES;
  190. }
  191. NSString *localIp = [QNIP local];
  192. if (!localIp || localIp.length == 0 || ![cacheInfo.localIp isEqualToString:localIp]) {
  193. return YES;
  194. }
  195. [self setDnsCacheInfo:cacheInfo];
  196. return [self recoverDnsCache:cacheInfo.info];
  197. }
  198. /// 本地缓存读取失败后,加载本地域名,预取DNS解析信息
  199. - (void)localFetch{
  200. if ([self prepareToPreFetch] == NO) {
  201. return;
  202. }
  203. [self preFetchHosts:[self getLocalPreHost]];
  204. [self recorderDnsCache];
  205. [self endPreFetch];
  206. }
  207. //MARK: -- 检测并预取
  208. /// 根据token检测Dns缓存信息时效,无效则预取。 完成预取操作返回YES,反之返回NO
  209. - (void)checkAndPrefetchDnsIfNeed:(QNZone *)currentZone token:(QNUpToken *)token{
  210. if ([self prepareToPreFetch] == NO) {
  211. return;
  212. }
  213. [self preFetchHosts:[self getCurrentZoneHosts:currentZone token:token]];
  214. [self recorderDnsCache];
  215. [self endPreFetch];
  216. }
  217. /// 检测已预取dns是否还有效,无效则重新预取
  218. - (void)checkWhetherCachedDnsValid{
  219. if ([self prepareToPreFetch] == NO) {
  220. return;
  221. }
  222. [self preFetchHosts:[self.addressDictionary allKeys]];
  223. [self recorderDnsCache];
  224. [self endPreFetch];
  225. }
  226. //MARK: -- 读取缓存的DNS信息
  227. /// 根据host从缓存中读取DNS信息
  228. - (NSArray <id <QNIDnsNetworkAddress> > *)getInetAddressByHost:(NSString *)host{
  229. if ([self isDnsOpen] == NO) {
  230. return nil;
  231. }
  232. NSArray <QNDnsNetworkAddress *> *addressList = nil;
  233. @synchronized (self) {
  234. addressList = self.addressDictionary[host];
  235. }
  236. if (![addressList.firstObject isValid]) {
  237. QNAsyncRun(^{
  238. [[QNTransactionManager shared] setDnsCheckWhetherCachedValidTransactionAction];
  239. });
  240. }
  241. return addressList;
  242. }
  243. //MARK: --
  244. //MARK: -- 根据dns预取
  245. - (BOOL)prepareToPreFetch{
  246. if ([self isDnsOpen] == NO) {
  247. return NO;
  248. }
  249. self.lastPrefetchedErrorMessage = nil;
  250. if (self.isPrefetching == YES) {
  251. return NO;
  252. }
  253. NSString *localIp = [QNIP local];
  254. if (localIp == nil ||
  255. (self.dnsCacheInfo && ![localIp isEqualToString:self.dnsCacheInfo.localIp])) {
  256. [self clearPreHosts];
  257. }
  258. self.isPrefetching = YES;
  259. return YES;
  260. }
  261. - (void)endPreFetch{
  262. self.isPrefetching = NO;
  263. }
  264. - (void)preFetchHosts:(NSArray <NSString *> *)fetchHosts{
  265. self.httpDns.defaultTtl = kQNGlobalConfiguration.dnsCacheTime;
  266. NSArray *nextFetchHosts = fetchHosts;
  267. nextFetchHosts = [self preFetchHosts:nextFetchHosts
  268. dns:kQNGlobalConfiguration.dns];
  269. nextFetchHosts = [self preFetchHosts:nextFetchHosts
  270. dns:self.httpDns];
  271. }
  272. - (NSArray *)preFetchHosts:(NSArray <NSString *> *)preHosts
  273. dns:(id <QNDnsDelegate>)dns{
  274. if (!preHosts || preHosts.count == 0) {
  275. return nil;
  276. }
  277. if (!dns) {
  278. return [preHosts copy];
  279. }
  280. NSMutableArray *failHosts = [NSMutableArray array];
  281. for (NSString *host in preHosts) {
  282. int rePreNum = 0;
  283. BOOL isSuccess = NO;
  284. while (rePreNum < kQNGlobalConfiguration.dnsRepreHostNum) {
  285. if ([self preFetchHost:host dns:dns]) {
  286. isSuccess = YES;
  287. break;
  288. }
  289. rePreNum += 1;
  290. }
  291. if (!isSuccess) {
  292. [failHosts addObject:host];
  293. }
  294. }
  295. return [failHosts copy];
  296. }
  297. - (BOOL)preFetchHost:(NSString *)preHost
  298. dns:(id <QNDnsDelegate>)dns{
  299. if (!preHost || preHost.length == 0) {
  300. return NO;
  301. }
  302. NSArray<QNDnsNetworkAddress *>* preAddressList = self.addressDictionary[preHost];
  303. if (preAddressList && [preAddressList.firstObject isValid]) {
  304. return YES;
  305. }
  306. NSArray <id <QNIDnsNetworkAddress> > * addressList = [dns lookup:preHost];
  307. if (addressList && addressList.count > 0) {
  308. NSMutableArray *addressListP = [NSMutableArray array];
  309. for (id <QNIDnsNetworkAddress>inetAddress in addressList) {
  310. QNDnsNetworkAddress *address = [QNDnsNetworkAddress inetAddress:inetAddress];
  311. if (address) {
  312. if (dns == kQNGlobalConfiguration.dns) {
  313. address.sourceValue = @"customized";
  314. }
  315. address.hostValue = preHost;
  316. if (!address.ttlValue) {
  317. address.ttlValue = @(kQNDefaultDnsCacheTime);
  318. }
  319. if (!address.timestampValue) {
  320. address.timestampValue = @([[NSDate date] timeIntervalSince1970]);
  321. }
  322. [addressListP addObject:address];
  323. }
  324. }
  325. addressListP = [addressListP copy];
  326. @synchronized (self) {
  327. self.addressDictionary[preHost] = addressListP;
  328. }
  329. return YES;
  330. } else {
  331. return NO;
  332. }
  333. }
  334. //MARK: -- 加载和存储缓存信息
  335. - (BOOL)recoverDnsCache:(NSDictionary *)dataDic{
  336. if (dataDic == nil) {
  337. return NO;
  338. }
  339. NSMutableDictionary *newAddressDictionary = [NSMutableDictionary dictionary];
  340. for (NSString *key in dataDic.allKeys) {
  341. NSArray *ips = dataDic[key];
  342. if ([ips isKindOfClass:[NSArray class]]) {
  343. NSMutableArray <QNDnsNetworkAddress *> * addressList = [NSMutableArray array];
  344. for (NSDictionary *ipInfo in ips) {
  345. if ([ipInfo isKindOfClass:[NSDictionary class]]) {
  346. QNDnsNetworkAddress *address = [QNDnsNetworkAddress inetAddress:ipInfo];
  347. if (address) {
  348. [addressList addObject:address];
  349. }
  350. }
  351. }
  352. if (addressList.count > 0) {
  353. newAddressDictionary[key] = [addressList copy];
  354. }
  355. }
  356. }
  357. @synchronized (self) {
  358. self.addressDictionary = newAddressDictionary;
  359. }
  360. return NO;
  361. }
  362. - (BOOL)recorderDnsCache{
  363. NSTimeInterval currentTime = [QNUtils currentTimestamp];
  364. NSString *localIp = [QNIP local];
  365. if (localIp == nil || localIp.length == 0) {
  366. return NO;
  367. }
  368. NSError *error;
  369. id <QNRecorderDelegate> recorder = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir
  370. error:&error];
  371. if (error) {
  372. return NO;
  373. }
  374. NSMutableDictionary *addressInfo = [NSMutableDictionary dictionary];
  375. for (NSString *key in self.addressDictionary.allKeys) {
  376. NSArray *addressModelList = self.addressDictionary[key];
  377. NSMutableArray * addressDicList = [NSMutableArray array];
  378. for (QNDnsNetworkAddress *ipInfo in addressModelList) {
  379. NSDictionary *addressDic = [ipInfo toDictionary];
  380. if (addressDic) {
  381. [addressDicList addObject:addressDic];
  382. }
  383. }
  384. if (addressDicList.count > 0) {
  385. addressInfo[key] = addressDicList;
  386. }
  387. }
  388. QNDnsCacheInfo *cacheInfo = [QNDnsCacheInfo dnsCacheInfo:[NSString stringWithFormat:@"%.0lf",currentTime]
  389. localIp:localIp
  390. info:addressInfo];
  391. NSData *cacheData = [cacheInfo jsonData];
  392. if (!cacheData) {
  393. return NO;
  394. }
  395. [self setDnsCacheInfo:cacheInfo];
  396. [recorder set:localIp data:cacheData];
  397. return true;
  398. }
  399. - (void)clearPreHosts{
  400. @synchronized (self) {
  401. [self.addressDictionary removeAllObjects];
  402. }
  403. }
  404. //MARK: -- 获取预取hosts
  405. - (NSArray <NSString *> *)getLocalPreHost{
  406. NSMutableArray *localHosts = [NSMutableArray array];
  407. NSArray *fixedHosts = [self getFixedZoneHosts];
  408. [localHosts addObjectsFromArray:fixedHosts];
  409. [localHosts addObject:kQNPreQueryHost00];
  410. [localHosts addObject:kQNPreQueryHost01];
  411. return [localHosts copy];
  412. }
  413. - (NSArray <NSString *> *)getAllPreHost:(QNZone *)currentZone
  414. token:(QNUpToken *)token{
  415. NSMutableSet *set = [NSMutableSet set];
  416. NSMutableArray *fetchHosts = [NSMutableArray array];
  417. NSArray *fixedHosts = [self getFixedZoneHosts];
  418. [fetchHosts addObjectsFromArray:fixedHosts];
  419. NSArray *autoHosts = [self getCurrentZoneHosts:currentZone token:token];
  420. [fetchHosts addObjectsFromArray:autoHosts];
  421. [fetchHosts addObject:kQNPreQueryHost00];
  422. [fetchHosts addObject:kQNPreQueryHost01];
  423. NSArray *cacheHost = [self getCacheHosts];
  424. [fetchHosts addObjectsFromArray:cacheHost];
  425. NSMutableArray *fetchHostsFiltered = [NSMutableArray array];
  426. for (NSString *host in fetchHosts) {
  427. NSInteger countBeforeAdd = set.count;
  428. [set addObject:host];
  429. NSInteger countAfterAdd = set.count;
  430. if (countBeforeAdd < countAfterAdd) {
  431. [fetchHostsFiltered addObject:host];
  432. }
  433. }
  434. return [fetchHostsFiltered copy];
  435. }
  436. - (NSArray <NSString *> *)getCurrentZoneHosts:(QNZone *)currentZone
  437. token:(QNUpToken *)token{
  438. if (!currentZone || !token || !token.token) {
  439. return nil;
  440. }
  441. [currentZone preQuery:token on:^(int code, QNResponseInfo *responseInfo, QNUploadRegionRequestMetrics *metrics) {
  442. dispatch_semaphore_signal(self.semaphore);
  443. }];
  444. dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
  445. QNZonesInfo *autoZonesInfo = [currentZone getZonesInfoWithToken:token];
  446. NSMutableArray *autoHosts = [NSMutableArray array];
  447. NSArray *zoneInfoList = autoZonesInfo.zonesInfo;
  448. for (QNZoneInfo *info in zoneInfoList) {
  449. if (info.allHosts) {
  450. [autoHosts addObjectsFromArray:info.allHosts];
  451. }
  452. }
  453. return [autoHosts copy];
  454. }
  455. - (NSArray <NSString *> *)getFixedZoneHosts{
  456. NSMutableArray *localHosts = [NSMutableArray array];
  457. QNFixedZone *fixedZone = [QNFixedZone localsZoneInfo];
  458. QNZonesInfo *zonesInfo = [fixedZone getZonesInfoWithToken:nil];
  459. for (QNZoneInfo *zoneInfo in zonesInfo.zonesInfo) {
  460. if (zoneInfo.allHosts) {
  461. [localHosts addObjectsFromArray:zoneInfo.allHosts];
  462. }
  463. }
  464. return [localHosts copy];
  465. }
  466. - (NSArray <NSString *> *)getCacheHosts{
  467. return self.addressDictionary.allKeys;
  468. }
  469. //MARK: --
  470. - (BOOL)isDnsOpen{
  471. return [kQNGlobalConfiguration isDnsOpen];
  472. }
  473. - (QNDnsCacheInfo *)dnsCacheInfo{
  474. if (_dnsCacheInfo == nil) {
  475. _dnsCacheInfo = [[QNDnsCacheInfo alloc] init];
  476. }
  477. return _dnsCacheInfo;
  478. }
  479. - (NSMutableDictionary<NSString *,NSArray<QNDnsNetworkAddress *> *> *)addressDictionary{
  480. if (_addressDictionary == nil) {
  481. _addressDictionary = [NSMutableDictionary dictionary];
  482. }
  483. return _addressDictionary;
  484. }
  485. - (dispatch_semaphore_t)semaphore{
  486. if (_getAutoZoneSemaphore == NULL) {
  487. _getAutoZoneSemaphore = dispatch_semaphore_create(0);
  488. }
  489. return _getAutoZoneSemaphore;
  490. }
  491. - (QNDnsManager *)httpDns{
  492. if (_httpDns == nil) {
  493. QNResolver *systemDnsresolver = [QNResolver systemResolver];
  494. QNDnspodFree *dnspodFree = [[QNDnspodFree alloc] init];
  495. QNDnsManager *httpDns = [[QNDnsManager alloc] init:@[systemDnsresolver, dnspodFree]
  496. networkInfo:nil];
  497. kQNWeakSelf;
  498. httpDns.queryErrorHandler = ^(NSError *error, NSString *host) {
  499. kQNStrongSelf;
  500. self.lastPrefetchedErrorMessage = [error localizedDescription];
  501. };
  502. _httpDns = httpDns;
  503. }
  504. return _httpDns;
  505. }
  506. @end
  507. //MARK: -- DNS 事务
  508. @implementation QNTransactionManager(Dns)
  509. #define kQNLoadLocalDnsTransactionName @"QNLoadLocalDnsTransaction"
  510. #define kQNDnsCheckAndPrefetchTransactionName @"QNDnsCheckAndPrefetchTransactionName"
  511. - (void)addDnsLocalLoadTransaction{
  512. if ([kQNDnsPrefetch isDnsOpen] == NO) {
  513. return;
  514. }
  515. static dispatch_once_t onceToken;
  516. dispatch_once(&onceToken, ^{
  517. QNTransaction *transaction = [QNTransaction transaction:kQNLoadLocalDnsTransactionName after:0 action:^{
  518. [kQNDnsPrefetch recoverCache];
  519. [kQNDnsPrefetch localFetch];
  520. }];
  521. [[QNTransactionManager shared] addTransaction:transaction];
  522. });
  523. }
  524. - (BOOL)addDnsCheckAndPrefetchTransaction:(QNZone *)currentZone token:(QNUpToken *)token{
  525. if (!token) {
  526. return NO;
  527. }
  528. if ([kQNDnsPrefetch isDnsOpen] == NO) {
  529. return NO;
  530. }
  531. BOOL ret = NO;
  532. @synchronized (kQNDnsPrefetch) {
  533. QNTransactionManager *transactionManager = [QNTransactionManager shared];
  534. if (![transactionManager existTransactionsForName:token.token]) {
  535. QNTransaction *transaction = [QNTransaction transaction:token.token after:0 action:^{
  536. [kQNDnsPrefetch checkAndPrefetchDnsIfNeed:currentZone token:token];
  537. }];
  538. [transactionManager addTransaction:transaction];
  539. ret = YES;
  540. }
  541. }
  542. return ret;
  543. }
  544. - (void)setDnsCheckWhetherCachedValidTransactionAction{
  545. if ([kQNDnsPrefetch isDnsOpen] == NO) {
  546. return;
  547. }
  548. @synchronized (kQNDnsPrefetch) {
  549. QNTransactionManager *transactionManager = [QNTransactionManager shared];
  550. QNTransaction *transaction = [transactionManager transactionsForName:kQNDnsCheckAndPrefetchTransactionName].firstObject;
  551. if (!transaction) {
  552. QNTransaction *transaction = [QNTransaction timeTransaction:kQNDnsCheckAndPrefetchTransactionName
  553. after:10
  554. interval:120
  555. action:^{
  556. [kQNDnsPrefetch checkWhetherCachedDnsValid];
  557. }];
  558. [transactionManager addTransaction:transaction];
  559. } else {
  560. [transactionManager performTransaction:transaction];
  561. }
  562. }
  563. }
  564. @end