123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- //
- // QNAutoZone.m
- // QiniuSDK
- //
- // Created by yangsen on 2020/4/16.
- // Copyright © 2020 Qiniu. All rights reserved.
- //
- #import "QNDefine.h"
- #import "QNAutoZone.h"
- #import "QNConfig.h"
- #import "QNRequestTransaction.h"
- #import "QNZoneInfo.h"
- #import "QNUpToken.h"
- #import "QNResponseInfo.h"
- #import "QNFixedZone.h"
- #import "QNSingleFlight.h"
- @interface QNAutoZoneCache : NSObject
- @property(nonatomic, strong)NSMutableDictionary *cache;
- @end
- @implementation QNAutoZoneCache
- + (instancetype)share{
- static QNAutoZoneCache *cache = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- cache = [[QNAutoZoneCache alloc] init];
- [cache setupData];
- });
- return cache;
- }
- - (void)setupData{
- self.cache = [NSMutableDictionary dictionary];
- }
- - (void)cache:(NSDictionary *)zonesInfo forKey:(NSString *)cacheKey{
-
- if (!cacheKey || [cacheKey isEqualToString:@""]) {
- return;
- }
-
- @synchronized (self) {
- if (zonesInfo) {
- self.cache[cacheKey] = zonesInfo;
- } else {
- [self.cache removeObjectForKey:cacheKey];
- }
- }
- }
- - (QNZonesInfo *)zonesInfoForKey:(NSString *)cacheKey{
-
- if (!cacheKey || [cacheKey isEqualToString:@""]) {
- return nil;
- }
-
- NSDictionary *zonesInfoDic = nil;
- @synchronized (self) {
- zonesInfoDic = self.cache[cacheKey];
- }
-
- if (zonesInfoDic == nil) {
- return nil;
- }
-
- return [QNZonesInfo infoWithDictionary:zonesInfoDic];
- }
- @end
- @interface QNUCQuerySingleFlightValue : NSObject
- @property(nonatomic, strong)QNResponseInfo *responseInfo;
- @property(nonatomic, strong)NSDictionary *response;
- @property(nonatomic, strong)QNUploadRegionRequestMetrics *metrics;
- @end
- @implementation QNUCQuerySingleFlightValue
- @end
- @interface QNAutoZone()
- @property(nonatomic, strong)NSMutableDictionary *cache;
- @property(nonatomic, strong)NSLock *lock;
- @property(nonatomic, strong)NSMutableArray <QNRequestTransaction *> *transactions;
- @end
- @implementation QNAutoZone
- + (QNSingleFlight *)UCQuerySingleFlight {
- static QNSingleFlight *singleFlight = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- singleFlight = [[QNSingleFlight alloc] init];
- });
- return singleFlight;
- }
- - (instancetype)init{
- if (self = [super init]) {
- _cache = [NSMutableDictionary new];
- _lock = [NSLock new];
- _transactions = [NSMutableArray array];
- }
- return self;
- }
- - (QNZonesInfo *)getZonesInfoWithToken:(QNUpToken *)token {
- if (token == nil) return nil;
- [self.lock lock];
- QNZonesInfo *zonesInfo = [_cache objectForKey:[token index]];
- [self.lock unlock];
- return zonesInfo;
- }
- - (void)preQuery:(QNUpToken *)token
- on:(QNPrequeryReturn)ret {
-
- if (token == nil || ![token isValid]) {
- ret(-1, [QNResponseInfo responseInfoWithInvalidToken:@"invalid token"], nil);
- return;
- }
-
- NSString *cacheKey = token.index;
-
- [_lock lock];
- QNZonesInfo *zonesInfo = [_cache objectForKey:cacheKey];
- [_lock unlock];
-
- if (zonesInfo == nil) {
- zonesInfo = [[QNAutoZoneCache share] zonesInfoForKey:cacheKey];
- if (zonesInfo && zonesInfo.isValid) {
- [self.lock lock];
- [self.cache setValue:zonesInfo forKey:cacheKey];
- [self.lock unlock];
- }
- }
-
- if (zonesInfo != nil && zonesInfo.isValid) {
- ret(0, [QNResponseInfo successResponse], nil);
- return;
- }
-
- kQNWeakSelf;
- QNSingleFlight *singleFlight = [QNAutoZone UCQuerySingleFlight];
- [singleFlight perform:token.index action:^(QNSingleFlightComplete _Nonnull complete) {
- kQNStrongSelf;
- QNRequestTransaction *transaction = [self createUploadRequestTransaction:token];
-
- kQNWeakSelf;
- kQNWeakObj(transaction);
- [transaction queryUploadHosts:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
- kQNStrongSelf;
- kQNStrongObj(transaction);
-
- QNUCQuerySingleFlightValue *value = [[QNUCQuerySingleFlightValue alloc] init];
- value.responseInfo = responseInfo;
- value.response = response;
- value.metrics = metrics;
- complete(value, nil);
-
- [self destroyUploadRequestTransaction:transaction];
- }];
-
- } complete:^(id _Nullable value, NSError * _Nullable error) {
- kQNStrongSelf;
-
- QNResponseInfo *responseInfo = [(QNUCQuerySingleFlightValue *)value responseInfo];
- NSDictionary *response = [(QNUCQuerySingleFlightValue *)value response];
- QNUploadRegionRequestMetrics *metrics = [(QNUCQuerySingleFlightValue *)value metrics];
- if (responseInfo && responseInfo.isOK) {
- QNZonesInfo *zonesInfo = [QNZonesInfo infoWithDictionary:response];
- [self.lock lock];
- [self.cache setValue:zonesInfo forKey:cacheKey];
- [self.lock unlock];
- [[QNAutoZoneCache share] cache:response forKey:cacheKey];
- ret(0, responseInfo, metrics);
- } else {
- if (responseInfo.isConnectionBroken) {
- ret(kQNNetworkError, responseInfo, metrics);
- } else {
- QNZonesInfo *zonesInfo = [[QNFixedZone localsZoneInfo] getZonesInfoWithToken:token];
- [self.lock lock];
- [self.cache setValue:zonesInfo forKey:cacheKey];
- [self.lock unlock];
- ret(0, responseInfo, metrics);
- }
- }
- }];
- }
- - (QNRequestTransaction *)createUploadRequestTransaction:(QNUpToken *)token{
-
- QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithHosts:@[kQNPreQueryHost00, kQNPreQueryHost01]
- regionId:QNZoneInfoEmptyRegionId
- token:token];
- [self.lock lock];
- [self.transactions addObject:transaction];
- [self.lock unlock];
- return transaction;
- }
- - (void)destroyUploadRequestTransaction:(QNRequestTransaction *)transaction{
- if (transaction) {
- [self.lock lock];
- [self.transactions removeObject:transaction];
- [self.lock unlock];
- }
- }
- @end
|