Commit 9c7f79da by zhangyunjie

重编译七牛SDK

parent 925afddc
//
//
......@@ -63,7 +63,7 @@ typedef void(^OffcnSDKReachabilityStatusCallBack)(OffcnSDKReachabilityStatus sta
/// @param text 文本
/// @param filePath 图片/音频(语音消息格式,只能是aac格式)/视频/文件,沙盒路径
/// @param finished 结果回调
-(void)sendMsgWithMsg_fromID:(NSString *)msg_fromID msg_toID:(NSString *)msg_toID msg_type:(OffcnSDKMsgType)msg_type text:(NSString *)text filePath:(NSString *)filePath Finished:(void(^)(BOOL success,OffcnIMSendMsgModel *sendMsgModel,NSString *errorMessage))finished;
-(void)sendMsgWithMsg_fromID:(NSString *)msg_fromID msg_toID:(NSString *)msg_toID msg_type:(OffcnSDKMsgType)msg_type text:(NSString *)text filePath:(NSString *)filePath Finished:(void(^)(BOOL success,OffcnIMSendMsgModel *sendMsgModel,NSString *errorMessage))finished ProgressPercent:(void(^)(NSString *key, float percent))progressPercent;
/// 用户信息标记已读
/// @param msg_fromID 发送人ID
......
//
//
......@@ -111,7 +111,7 @@ static OffcnIMSDKiOS *liveTelecastSDK;
#pragma mark - 操作事件
//发送消息
-(void)sendMsgWithMsg_fromID:(NSString *)msg_fromID msg_toID:(NSString *)msg_toID msg_type:(OffcnSDKMsgType)msg_type text:(NSString *)text filePath:(NSString *)filePath Finished:(void(^)(BOOL success,OffcnIMSendMsgModel *sendMsgModel,NSString *errorMessage))finished{
-(void)sendMsgWithMsg_fromID:(NSString *)msg_fromID msg_toID:(NSString *)msg_toID msg_type:(OffcnSDKMsgType)msg_type text:(NSString *)text filePath:(NSString *)filePath Finished:(void(^)(BOOL success,OffcnIMSendMsgModel *sendMsgModel,NSString *errorMessage))finished ProgressPercent:(void(^)(NSString *key, float percent))progressPercent{
KWeakSelf
NSString *tidStr = [NSString stringWithFormat:@"%@_%@",msg_toID,[SDGeneralTool getNowSSSTimeTimestamp]];
......@@ -255,6 +255,9 @@ static OffcnIMSDKiOS *liveTelecastSDK;
}else{
finished(success,nil,errorMessage);
}
} ProgressPercent:^(NSString *key, float percent) {
progressPercent(key,percent);
}];
}
}
......
//
//
// NSObject+ZYJQNSwizzle.h
// ZYJHappyDNS
//
// Created by yangsen on 2020/4/13.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject(ZYJQNSwizzle)
/// swizzle 两个对象方法
/// @param selectorA 方法a的sel
/// @param selectorB 方法b的sel
+ (BOOL)ZYJQN_swizzleInstanceMethodsOfSelectorA:(SEL)selectorA
selectorB:(SEL)selectorB;
/// swizzle 两个类方法
/// @param selectorA 方法a的sel
/// @param selectorB 方法b的sel
+ (BOOL)ZYJQN_swizzleClassMethodsOfSelectorA:(SEL)selectorA
selectorB:(SEL)selectorB;
@end
NS_ASSUME_NONNULL_END
//
//
// NSObject+ZYJQNSwizzle.m
// ZYJHappyDNS
//
// Created by yangsen on 2020/4/13.
//
#import "NSObject+ZYJQNSwizzle.h"
#import <objc/runtime.h>
@implementation NSObject(ZYJQNSwizzle)
+ (BOOL)ZYJQN_swizzleInstanceMethodsOfSelectorA:(SEL)selectorA
selectorB:(SEL)selectorB{
Method methodA = class_getInstanceMethod(self, selectorA);
Method methodB = class_getInstanceMethod(self, selectorB);
if (!methodA || !methodB) {
return NO;
}
class_addMethod(self,
selectorA,
class_getMethodImplementation(self, selectorA),
method_getTypeEncoding(methodA));
class_addMethod(self,
selectorB,
class_getMethodImplementation(self, selectorB),
method_getTypeEncoding(methodB));
method_exchangeImplementations(class_getInstanceMethod(self, selectorA),
class_getInstanceMethod(self, selectorB));
return YES;
}
+ (BOOL)ZYJQN_swizzleClassMethodsOfSelectorA:(SEL)selectorA
selectorB:(SEL)selectorB{
Method methodA = class_getInstanceMethod(object_getClass(self), selectorA);
Method methodB = class_getInstanceMethod(object_getClass(self), selectorB);
if (!methodA || !methodB) {
return NO;
}
class_addMethod(self,
selectorA,
class_getMethodImplementation(self, selectorA),
method_getTypeEncoding(methodA));
class_addMethod(self,
selectorB,
class_getMethodImplementation(self, selectorB),
method_getTypeEncoding(methodB));
method_exchangeImplementations(class_getInstanceMethod(self, selectorA),
class_getInstanceMethod(self, selectorB));
return YES;
}
@end
//
//
// NSURLRequest+ZYJQNRequest.h
// AppTest
//
// Created by yangsen on 2020/4/8.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSURLRequest(ZYJQNRequest)
/// 是否是七牛请求【内部使用】
/// 作为是否进行请求监听的判断依据 NO,当设置了ZYJQN_domain返回YES,反之为NO
@property(nonatomic, assign, readonly)BOOL ZYJQN_isQiNiuRequest;
/// 请求id【内部使用】
/// 只有通过设置ZYJQN_domain才会有效
@property(nonatomic, strong, nullable, readonly)NSString *ZYJQN_identifier;
/// 请求domain【内部使用】
/// 只有通过NSMutableURLRequest设置才会有效
@property(nonatomic, strong, nullable, readonly)NSString *ZYJQN_domain;
/// 请求头信息 去除七牛内部标记占位
@property(nonatomic, strong, nullable, readonly)NSDictionary *ZYJQN_allHTTPHeaderFields;
+ (instancetype)ZYJQN_requestWithURL:(NSURL *)url;
/// 获取请求体
- (NSData *)ZYJQN_getHttpBody;
- (BOOL)ZYJQN_isHttps;
@end
@interface NSMutableURLRequest(ZYJQNRequest)
/// 请求domain【内部使用】
@property(nonatomic, strong, nullable)NSString *ZYJQN_domain;
@end
NS_ASSUME_NONNULL_END
//
//
// NSURLRequest+ZYJQNRequest.m
// AppTest
//
// Created by yangsen on 2020/4/8.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <objc/runtime.h>
#import "NSURLRequest+ZYJQNRequest.h"
@implementation NSURLRequest(ZYJQNRequest)
#define kZYJQNURLReuestHostKey @"Host"
#define kZYJQNURLReuestIdentifierKey @"ZYJQNURLReuestIdentifier"
- (BOOL)ZYJQN_isQiNiuRequest{
if (self.ZYJQN_identifier && self.ZYJQN_domain) {
return YES;
} else {
return NO;
}
}
- (NSString *)ZYJQN_identifier{
return self.allHTTPHeaderFields[kZYJQNURLReuestIdentifierKey];
}
- (NSString *)ZYJQN_domain{
NSString *host = self.allHTTPHeaderFields[kZYJQNURLReuestHostKey];
if (host == nil) {
host = self.URL.host;
}
return host;
}
- (NSDictionary *)ZYJQN_allHTTPHeaderFields{
NSDictionary *headerFields = [self.allHTTPHeaderFields copy];
NSMutableDictionary *headerFieldsNew = [NSMutableDictionary dictionary];
for (NSString *key in headerFields) {
if (![key isEqualToString:kZYJQNURLReuestIdentifierKey]) {
[headerFieldsNew setObject:headerFields[key] forKey:key];
}
}
return [headerFieldsNew copy];
}
+ (instancetype)ZYJQN_requestWithURL:(NSURL *)url{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:url.host forHTTPHeaderField:kZYJQNURLReuestHostKey];
return request;
}
- (NSData *)ZYJQN_getHttpBody{
if (self.HTTPBody || ![self.HTTPMethod isEqualToString:@"POST"]) {
return self.HTTPBody;
}
NSInteger maxLength = 1024;
uint8_t d[maxLength];
NSInputStream *stream = self.HTTPBodyStream;
NSMutableData *data = [NSMutableData data];
[stream open];
BOOL end = NO;
while (!end) {
NSInteger bytesRead = [stream read:d maxLength:maxLength];
if (bytesRead == 0) {
end = YES;
} else if (bytesRead == -1){
end = YES;
} else if (stream.streamError == nil){
[data appendBytes:(void *)d length:bytesRead];
}
}
[stream close];
return [data copy];
}
- (BOOL)ZYJQN_isHttps{
if ([self.URL.absoluteString rangeOfString:@"https://"].location != NSNotFound) {
return YES;
} else {
return NO;
}
}
@end
@implementation NSMutableURLRequest(ZYJQNRequest)
- (void)setZYJQN_domain:(NSString *)ZYJQN_domain{
if (ZYJQN_domain) {
[self addValue:ZYJQN_domain forHTTPHeaderField:kZYJQNURLReuestHostKey];
} else {
[self setValue:nil forHTTPHeaderField:kZYJQNURLReuestHostKey];
}
NSString *identifier = [NSString stringWithFormat:@"%p-%@", &self, ZYJQN_domain];
[self setZYJQN_identifier:identifier];
}
- (void)setZYJQN_identifier:(NSString *)ZYJQN_identifier{
if (ZYJQN_identifier) {
[self addValue:ZYJQN_identifier forHTTPHeaderField:kZYJQNURLReuestIdentifierKey];
} else {
[self setValue:nil forHTTPHeaderField:kZYJQNURLReuestIdentifierKey];
}
}
@end
//
//
// ZYJHappyDNS.h
// ZYJHappyDNS
//
// Created by bailong on 15/6/24.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNDnsManager.h"
#import "ZYJQNDnspodEnterprise.h"
#import "ZYJQNDnspodFree.h"
#import "ZYJQNDomain.h"
#import "ZYJQNHijackingDetectWrapper.h"
#import "ZYJQNIP.h"
#import "ZYJQNNetworkInfo.h"
#import "ZYJQNRecord.h"
#import "ZYJQNResolver.h"
#import "ZYJQNResolverDelegate.h"
#import "ZYJQNGetAddrInfo.h"
//
//
// ZYJQNALAssetFile.h
// ZYJQiniuSDK
//
// Created by bailong on 15/7/25.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNFileDelegate.h"
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED)
#if !TARGET_OS_MACCATALYST
@class ALAsset;
@interface ZYJQNALAssetFile : NSObject <ZYJQNFileDelegate>
/**
* 打开指定文件
*
* @param asset 资源文件
* @param error 输出的错误信息
*
* @return 实例
*/
- (instancetype)init:(ALAsset *)asset
error:(NSError *__autoreleasing *)error;
@end
#endif
#endif
//
//
// ZYJQNALAssetFile.m
// ZYJQiniuSDK
//
// Created by bailong on 15/7/25.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import "ZYJQNALAssetFile.h"
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
#if !TARGET_OS_MACCATALYST
#import <AssetsLibrary/AssetsLibrary.h>
#import "ZYJQNResponseInfo.h"
@interface ZYJQNALAssetFile ()
@property (nonatomic) ALAsset *asset;
@property (readonly) int64_t fileSize;
@property (readonly) int64_t fileModifyTime;
@property (nonatomic, strong) NSLock *lock;
@end
@implementation ZYJQNALAssetFile
- (instancetype)init:(ALAsset *)asset
error:(NSError *__autoreleasing *)error {
if (self = [super init]) {
NSDate *createTime = [asset valueForProperty:ALAssetPropertyDate];
int64_t t = 0;
if (createTime != nil) {
t = [createTime timeIntervalSince1970];
}
_fileModifyTime = t;
_fileSize = asset.defaultRepresentation.size;
_asset = asset;
_lock = [[NSLock alloc] init];
}
return self;
}
- (NSData *)read:(long)offset
size:(long)size
error:(NSError **)error {
NSData *data = nil;
@try {
[_lock lock];
ALAssetRepresentation *rep = [self.asset defaultRepresentation];
Byte *buffer = (Byte *)malloc(size);
NSUInteger buffered = [rep getBytes:buffer fromOffset:offset length:size error:error];
data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
} @catch (NSException *exception) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:kZYJQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}];
NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols);
} @finally {
[_lock unlock];
}
return data;
}
- (NSData *)readAllWithError:(NSError **)error {
return [self read:0 size:(long)_fileSize error:error];
}
- (void)close {
}
- (NSString *)path {
ALAssetRepresentation *rep = [self.asset defaultRepresentation];
return [rep url].path;
}
- (int64_t)modifyTime {
return _fileModifyTime;
}
- (int64_t)size {
return _fileSize;
}
@end
#endif
#endif
//
//
// Assessment.h
// ZYJHappyDNS
//
// Created by bailong on 16/7/19.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYJQNJudge : NSObject
@end
@interface ZYJQNAssessment : NSObject
- (void)submitErrorRecord;
- (void)submitSpeedRecord;
@end
//
//
// Assessment.m
// ZYJHappyDNS
//
// Created by bailong on 16/7/19.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNAssessment.h"
@implementation ZYJQNAssessment
- (void)submitErrorRecord {
}
- (void)submitSpeedRecord {
}
@end
//
//
// ZYJQNAsyncRun.h
// ZYJQiniuSDK
//
// Created by bailong on 14/10/17.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef void (^ZYJQNRun)(void);
void ZYJQNAsyncRun(ZYJQNRun run);
void ZYJQNAsyncRunInMain(ZYJQNRun run);
void ZYJQNAsyncRunAfter(NSTimeInterval time, dispatch_queue_t queue, ZYJQNRun run);
//
//
// ZYJQNAsyncRun.m
// ZYJQiniuSDK
//
// Created by bailong on 14/10/17.
// Copyright (c) 2014 Qiniu. All rights reserved.
//
#import "ZYJQNAsyncRun.h"
#import <Foundation/Foundation.h>
void ZYJQNAsyncRun(ZYJQNRun run) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
run();
});
}
void ZYJQNAsyncRunInMain(ZYJQNRun run) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
run();
});
}
void ZYJQNAsyncRunAfter(NSTimeInterval time, dispatch_queue_t queue, ZYJQNRun run) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), queue, ^{
run();
});
}
//
//
// ZYJQNAutoZone.h
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/16.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNZone.h"
NS_ASSUME_NONNULL_BEGIN
@interface ZYJQNAutoZone : ZYJQNZone
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNAutoZone.m
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/16.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNAutoZone.h"
#import "ZYJQNSessionManager.h"
#import "ZYJQNZoneInfo.h"
#import "ZYJQNUpToken.h"
#import "ZYJQNResponseInfo.h"
@interface ZYJQNAutoZoneCache : NSObject
@property(nonatomic, strong)NSMutableDictionary *cache;
@end
@implementation ZYJQNAutoZoneCache
+ (instancetype)share{
static ZYJQNAutoZoneCache *cache = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cache = [[ZYJQNAutoZoneCache alloc] init];
[cache setupData];
});
return cache;
}
- (void)setupData{
self.cache = [NSMutableDictionary dictionary];
}
- (void)cache:(NSDictionary *)zonesInfo
forToken:(ZYJQNUpToken *)token{
NSString *cacheKey = token.index;
if (!cacheKey || [cacheKey isEqualToString:@""]) {
return;
}
@synchronized (self) {
if (zonesInfo) {
self.cache[cacheKey] = zonesInfo;
} else {
[self.cache removeObjectForKey:cacheKey];
}
}
}
- (ZYJQNZonesInfo *)zonesInfoForToken:(ZYJQNUpToken *)token{
NSString *cacheKey = token.index;
if (!cacheKey || [cacheKey isEqualToString:@""]) {
return nil;
}
NSDictionary *zonesInfoDic = nil;
@synchronized (self) {
zonesInfoDic = self.cache[cacheKey];
}
if (zonesInfoDic == nil) {
return nil;
}
ZYJQNZonesInfo *zonesInfo = [ZYJQNZonesInfo buildZonesInfoWithResp:zonesInfoDic];
NSMutableArray *zonesInfoArray = [NSMutableArray array];
for (ZYJQNZoneInfo *zoneInfo in zonesInfo.zonesInfo) {
if ([zoneInfo isValid]) {
[zonesInfoArray addObject:zoneInfo];
}
}
zonesInfo.zonesInfo = [zonesInfoArray copy];
return zonesInfo;
}
@end
@implementation ZYJQNAutoZone {
NSString *server;
NSMutableDictionary *cache;
NSLock *lock;
ZYJQNSessionManager *sesionManager;
}
- (instancetype)init{
if (self = [super init]) {
server = @"https://uc.qbox.me";
cache = [NSMutableDictionary new];
lock = [NSLock new];
sesionManager = [[ZYJQNSessionManager alloc] initWithProxy:nil timeout:10 urlConverter:nil];
}
return self;
}
- (NSString *)up:(ZYJQNUpToken *)token
zoneInfoType:(ZYJQNZoneInfoType)zoneInfoType
isHttps:(BOOL)isHttps
frozenDomain:(NSString *)frozenDomain {
NSString *index = [token index];
[lock lock];
ZYJQNZonesInfo *zonesInfo = [cache objectForKey:index];
[lock unlock];
if (zonesInfo == nil) {
return nil;
}
return [self upHost:[zonesInfo getZoneInfoWithType:zoneInfoType] isHttps:isHttps lastUpHost:frozenDomain];
}
- (ZYJQNZonesInfo *)getZonesInfoWithToken:(ZYJQNUpToken *)token {
if (token == nil) return nil;
[lock lock];
ZYJQNZonesInfo *zonesInfo = [cache objectForKey:[token index]];
[lock unlock];
return zonesInfo;
}
- (void)preQuery:(ZYJQNUpToken *)token
on:(ZYJQNPrequeryReturn)ret {
if (token == nil) {
ret(-1, nil);
return;
}
[lock lock];
ZYJQNZonesInfo *zonesInfo = [cache objectForKey:[token index]];
[lock unlock];
if (zonesInfo == nil) {
zonesInfo = [[ZYJQNAutoZoneCache share] zonesInfoForToken:token];
[self->lock lock];
[self->cache setValue:zonesInfo forKey:[token index]];
[self->lock unlock];
}
if (zonesInfo != nil) {
ret(0, nil);
return;
}
//https://uc.qbox.me/v3/query?ak=T3sAzrwItclPGkbuV4pwmszxK7Ki46qRXXGBBQz3&bucket=if-pbl
NSString *url = [NSString stringWithFormat:@"%@/v3/query?ak=%@&bucket=%@", server, token.access, token.bucket];
[sesionManager get:url withHeaders:nil withCompleteBlock:^(ZYJQNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody) {
if (!httpResponseInfo.error) {
ZYJQNZonesInfo *zonesInfo = [ZYJQNZonesInfo buildZonesInfoWithResp:respBody];
if (httpResponseInfo == nil) {
ret(kZYJQNInvalidToken, httpResponseInfo);
} else {
[self->lock lock];
[self->cache setValue:zonesInfo forKey:[token index]];
[self->lock unlock];
[[ZYJQNAutoZoneCache share] cache:respBody forToken:token];
ret(0, httpResponseInfo);
}
} else {
ret(kZYJQNNetworkError, httpResponseInfo);
}
}];
}
@end
//
//
// ZYJQNBaseUpload.h
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2020/4/19.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNConfiguration.h"
#import "ZYJQNCrc32.h"
#import "ZYJQNRecorderDelegate.h"
#import "ZYJQNHttpResponseInfo.h"
#import "ZYJQNSessionManager.h"
#import "ZYJQNUpToken.h"
#import "ZYJQNUrlSafeBase64.h"
#import "ZYJQNAsyncRun.h"
#import "ZYJQNUploadInfoCollector.h"
#import "ZYJQNUploadManager.h"
#import "ZYJQNUploadOption.h"
@interface ZYJQNBaseUpload : NSObject
@property (nonatomic, copy) NSString *key;
@property (nonatomic, copy) NSString *identifier;
@property (nonatomic, copy) NSString *access; //AK
@property (nonatomic, assign) UInt32 size;
@property (nonatomic, strong) ZYJQNSessionManager *sessionManager;
@property (nonatomic, strong) ZYJQNUpToken *token;
@property (nonatomic, strong) ZYJQNUploadOption *option;
@property (nonatomic, strong) ZYJQNUpCompletionHandler complete;
@property (nonatomic, strong) ZYJQNConfiguration *config;
@property (nonatomic, assign) ZYJQNZoneInfoType currentZoneType;
@property (nonatomic, assign) ZYJQNRequestType requestType;
- (void)collectHttpResponseInfo:(ZYJQNHttpResponseInfo *)httpResponseInfo fileOffset:(uint64_t)fileOffset;
- (void)collectUploadQualityInfo;
- (void)run;
@end
//
//
// ZYJQNBaseUpload.m
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2020/4/19.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNBaseUpload.h"
@interface ZYJQNBaseUpload ()
@end
@implementation ZYJQNBaseUpload
- (void)run {
// rewrite by subclass
}
- (void)collectHttpResponseInfo:(ZYJQNHttpResponseInfo *)httpResponseInfo fileOffset:(uint64_t)fileOffset {
ZYJQNZonesInfo *zonesInfo = [self.config.zone getZonesInfoWithToken:self.token];
NSString *targetRegionId = [zonesInfo getZoneInfoRegionNameWithType:ZYJQNZoneInfoTypeMain];
NSString *currentRegionId = [zonesInfo getZoneInfoRegionNameWithType:self.currentZoneType];
[Collector addRequestWithType:self.requestType httpResponseInfo:httpResponseInfo fileOffset:fileOffset targetRegionId:targetRegionId currentRegionId:currentRegionId identifier:self.identifier];
uint64_t bytesSent;
if (self.requestType == ZYJQNRequestType_mkblk || self.requestType == ZYJQNRequestType_bput) {
if (httpResponseInfo.hasHttpResponse) {
bytesSent = httpResponseInfo.bytesTotal;
} else {
bytesSent = 0;
}
[Collector append:ZYJCK_blockBytesSent value:@(bytesSent) identifier:self.identifier];
} else {
bytesSent = httpResponseInfo.bytesSent;
}
[Collector append:ZYJCK_totalBytesSent value:@(bytesSent) identifier:self.identifier];
}
- (void)collectUploadQualityInfo {
ZYJQNZonesInfo *zonesInfo = [self.config.zone getZonesInfoWithToken:self.token];
NSString *targetRegionId = [zonesInfo getZoneInfoRegionNameWithType:ZYJQNZoneInfoTypeMain];
NSString *currentRegionId = [zonesInfo getZoneInfoRegionNameWithType:self.currentZoneType];
[Collector update:ZYJCK_targetRegionId value:targetRegionId identifier:self.identifier];
[Collector update:ZYJCK_currentRegionId value:currentRegionId identifier:self.identifier];
[Collector update:ZYJCK_fileSize value:@(self.size) identifier:self.identifier];
}
@end
//
//
// ZYJQNHttpClient.h
// AppTest
//
// Created by yangsen on 2020/4/7.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol ZYJQNCFHttpClientDelegate <NSObject>
- (void)redirectedToRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse;
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain;
- (void)onError:(NSError *)error;
- (void)didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;
- (void)onReceiveResponse:(NSURLResponse *)response;
- (void)didLoadData:(NSData *)data;
- (void)didFinish;
@end
@interface ZYJQNCFHttpClient : NSObject
@property(nonatomic, strong, readonly)NSMutableURLRequest *request;
@property(nonatomic, weak)id <ZYJQNCFHttpClientDelegate> delegate;
+ (instancetype)client:(NSURLRequest *)request;
- (void)startLoading;
- (void)stopLoading;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNConcurrentResumeUpload.h
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2019/7/15.
// Copyright © 2019 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNBaseUpload.h"
#import "ZYJQNFileDelegate.h"
@interface ZYJQNConcurrentResumeUpload : ZYJQNBaseUpload
- (instancetype)initWithFile:(id<ZYJQNFileDelegate>)file
withKey:(NSString *)key
withToken:(ZYJQNUpToken *)token
withIdentifier:(NSString *)identifier
withRecorder:(id<ZYJQNRecorderDelegate>)recorder
withRecorderKey:(NSString *)recorderKey
withSessionManager:(ZYJQNSessionManager *)sessionManager
withCompletionHandler:(ZYJQNUpCompletionHandler)block
withOption:(ZYJQNUploadOption *)option
withConfiguration:(ZYJQNConfiguration *)config;
- (void)run;
@end
//
//
// ZYJQNConfig.h
// ZYJQiniuSDK
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
//MArk: -- 内部布置 尽量不要修改
#define kZYJQNPreQueryHost @"uc.qbox.me"
//
//
// ZYJQNConfiguration.h
// ZYJQiniuSDK
//
// Created by bailong on 15/5/21.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNRecorderDelegate.h"
#import "ZYJQNDns.h"
#import "ZYJQNZone.h"
/**
* 断点上传时的分块大小
*/
extern const UInt32 kZYJQNBlockSize;
/**
* DNS默认缓存时间
*/
extern const UInt32 kZYJQNDefaultDnsCacheTime;
/**
* 转换为用户需要的url
*
* @param url 上传url
*
* @return 根据上传url算出代理url
*/
typedef NSString * (^ZYJQNUrlConvert)(NSString *url);
@class ZYJQNConfigurationBuilder;
@class ZYJQNZone;
@class ZYJQNReportConfig;
/**
* Builder block
*
* @param builder builder实例
*/
typedef void (^ZYJQNConfigurationBuilderBlock)(ZYJQNConfigurationBuilder *builder);
@interface ZYJQNConfiguration : NSObject
/**
* 存储区域
*/
@property (copy, nonatomic, readonly) ZYJQNZone *zone;
/**
* 断点上传时的分片大小
*/
@property (readonly) UInt32 chunkSize;
/**
* 如果大于此值就使用断点上传,否则使用form上传
*/
@property (readonly) UInt32 putThreshold;
/**
* 上传失败时每个上传域名的重试次数,默认重试3次
*/
@property (readonly) UInt32 retryMax;
/**
* 重试前等待时长,默认0.5s
*/
@property (readonly) NSTimeInterval retryInterval;
/**
* 超时时间 单位 秒
*/
@property (readonly) UInt32 timeoutInterval;
/**
* 是否使用 https,默认为 YES
*/
@property (nonatomic, assign, readonly) BOOL useHttps;
/**
* 是否开启并发分片上传,默认为NO
*/
@property (nonatomic, assign, readonly) BOOL useConcurrentResumeUpload;
/**
* 并发分片上传的并发任务个数,在concurrentResumeUpload为YES时有效,默认为3个
*/
@property (nonatomic, assign, readonly) UInt32 concurrentTaskCount;
@property (nonatomic, readonly) ZYJQNReportConfig *reportConfig;
/**
* 重试时是否允许使用备用上传域名,默认为YES
*/
@property (nonatomic, assign) BOOL allowBackupHost;
@property (nonatomic, readonly) id<ZYJQNRecorderDelegate> recorder;
@property (nonatomic, readonly) ZYJQNRecorderKeyGenerator recorderKeyGen;
@property (nonatomic, readonly) NSDictionary *proxy;
@property (nonatomic, readonly) ZYJQNUrlConvert converter;
+ (instancetype)build:(ZYJQNConfigurationBuilderBlock)block;
@end
#define kZYJQNGlobalConfiguration [ZYJQNGlobalConfiguration shared]
@interface ZYJQNGlobalConfiguration : NSObject
/**
* 是否开启dns预解析 默认开启
*/
@property(nonatomic, assign)BOOL isDnsOpen;
/**
* dns 预取失败后 会进行重新预取 rePreHostNum为最多尝试次数
*/
@property(nonatomic, assign)UInt32 dnsRepreHostNum;
/**
* dns预取缓存时间 单位:秒
*/
@property(nonatomic, assign)UInt32 dnsCacheTime;
/**
* 自定义DNS解析客户端host
*/
@property(nonatomic, strong) id <ZYJQNDnsDelegate> dns;
/**
* dns解析结果本地缓存路径
*/
@property(nonatomic, copy, readonly)NSString *dnscacheDir;
+ (instancetype)shared;
@end
@interface ZYJQNConfigurationBuilder : NSObject
/**
* 默认上传服务器地址
*/
@property (nonatomic, strong) ZYJQNZone *zone;
/**
* 断点上传时的分片大小
*/
@property (assign) UInt32 chunkSize;
/**
* 如果大于此值就使用断点上传,否则使用form上传
*/
@property (assign) UInt32 putThreshold;
/**
* 上传失败时每个上传域名的重试次数,默认重试3次
*/
@property (assign) UInt32 retryMax;
/**
* 重试前等待时长,默认0.5s
*/
@property (assign) NSTimeInterval retryInterval;
/**
* 超时时间 单位 秒
*/
@property (assign) UInt32 timeoutInterval;
/**
* 是否使用 https,默认为 YES
*/
@property (nonatomic, assign) BOOL useHttps;
/**
* 重试时是否允许使用备用上传域名,默认为YES
*/
@property (nonatomic, assign) BOOL allowBackupHost;
/**
* 是否开启并发分片上传,默认为NO
*/
@property (nonatomic, assign) BOOL useConcurrentResumeUpload;
/**
* 并发分片上传的并发任务个数,在concurrentResumeUpload为YES时有效,默认为3个
*/
@property (nonatomic, assign) UInt32 concurrentTaskCount;
@property (nonatomic, strong) id<ZYJQNRecorderDelegate> recorder;
@property (nonatomic, strong) ZYJQNRecorderKeyGenerator recorderKeyGen;
@property (nonatomic, strong) ZYJQNReportConfig *reportConfig;
@property (nonatomic, strong) NSDictionary *proxy;
@property (nonatomic, strong) ZYJQNUrlConvert converter;
@end
//
//
// ZYJQNConfiguration.m
// ZYJQiniuSDK
//
// Created by bailong on 15/5/21.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import "ZYJQNConfiguration.h"
#import "ZYJQNHttpResponseInfo.h"
#import "ZYJQNResponseInfo.h"
#import "ZYJQNSessionManager.h"
#import "ZYJQNUpToken.h"
#import "ZYJQNUploadInfoReporter.h"
#import "ZYJQNAutoZone.h"
const UInt32 kZYJQNBlockSize = 4 * 1024 * 1024;
const UInt32 kZYJQNDefaultDnsCacheTime = 2 * 60;
@implementation ZYJQNConfiguration
+ (instancetype)build:(ZYJQNConfigurationBuilderBlock)block {
ZYJQNConfigurationBuilder *builder = [[ZYJQNConfigurationBuilder alloc] init];
block(builder);
return [[ZYJQNConfiguration alloc] initWithBuilder:builder];
}
- (instancetype)initWithBuilder:(ZYJQNConfigurationBuilder *)builder {
if (self = [super init]) {
_chunkSize = builder.chunkSize;
_putThreshold = builder.putThreshold;
_retryMax = builder.retryMax;
_retryInterval = builder.retryInterval;
_timeoutInterval = builder.timeoutInterval;
_recorder = builder.recorder;
_recorderKeyGen = builder.recorderKeyGen;
_proxy = builder.proxy;
_converter = builder.converter;
_zone = builder.zone;
_useHttps = builder.useHttps;
_allowBackupHost = builder.allowBackupHost;
_reportConfig = builder.reportConfig;
_useConcurrentResumeUpload = builder.useConcurrentResumeUpload;
_concurrentTaskCount = builder.concurrentTaskCount;
}
return self;
}
@end
@interface ZYJQNGlobalConfiguration()
@end
@implementation ZYJQNGlobalConfiguration
+ (instancetype)shared{
static ZYJQNGlobalConfiguration *config = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
config = [[ZYJQNGlobalConfiguration alloc] init];
[config setupData];
});
return config;
}
- (void)setupData{
_isDnsOpen = YES;
_dnscacheDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches/Dns"];
_dnsRepreHostNum = 2;
_dnsCacheTime = kZYJQNDefaultDnsCacheTime;
}
@end
@implementation ZYJQNConfigurationBuilder
- (instancetype)init {
if (self = [super init]) {
_zone = [[ZYJQNAutoZone alloc] init];
_chunkSize = 2 * 1024 * 1024;
_putThreshold = 4 * 1024 * 1024;
_retryMax = 3;
_timeoutInterval = 60;
_retryInterval = 0.5;
_reportConfig = [ZYJQNReportConfig sharedInstance];
_recorder = nil;
_recorderKeyGen = nil;
_proxy = nil;
_converter = nil;
_useHttps = YES;
_allowBackupHost = YES;
_useConcurrentResumeUpload = NO;
_concurrentTaskCount = 3;
}
return self;
}
@end
//
//
// ZYJQNCrc.h
// ZYJQiniuSDK
//
// Created by bailong on 14-9-29.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* 生成crc32 校验码
*/
@interface ZYJQNCrc32 : NSObject
/**
* 文件校验
*
* @param filePath 文件路径
* @param error 文件读取错误
*
* @return 校验码
*/
+ (UInt32)file:(NSString *)filePath
error:(NSError **)error;
/**
* 二进制字节校验
*
* @param data 二进制数据
*
* @return 校验码
*/
+ (UInt32)data:(NSData *)data;
@end
//
//
// ZYJQNCrc.m
// ZYJQiniuSDK
//
// Created by bailong on 14-9-29.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <zlib.h>
#import "ZYJQNConfiguration.h"
#import "ZYJQNCrc32.h"
@implementation ZYJQNCrc32
+ (UInt32)data:(NSData *)data {
uLong crc = crc32(0L, Z_NULL, 0);
crc = crc32(crc, [data bytes], (uInt)[data length]);
return (UInt32)crc;
}
+ (UInt32)file:(NSString *)filePath
error:(NSError **)error {
@autoreleasepool {
NSData *data = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:error];
if (*error != nil) {
return 0;
}
int len = (int)[data length];
int count = (len + kZYJQNBlockSize - 1) / kZYJQNBlockSize;
uLong crc = crc32(0L, Z_NULL, 0);
for (int i = 0; i < count; i++) {
int offset = i * kZYJQNBlockSize;
int size = (len - offset) > kZYJQNBlockSize ? kZYJQNBlockSize : (len - offset);
NSData *d = [data subdataWithRange:NSMakeRange(offset, (unsigned int)size)];
crc = crc32(crc, [d bytes], (uInt)[d length]);
}
return (UInt32)crc;
}
}
@end
//
//
// ZYJQNDes.h
// ZYJHappyDNS
//
// Created by bailong on 15/8/1.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
extern const int kZYJQN_ENCRYPT_FAILED;
extern const int kZYJQN_DECRYPT_FAILED;
@interface ZYJQNDes : NSObject
- (NSData *)encrypt:(NSData *)input;
- (NSData *)decrpyt:(NSData *)input;
- (instancetype)init:(NSData *)key;
@end
//
//
// ZYJQNDes.m
// ZYJHappyDNS
//
// Created by bailong on 15/8/1.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <CommonCrypto/CommonCryptor.h>
#import "ZYJQNDes.h"
@interface ZYJQNDes ()
@property (nonatomic, strong) NSData *key;
@end
@implementation ZYJQNDes
- (NSData *)encrypt:(NSData *)data {
const void *input = data.bytes;
size_t inputSize = data.length;
size_t bufferSize = (inputSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
uint8_t *buffer = malloc(bufferSize * sizeof(uint8_t));
memset((void *)buffer, 0x0, bufferSize);
size_t movedBytes = 0;
const void *vkey = _key.bytes;
CCCryptorStatus ccStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionECBMode | kCCOptionPKCS7Padding,
vkey,
kCCKeySizeDES,
NULL,
input,
inputSize,
(void *)buffer,
bufferSize,
&movedBytes);
if (ccStatus != kCCSuccess) {
NSLog(@"error code %d", ccStatus);
free(buffer);
return nil;
}
NSData *encrypted = [NSData dataWithBytes:(const void *)buffer length:(NSUInteger)movedBytes];
free(buffer);
return encrypted;
}
- (NSData *)decrpyt:(NSData *)raw {
const void *input = raw.bytes;
size_t inputSize = raw.length;
size_t bufferSize = 1024;
uint8_t *buffer = malloc(bufferSize * sizeof(uint8_t));
memset((void *)buffer, 0x0, bufferSize);
size_t movedBytes = 0;
const void *vkey = _key.bytes;
CCCryptorStatus ccStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmDES,
kCCOptionECBMode | kCCOptionPKCS7Padding,
vkey,
kCCKeySizeDES,
NULL,
input,
inputSize,
(void *)buffer,
bufferSize,
&movedBytes);
if (ccStatus != kCCSuccess) {
NSLog(@"error code %d", ccStatus);
free(buffer);
return nil;
}
NSData *decrypted = [NSData dataWithBytes:(const void *)buffer length:(NSUInteger)movedBytes];
free(buffer);
return decrypted;
}
- (instancetype)init:(NSData *)key {
if (self = [super init]) {
_key = key;
}
return self;
}
@end
//
//
// ZYJQNDns.h
// ZYJQNDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol ZYJQNInetAddressDelegate <NSObject>
/// 域名
@property(nonatomic, copy, readonly)NSString *hostValue;
/// 地址IP信息
@property(nonatomic, copy, readonly)NSString *ipValue;
/// ip有效时间 单位:秒
@property(nonatomic, strong, readonly)NSNumber *ttlValue;
/// 解析到host时的时间戳 单位:秒
@property(nonatomic, strong, readonly)NSNumber *timestampValue;
@end
@protocol ZYJQNDnsDelegate <NSObject>
/// 根据host获取解析结果
- (NSArray < id <ZYJQNInetAddressDelegate> > *)lookup:(NSString *)host;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNDnsCacheFile.h
// ZYJQNDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNRecorderDelegate.h"
NS_ASSUME_NONNULL_BEGIN
@interface ZYJQNDnsCacheFile : NSObject<ZYJQNRecorderDelegate>
/// DNS解析信息本地缓存路径
@property(nonatomic, copy, readonly)NSString *directory;
/// 构造方法 路径不存在,或进行创建,创建失败返回为nil
+ (instancetype _Nullable)dnsCacheFile:(NSString *)directory
error:(NSError **)perror;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNDnsCacheFile.m
// ZYJQNDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "ZYJQNDnsCacheFile.h"
@interface ZYJQNDnsCacheFile()
@property(nonatomic, copy)NSString *directory;
@end
@implementation ZYJQNDnsCacheFile
+ (instancetype)dnsCacheFile:(NSString *)directory
error:(NSError **)perror{
[[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:perror];
if (*perror != nil) {
return nil;
}
ZYJQNDnsCacheFile *f = [[ZYJQNDnsCacheFile alloc] init];
f.directory = directory;
return f;
}
- (NSError *)set:(NSString *)key
data:(NSData *)value {
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *filePath = [self pathOfKey:key];
[fileManager createFileAtPath:filePath contents:value attributes:nil];
return error;
}
- (NSData *)get:(NSString *)key {
return [NSData dataWithContentsOfFile:[self pathOfKey:key]];
}
- (NSError *)del:(NSString *)key {
NSError *error = nil;
NSString *path = [self pathOfKey:key];
if (path) {
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:path error:&error];
}
return error;
}
- (NSString *)getFileName{
return @"dnsCache";
}
- (NSString *)pathOfKey:(NSString *)key {
return [ZYJQNDnsCacheFile pathJoin:key path:_directory];
}
+ (NSString *)pathJoin:(NSString *)key
path:(NSString *)path {
return [[NSString alloc] initWithFormat:@"%@/%@", path, key];
}
@end
//
//
// ZYJQNDnsCacheKey.h
// ZYJQNDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZYJQNDnsCacheInfo : NSObject
/// 缓存时间戳
@property(nonatomic, copy, readonly)NSString *currentTime;
/// 缓存时本地IP
@property(nonatomic, copy, readonly)NSString *localIp;
/// 缓存信息
@property(nonatomic, copy, readonly)NSDictionary *info;
//MARK: -- 构造方法
/// 根据json构造对象
+ (instancetype)dnsCacheInfo:(NSData *)jsonData;
+ (instancetype)dnsCacheInfo:(NSString *)currentTime
localIp:(NSString *)localIp
info:(NSDictionary *)info;
/// 转化Json数据
- (NSData *)jsonData;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNDnsCacheKey.m
// ZYJQNDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "ZYJQNDnsCacheInfo.h"
@interface ZYJQNDnsCacheInfo()
/// 缓存时间戳
@property(nonatomic, copy)NSString *currentTime;
/// 缓存时本地IP
@property(nonatomic, copy)NSString *localIp;
/// 缓存信息
@property(nonatomic, copy)NSDictionary *info;
@end
@implementation ZYJQNDnsCacheInfo
+ (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 [ZYJQNDnsCacheInfo dnsCacheInfo:info[@"currentTime"]
localIp:info[@"localIp"]
info:info[@"info"]];;
}
+ (instancetype)dnsCacheInfo:(NSString *)currentTime
localIp:(NSString *)localIp
info:(NSDictionary *)info{
ZYJQNDnsCacheInfo *cacheInfo = [[ZYJQNDnsCacheInfo 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
//
//
// ZYJQNDnsManager.h
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
@class ZYJQNNetworkInfo;
@class ZYJQNDomain;
@class ZYJQNRecord;
/**
* getaddrinfo 回调上层的函数
*
* @param host 请求的域名
* @return ip 列表
*/
typedef NSArray * (^ZYJQNGetAddrInfoCallback)(NSString *host);
/**
* ip status 回调上层的函数
*
* @param ip 请求的IP
* @param code 错误码
* @param ms 消耗时间
*/
typedef void (^ZYJQNIpStatusCallback)(NSString *ip, int code, int ms);
/**
* 外部IP 排序接口
*/
@protocol ZYJQNIpSorter <NSObject>
/**
* 排序方法
*
* @param ips 传入的IP列表
*
* @return 返回排序好的IP 列表
*/
- (NSArray *)sort:(NSArray *)ips;
@end
/**
* DNS请求客户端,集成了cache管理
*/
@interface ZYJQNDnsManager : NSObject
/// 默认ttl值 单位:秒
@property(nonatomic, assign)int defaultTtl;
/// 查询失败时抛出错误信息回调
@property(nonatomic, copy)void(^ queryErrorHandler)(NSError *error, NSString *host);
/**
* 解析域名
*
* @param domain 域名
*
* @return IP列表
*/
- (NSArray <NSString *> *)query:(NSString *)domain;
/**
* 解析域名
*
* @param domain 域名
*
* @return ZYJQNRecord列表 ZYJQNRecord.value即为host
*/
- (NSArray <ZYJQNRecord *> *)queryRecords:(NSString *)domain;
/**
* 解析域名,使用Domain对象进行详细约定
*
* @param domain 配置了一些domain 参数的 domain 对象
*
* @return IP 列表
*/
- (NSArray <NSString *> *)queryWithDomain:(ZYJQNDomain *)domain;
/**
* 通知网络发生变化
*
* @param netInfo 网络信息
*/
- (void)onNetworkChange:(ZYJQNNetworkInfo *)netInfo;
/**
* Dns client 初始化
*
* @param resolvers 解析服务器列表
* @param netInfo 当前网络信息
*
* @return DnsManager
*/
- (instancetype)init:(NSArray *)resolvers networkInfo:(ZYJQNNetworkInfo *)netInfo;
/**
* Dns client 初始化
*
* @param resolvers 解析服务器列表
* @param netInfo 当前网络信息
* @param sorter 外部排序函数
*
* @return DnsManager
*/
- (instancetype)init:(NSArray *)resolvers networkInfo:(ZYJQNNetworkInfo *)netInfo sorter:(id<ZYJQNIpSorter>)sorter;
/**
* 内置 Hosts 解析
*
* @param domain 域名
* @param ip 对应IP
*
* @return 当前Dnsmanager, 为了链式调用
*/
- (instancetype)putHosts:(NSString *)domain ip:(NSString *)ip;
/**
* 内置 Hosts 解析
*
* @param domain 域名
* @param ip 对应IP
* @param provider 网络运营商
*
* @return 当前Dnsmanager, 为了链式调用
*/
- (instancetype)putHosts:(NSString *)domain ip:(NSString *)ip provider:(int)provider;
/**
* 设置底层 getaddrinfo 使用的回调
*
* @param block 回调的代码块
*/
+ (void)setGetAddrInfoBlock:(ZYJQNGetAddrInfoCallback)block;
/**
* 设置底层 getaddrinfo 回调使用的dnsmanager
*
* @param dns 回调用的dnsmanager
*/
+ (void)setDnsManagerForGetAddrInfo:(ZYJQNDnsManager *)dns;
/**
* 设置底层 业务统计 如connect 回调使用的Callback
*
* @param block 回调返回该IP状态
*/
+ (void)setIpStatusCallback:(ZYJQNIpStatusCallback)block;
/**
* 根据时区判断是否要设置httpDns
*
*/
+ (BOOL)needHttpDns;
@end
/**
* DnsManager 的 URL 辅助类
*/
@interface ZYJQNDnsManager (NSURL)
/**
* 使用URL 进行请求
*
* @param url 请求的Url
*
* @return 返回IP 替换过的url
*/
- (NSURL *)queryAndReplaceWithIP:(NSURL *)url;
@end
//
//
// ZYJQNDnsPrefetcher.h
// ZYJQNDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "ZYJQNTransactionManager.h"
#import "ZYJQNDns.h"
#import "ZYJQNConfiguration.h"
NS_ASSUME_NONNULL_BEGIN
#define kZYJQNDnsPrefetcher [ZYJQNDnsPrefetcher shared]
@interface ZYJQNDnsPrefetcher : NSObject
+ (instancetype)shared;
// 无效缓存,会根据inetAddress的host获取缓存列表,并移除inetAddress
- (void)invalidInetAdress:(id <ZYJQNInetAddressDelegate>)inetAddress;
/// 根据host从缓存中读取DNS信息
- (NSArray <id <ZYJQNInetAddressDelegate> > *)getInetAddressByHost:(NSString *)host;
@end
@interface ZYJQNTransactionManager(Dns)
/// 添加加载本地dns事务
- (void)addDnsLocalLoadTransaction;
/// 添加检测并预取dns事务 如果未开启DNS 或 事务队列中存在token对应的事务未处理,则返回NO
- (BOOL)addDnsCheckAndPrefetchTransaction:(ZYJQNZone *)currentZone token:(NSString *)token;
/// 设置定时事务:检测已缓存DNS有效情况事务 无效会重新预取
- (void)setDnsCheckWhetherCachedValidTransactionAction;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNDnspodEnterprise.h
// ZYJHappyDNS
//
// Created by bailong on 15/7/31.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNResolverDelegate.h"
#import <Foundation/Foundation.h>
extern const int kZYJQN_ENCRYPT_FAILED;
extern const int kZYJQN_DECRYPT_FAILED;
@interface ZYJQNDnspodEnterprise : NSObject <ZYJQNResolverDelegate>
- (instancetype)initWithId:(NSString *)userId
key:(NSString *)key;
- (instancetype)initWithId:(NSString *)userId
key:(NSString *)key
server:(NSString *)server;
- (instancetype)initWithId:(NSString *)userId
key:(NSString *)key
server:(NSString *)server
timeout:(NSUInteger)time;
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error;
@end
//
//
// ZYJQNDnspodFree.m
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNDnspodEnterprise.h"
#import <CommonCrypto/CommonCryptor.h>
#import "ZYJQNDes.h"
#import "ZYJQNDomain.h"
#import "ZYJQNHex.h"
#import "ZYJQNIP.h"
#import "ZYJQNRecord.h"
const int kZYJQN_ENCRYPT_FAILED = -10001;
const int kZYJQN_DECRYPT_FAILED = -10002;
@interface ZYJQNDnspodEnterprise ()
@property (readonly, strong) NSString *server;
@property (nonatomic, strong) NSString *userId;
@property (nonatomic, strong) ZYJQNDes *des;
@property (nonatomic) NSUInteger timeout;
@end
@implementation ZYJQNDnspodEnterprise
- (instancetype)initWithId:(NSString *)userId
key:(NSString *)key {
return [self initWithId:userId key:key server:@"119.29.29.29"];
}
- (instancetype)initWithId:(NSString *)userId
key:(NSString *)key
server:(NSString *)server {
return [self initWithId:userId key:key server:@"119.29.29.29" timeout:ZYJQN_DNS_DEFAULT_TIMEOUT];
}
- (instancetype)initWithId:(NSString *)userId
key:(NSString *)key
server:(NSString *)server
timeout:(NSUInteger)time {
if (self = [super init]) {
_server = server;
_userId = userId;
_des = [[ZYJQNDes alloc] init:[key dataUsingEncoding:NSUTF8StringEncoding]];
_timeout = time;
}
return self;
}
- (NSString *)encrypt:(NSString *)domain {
NSData *data = [_des encrypt:[domain dataUsingEncoding:NSUTF8StringEncoding]];
if (data == nil) {
return nil;
}
NSString *str = [ZYJQNHex encodeHexData:data];
return str;
}
- (NSString *)decrypt:(NSData *)raw {
NSData *enc = [ZYJQNHex decodeHexString:[[NSString alloc] initWithData:raw
encoding:NSUTF8StringEncoding]];
if (enc == nil) {
return nil;
}
NSData *data = [_des decrpyt:enc];
if (data == nil) {
return nil;
}
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
NSString *encrypt = [self encrypt:domain.domain];
if (encrypt == nil) {
if (error != nil) {
*error = [[NSError alloc] initWithDomain:domain.domain code:kZYJQN_ENCRYPT_FAILED userInfo:nil];
}
return nil;
}
NSString *url = [NSString stringWithFormat:@"http://%@/d?ttl=1&dn=%@&id=%@", [ZYJQNIP ipHost:_server], encrypt, _userId];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:_timeout];
NSHTTPURLResponse *response = nil;
NSError *httpError = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&httpError];
if (httpError != nil) {
if (error != nil) {
*error = httpError;
}
return nil;
}
if (response.statusCode != 200) {
return nil;
}
NSString *raw = [self decrypt:data];
if (raw == nil) {
if (error != nil) {
*error = [[NSError alloc] initWithDomain:domain.domain code:kZYJQN_DECRYPT_FAILED userInfo:nil];
}
return nil;
}
NSArray *ip1 = [raw componentsSeparatedByString:@","];
if (ip1.count != 2) {
return nil;
}
NSString *ttlStr = [ip1 objectAtIndex:1];
int ttl = [ttlStr intValue];
if (ttl <= 0) {
return nil;
}
NSString *ips = [ip1 objectAtIndex:0];
NSArray *ipArray = [ips componentsSeparatedByString:@";"];
NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:ipArray.count];
for (int i = 0; i < ipArray.count; i++) {
ZYJQNRecord *record = [[ZYJQNRecord alloc] init:[ipArray objectAtIndex:i] ttl:ttl type:kZYJQNTypeA source:ZYJQNRecordSourceDnspodEnterprise];
[ret addObject:record];
}
return ret;
}
@end
//
//
// ZYJQNDnspodFree.h
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNResolverDelegate.h"
#import <Foundation/Foundation.h>
@interface ZYJQNDnspodFree : NSObject <ZYJQNResolverDelegate>
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error;
- (instancetype)init;
- (instancetype)initWithServer:(NSString *)server;
- (instancetype)initWithServer:(NSString *)server
timeout:(NSUInteger)time;
@end
//
//
// ZYJQNDnspodFree.m
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNDnspodFree.h"
#import "ZYJQNDomain.h"
#import "ZYJQNIP.h"
#import "ZYJQNRecord.h"
@interface ZYJQNDnspodFree ()
@property (readonly, nonatomic, strong) NSString *server;
@property (readonly, nonatomic) NSUInteger timeout;
@end
@implementation ZYJQNDnspodFree
- (instancetype)init {
return [self initWithServer:@"119.29.29.29"];
}
- (instancetype)initWithServer:(NSString *)server {
return [self initWithServer:@"119.29.29.29" timeout:ZYJQN_DNS_DEFAULT_TIMEOUT];
}
- (instancetype)initWithServer:(NSString *)server
timeout:(NSUInteger)time {
if (self = [super init]) {
_server = server;
_timeout = time;
}
return self;
}
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
NSString *url = [NSString stringWithFormat:@"http://%@/d?ttl=1&dn=%@", [ZYJQNIP ipHost:_server], domain.domain];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:_timeout];
NSHTTPURLResponse *response = nil;
NSError *httpError = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&httpError];
if (httpError != nil) {
if (error != nil) {
*error = httpError;
}
return nil;
}
if (response.statusCode != 200) {
return nil;
}
NSString *raw = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSArray *ip1 = [raw componentsSeparatedByString:@","];
if (ip1.count != 2) {
return nil;
}
NSString *ttlStr = [ip1 objectAtIndex:1];
int ttl = [ttlStr intValue];
if (ttl <= 0) {
return nil;
}
NSString *ips = [ip1 objectAtIndex:0];
NSArray *ipArray = [ips componentsSeparatedByString:@";"];
NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:ipArray.count];
for (int i = 0; i < ipArray.count; i++) {
ZYJQNRecord *record = [[ZYJQNRecord alloc] init:[ipArray objectAtIndex:i] ttl:ttl type:kZYJQNTypeA source:ZYJQNRecordSourceDnspodFree];
[ret addObject:record];
}
return ret;
}
@end
//
//
// ZYJQNDomain.h
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYJQNDomain : NSObject
@property (nonatomic, strong, readonly) NSString *domain;
// 用来判断劫持
@property (nonatomic, readonly) BOOL hasCname;
// 用来判断劫持
@property (nonatomic, readonly) int maxTtl;
@property (nonatomic, readonly) BOOL hostsFirst;
- (instancetype)init:(NSString *)domain;
- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname;
- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname maxTtl:(int)maxTtl;
@end
//
//
// ZYJQNDomain.m
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNDomain.h"
@implementation ZYJQNDomain
- (instancetype)init:(NSString *)domain {
return [self init:domain hostsFirst:NO hasCname:NO maxTtl:0];
}
- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname {
return [self init:domain hostsFirst:hostsFirst hasCname:hasCname maxTtl:0];
}
- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname maxTtl:(int)maxTtl {
if (self = [super init]) {
_domain = domain;
_hasCname = hasCname;
_maxTtl = maxTtl;
_hostsFirst = hostsFirst;
}
return self;
}
@end
//
//
// ZYJQNEtag.h
// ZYJQiniuSDK
//
// Created by bailong on 14/10/4.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* 服务器 hash etag 生成
*/
@interface ZYJQNEtag : NSObject
/**
* 文件etag
*
* @param filePath 文件路径
* @param error 输出文件读取错误
*
* @return etag
*/
+ (NSString *)file:(NSString *)filePath
error:(NSError **)error;
/**
* 二进制数据etag
*
* @param data 数据
*
* @return etag
*/
+ (NSString *)data:(NSData *)data;
@end
//
//
// ZYJQNEtag.m
// ZYJQiniuSDK
//
// Created by bailong on 14/10/4.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#include <CommonCrypto/CommonCrypto.h>
#import "ZYJQNConfiguration.h"
#import "ZYJQNEtag.h"
#import "ZYJQNUrlSafeBase64.h"
@implementation ZYJQNEtag
+ (NSString *)file:(NSString *)filePath
error:(NSError **)error {
@autoreleasepool {
NSData *data = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:error];
if (error && *error) {
return 0;
}
return [ZYJQNEtag data:data];
}
}
+ (NSString *)data:(NSData *)data {
if (data == nil || [data length] == 0) {
return @"Fto5o-5ea0sNMlW_75VgGJCv2AcJ";
}
int len = (int)[data length];
int count = (len + kZYJQNBlockSize - 1) / kZYJQNBlockSize;
NSMutableData *retData = [NSMutableData dataWithLength:CC_SHA1_DIGEST_LENGTH + 1];
UInt8 *ret = [retData mutableBytes];
NSMutableData *blocksSha1 = nil;
UInt8 *pblocksSha1 = ret + 1;
if (count > 1) {
blocksSha1 = [NSMutableData dataWithLength:CC_SHA1_DIGEST_LENGTH * count];
pblocksSha1 = [blocksSha1 mutableBytes];
}
for (int i = 0; i < count; i++) {
int offset = i * kZYJQNBlockSize;
int size = (len - offset) > kZYJQNBlockSize ? kZYJQNBlockSize : (len - offset);
NSData *d = [data subdataWithRange:NSMakeRange(offset, (unsigned int)size)];
CC_SHA1([d bytes], (CC_LONG)size, pblocksSha1 + i * CC_SHA1_DIGEST_LENGTH);
}
if (count == 1) {
ret[0] = 0x16;
} else {
ret[0] = 0x96;
CC_SHA1(pblocksSha1, (CC_LONG)CC_SHA1_DIGEST_LENGTH * count, ret + 1);
}
return [ZYJQNUrlSafeBase64 encodeData:retData];
}
@end
//
//
// ZYJQNFile.h
// ZYJQiniuSDK
//
// Created by bailong on 15/7/25.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import "ZYJQNFileDelegate.h"
#import <Foundation/Foundation.h>
@interface ZYJQNFile : NSObject <ZYJQNFileDelegate>
/**
* 打开指定文件
*
* @param path 文件路径
* @param error 输出的错误信息
*
* @return 实例
*/
- (instancetype)init:(NSString *)path
error:(NSError *__autoreleasing *)error;
@end
//
//
// ZYJQNFile.m
// ZYJQiniuSDK
//
// Created by bailong on 15/7/25.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import "ZYJQNFile.h"
#import "ZYJQNResponseInfo.h"
@interface ZYJQNFile ()
@property (nonatomic, readonly) NSString *filepath;
@property (nonatomic) NSData *data;
@property (readonly) int64_t fileSize;
@property (readonly) int64_t fileModifyTime;
@property (nonatomic) NSFileHandle *file;
@property (nonatomic) NSLock *lock;
@end
@implementation ZYJQNFile
- (instancetype)init:(NSString *)path
error:(NSError *__autoreleasing *)error {
if (self = [super init]) {
_filepath = path;
NSError *error2 = nil;
NSDictionary *fileAttr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error2];
if (error2 != nil) {
if (error != nil) {
*error = error2;
}
return self;
}
_fileSize = [fileAttr fileSize];
NSDate *modifyTime = fileAttr[NSFileModificationDate];
int64_t t = 0;
if (modifyTime != nil) {
t = [modifyTime timeIntervalSince1970];
}
_fileModifyTime = t;
NSFileHandle *f = nil;
NSData *d = nil;
//[NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error] 不能用在大于 200M的文件上,改用filehandle
// 参见 https://issues.apache.org/jira/browse/CB-5790
if (_fileSize > 16 * 1024 * 1024) {
f = [NSFileHandle fileHandleForReadingAtPath:path];
if (f == nil) {
if (error != nil) {
*error = [[NSError alloc] initWithDomain:path code:kZYJQNFileError userInfo:nil];
}
return self;
}
} else {
d = [NSData dataWithContentsOfFile:path options:NSDataReadingMappedIfSafe error:&error2];
if (error2 != nil) {
if (error != nil) {
*error = error2;
}
return self;
}
}
_file = f;
_data = d;
_lock = [[NSLock alloc] init];
}
return self;
}
- (NSData *)read:(long)offset
size:(long)size
error:(NSError **)error {
NSData *data = nil;
@try {
[_lock lock];
if (_data != nil) {
data = [_data subdataWithRange:NSMakeRange(offset, (unsigned int)size)];
} else {
[_file seekToFileOffset:offset];
data = [_file readDataOfLength:size];
}
} @catch (NSException *exception) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:kZYJQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}];
NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols);
} @finally {
[_lock unlock];
}
return data;
}
- (NSData *)readAllWithError:(NSError **)error {
return [self read:0 size:(long)_fileSize error:error];
}
- (void)close {
if (_file != nil) {
[_file closeFile];
}
}
- (NSString *)path {
return _filepath;
}
- (int64_t)modifyTime {
return _fileModifyTime;
}
- (int64_t)size {
return _fileSize;
}
@end
//
//
// ZYJQNFileDelegate.h
// ZYJQiniuSDK
//
// Created by bailong on 15/7/25.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* 文件处理接口,支持ALAsset, NSFileHandle, NSData
*/
@protocol ZYJQNFileDelegate <NSObject>
/**
* 从指定偏移读取数据
*
* @param offset 偏移地址
* @param size 大小
* @param error 错误信息
*
* @return 数据
*/
- (NSData *)read:(long)offset
size:(long)size
error:(NSError **)error;
/**
* 读取所有文件内容
*
* @return 数据
* @error 错误信息
*/
- (NSData *)readAllWithError:(NSError **)error;
/**
* 关闭文件
*
*/
- (void)close;
/**
* 文件路径
*
* @return 文件路径
*/
- (NSString *)path;
/**
* 文件修改时间
*
* @return 修改时间
*/
- (int64_t)modifyTime;
/**
* 文件大小
*
* @return 文件大小
*/
- (int64_t)size;
@end
//
//
// ZYJQNFileRecorder.h
// ZYJQiniuSDK
//
// Created by bailong on 14/10/5.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import "ZYJQNRecorderDelegate.h"
#import <Foundation/Foundation.h>
/**
* 将上传记录保存到文件系统中
*/
@interface ZYJQNFileRecorder : NSObject <ZYJQNRecorderDelegate>
/**
* 用指定保存的目录进行初始化
*
* @param directory 目录
* @param error 输出的错误信息
*
* @return 实例
*/
+ (instancetype)fileRecorderWithFolder:(NSString *)directory
error:(NSError *__autoreleasing *)error;
/**
* 用指定保存的目录,以及是否进行base64编码进行初始化,
*
* @param directory 目录
* @param encode 为避免因为特殊字符或含有/,无法保存持久化记录,故用此参数指定是否要base64编码
* @param error 输出错误信息
*
* @return 实例
*/
+ (instancetype)fileRecorderWithFolder:(NSString *)directory
encodeKey:(BOOL)encode
error:(NSError *__autoreleasing *)error;
/**
* 从外部手动删除记录,如无特殊需求,不建议使用
*
* @param key 持久化记录key
* @param dir 目录
* @param encode 是否encode
*/
+ (void)removeKey:(NSString *)key
directory:(NSString *)dir
encodeKey:(BOOL)encode;
@end
//
//
// ZYJQNFileRecorder.m
// ZYJQiniuSDK
//
// Created by bailong on 14/10/5.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import "ZYJQNFileRecorder.h"
#import "ZYJQNUrlSafeBase64.h"
@interface ZYJQNFileRecorder ()
@property (copy, readonly) NSString *directory;
@property BOOL encode;
@end
@implementation ZYJQNFileRecorder
- (NSString *)pathOfKey:(NSString *)key {
return [ZYJQNFileRecorder pathJoin:key path:_directory];
}
+ (NSString *)pathJoin:(NSString *)key
path:(NSString *)path {
return [[NSString alloc] initWithFormat:@"%@/%@", path, key];
}
+ (instancetype)fileRecorderWithFolder:(NSString *)directory
error:(NSError *__autoreleasing *)perror {
return [ZYJQNFileRecorder fileRecorderWithFolder:directory encodeKey:false error:perror];
}
+ (instancetype)fileRecorderWithFolder:(NSString *)directory
encodeKey:(BOOL)encode
error:(NSError *__autoreleasing *)perror {
NSError *error;
[[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:&error];
if (error != nil) {
if (perror) {
*perror = error;
}
return nil;
}
return [[ZYJQNFileRecorder alloc] initWithFolder:directory encodeKey:encode];
}
- (instancetype)initWithFolder:(NSString *)directory encodeKey:(BOOL)encode {
if (self = [super init]) {
_directory = directory;
_encode = encode;
}
return self;
}
- (NSError *)set:(NSString *)key
data:(NSData *)value {
NSError *error;
if (_encode) {
key = [ZYJQNUrlSafeBase64 encodeString:key];
}
[value writeToFile:[self pathOfKey:key] options:NSDataWritingAtomic error:&error];
return error;
}
- (NSData *)get:(NSString *)key {
if (_encode) {
key = [ZYJQNUrlSafeBase64 encodeString:key];
}
return [NSData dataWithContentsOfFile:[self pathOfKey:key]];
}
- (NSError *)del:(NSString *)key {
NSError *error;
if (_encode) {
key = [ZYJQNUrlSafeBase64 encodeString:key];
}
[[NSFileManager defaultManager] removeItemAtPath:[self pathOfKey:key] error:&error];
return error;
}
- (NSString *)getFileName{
return nil;
}
+ (void)removeKey:(NSString *)key
directory:(NSString *)dir
encodeKey:(BOOL)encode {
if (encode) {
key = [ZYJQNUrlSafeBase64 encodeString:key];
}
NSError *error;
NSString *path = [ZYJQNFileRecorder pathJoin:key path:dir];
[[NSFileManager defaultManager] removeItemAtPath:path error:&error];
if (error) {
NSLog(@"%s,%@", __func__, error);
}
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p, dir: %@>", NSStringFromClass([self class]), self, _directory];
}
@end
//
//
// ZYJQNFixZone.h
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/16.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNZone.h"
NS_ASSUME_NONNULL_BEGIN
@interface ZYJQNFixedZone : ZYJQNZone
/**
* zone 0 华东
*
* @return 实例
*/
+ (instancetype)zone0;
/**
* zone 1 华北
*
* @return 实例
*/
+ (instancetype)zone1;
/**
* zone 2 华南
*
* @return 实例
*/
+ (instancetype)zone2;
/**
* zone Na0 北美
*
* @return 实例
*/
+ (instancetype)zoneNa0;
/**
* zone As0 新加坡
*
* @return 实例
*/
+ (instancetype)zoneAs0;
/**
* Zone初始化方法
*
* @param upList 默认上传服务器地址列表
* @return Zone实例
*/
- (instancetype)initWithupDomainList:(NSArray<NSString *> *)upList;
/**
* Zone初始化方法
*
* @param upList 默认上传服务器地址列表
*
* @return Zone实例
*/
+ (instancetype)createWithHost:(NSArray<NSString *> *)upList;
/**
* 获取本地所有固定zone信息
*/
+ (NSArray <ZYJQNFixedZone *> *)localsZoneInfo;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNFixZone.m
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/16.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNFixedZone.h"
#import "ZYJQNZoneInfo.h"
@interface ZYJQNFixedZone ()
@property (nonatomic, strong) ZYJQNZonesInfo *zonesInfo;
@end
@implementation ZYJQNFixedZone
- (instancetype)initWithupDomainList:(NSArray<NSString *> *)upList {
if (self = [super init]) {
self.zonesInfo = [self createZonesInfo:upList zoneRegion:ZYJQNZoneRegion_unknown];
}
return self;
}
- (instancetype)initWithupDomainList:(NSArray<NSString *> *)upList
zoneRegion:(ZYJQNZoneRegion)zoneRegion {
if (self = [super init]) {
self.zonesInfo = [self createZonesInfo:upList zoneRegion:zoneRegion];
}
return self;
}
+ (instancetype)createWithHost:(NSArray<NSString *> *)upList {
return [[ZYJQNFixedZone alloc] initWithupDomainList:upList zoneRegion:ZYJQNZoneRegion_unknown];
}
+ (instancetype)zone0 {
static ZYJQNFixedZone *z0 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSArray<NSString *> *uplist = @[@"upload.qiniup.com", @"upload-nb.qiniup.com",
@"upload-xs.qiniup.com", @"up.qiniup.com",
@"up-nb.qiniup.com", @"up-xs.qiniup.com",
@"upload.qbox.me", @"up.qbox.me"];
z0 = [ZYJQNFixedZone createWithHost:(NSArray<NSString *> *)uplist];
});
return z0;
}
+ (instancetype)zone1 {
static ZYJQNFixedZone *z1 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSArray<NSString *> *uplist = @[@"upload-z1.qiniup.com", @"up-z1.qiniup.com",
@"upload-z1.qbox.me", @"up-z1.qbox.me"];
z1 = [ZYJQNFixedZone createWithHost:(NSArray<NSString *> *)uplist];
});
return z1;
}
+ (instancetype)zone2 {
static ZYJQNFixedZone *z2 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSArray<NSString *> *uplist = @[@"upload-z2.qiniup.com", @"upload-gz.qiniup.com",
@"upload-fs.qiniup.com", @"up-z2.qiniup.com",
@"up-gz.qiniup.com", @"up-fs.qiniup.com",
@"upload-z2.qbox.me", @"up-z2.qbox.me"];
z2 = [ZYJQNFixedZone createWithHost:(NSArray<NSString *> *)uplist];
});
return z2;
}
+ (instancetype)zoneNa0 {
static ZYJQNFixedZone *zNa0 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSArray<NSString *> *uplist = @[@"upload-na0.qiniup.com", @"up-na0.qiniup.com",
@"upload-na0.qbox.me", @"up-na0.qbox.me"];
zNa0 = [ZYJQNFixedZone createWithHost:(NSArray<NSString *> *)uplist];
});
return zNa0;
}
+ (instancetype)zoneAs0 {
static ZYJQNFixedZone *zAs0 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSArray<NSString *> *uplist = @[@"upload-as0.qiniup.com", @"up-as0.qiniup.com",
@"upload-as0.qbox.me", @"up-as0.qbox.me"];
zAs0 = [ZYJQNFixedZone createWithHost:(NSArray<NSString *> *)uplist];
});
return zAs0;
}
+ (NSArray <ZYJQNFixedZone *> *)localsZoneInfo{
NSArray *zonesInfo = @[[ZYJQNFixedZone zone0],
[ZYJQNFixedZone zone1],
[ZYJQNFixedZone zone2],
[ZYJQNFixedZone zoneNa0],
[ZYJQNFixedZone zoneAs0]];
return zonesInfo;
}
- (ZYJQNZonesInfo *)createZonesInfo:(NSArray<NSString *> *)upDomainList
zoneRegion:(ZYJQNZoneRegion)zoneRegion {
NSMutableDictionary *upDomainDic = [[NSMutableDictionary alloc] init];
for (NSString *upDomain in upDomainList) {
[upDomainDic setValue:[NSDate dateWithTimeIntervalSince1970:0] forKey:upDomain];
}
ZYJQNZoneInfo *zoneInfo = [[ZYJQNZoneInfo alloc] init:86400 upDomainsList:(NSMutableArray<NSString *> *)upDomainList upDomainsDic:upDomainDic zoneRegion:zoneRegion];
ZYJQNZonesInfo *zonesInfo = [[ZYJQNZonesInfo alloc] initWithZonesInfo:@[zoneInfo]];
return zonesInfo;
}
- (void)preQuery:(ZYJQNUpToken *)token
on:(ZYJQNPrequeryReturn)ret {
ret(0, nil);
}
- (ZYJQNZonesInfo *)getZonesInfoWithToken:(ZYJQNUpToken *)token {
return self.zonesInfo;
}
- (NSString *)up:(ZYJQNUpToken *)token
zoneInfoType:(ZYJQNZoneInfoType)zoneInfoType
isHttps:(BOOL)isHttps
frozenDomain:(NSString *)frozenDomain {
if (self.zonesInfo == nil) {
return nil;
}
return [super upHost:[self.zonesInfo getZoneInfoWithType:ZYJQNZoneInfoTypeMain] isHttps:isHttps lastUpHost:frozenDomain];
}
@end
//
//
// ZYJQNFormUpload.h
// ZYJQiniuSDK
//
// Created by bailong on 15/1/4.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import "ZYJQNBaseUpload.h"
#import <Foundation/Foundation.h>
@interface ZYJQNFormUpload : ZYJQNBaseUpload
- (instancetype)initWithData:(NSData *)data
withKey:(NSString *)key
withFileName:(NSString *)fileName
withToken:(ZYJQNUpToken *)token
withIdentifier:(NSString *)identifier
withCompletionHandler:(ZYJQNUpCompletionHandler)block
withOption:(ZYJQNUploadOption *)option
withSessionManager:(ZYJQNSessionManager *)sessionManager
withConfiguration:(ZYJQNConfiguration *)config;
- (void)put;
@end
//
//
// ZYJQNFormUpload.m
// ZYJQiniuSDK
//
// Created by bailong on 15/1/4.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import "ZYJQNFormUpload.h"
@interface ZYJQNFormUpload ()
@property (nonatomic, strong) NSData *data;
@property (nonatomic) int retryTimes;
@property (nonatomic, strong) NSString *fileName;
@property (nonatomic) float previousPercent;
@end
@implementation ZYJQNFormUpload
- (instancetype)initWithData:(NSData *)data
withKey:(NSString *)key
withFileName:(NSString *)fileName
withToken:(ZYJQNUpToken *)token
withIdentifier:(NSString *)identifier
withCompletionHandler:(ZYJQNUpCompletionHandler)block
withOption:(ZYJQNUploadOption *)option
withSessionManager:(ZYJQNSessionManager *)sessionManager
withConfiguration:(ZYJQNConfiguration *)config {
if (self = [super init]) {
self.data = data;
self.size = (UInt32)data.length;
self.key = key;
self.token = token;
self.option = option != nil ? option : [ZYJQNUploadOption defaultOptions];
self.complete = block;
self.sessionManager = sessionManager;
self.config = config;
self.fileName = fileName != nil ? fileName : @"?";
self.previousPercent = 0;
self.access = token.access;
self.currentZoneType = ZYJQNZoneInfoTypeMain;
self.identifier = identifier;
self.requestType = ZYJQNRequestType_form;
}
return self;
}
- (void)put {
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
if (self.key) {
parameters[@"key"] = self.key;
}
parameters[@"token"] = self.token.token;
[parameters addEntriesFromDictionary:self.option.params];
parameters[@"crc32"] = [NSString stringWithFormat:@"%u", (unsigned int)[ZYJQNCrc32 data:_data]];
[self nextTask:0 needDelay:NO host:[self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil] param:parameters];
}
- (void)nextTask:(int)retried needDelay:(BOOL)needDelay host:(NSString *)host param:(NSDictionary *)param {
if (needDelay) {
ZYJQNAsyncRunAfter(self.config.retryInterval, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self nextTask:retried host:host param:param];
});
} else {
[self nextTask:retried host:host param:param];
}
}
- (void)nextTask:(int)retried host:(NSString *)host param:(NSDictionary *)param {
if (self.option.cancellationSignal()) {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector userCancel:self.identifier];
self.complete(info, self.key, nil);
return;
}
ZYJQNInternalProgressBlock p = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
float percent = (float)totalBytesWritten / (float)totalBytesExpectedToWrite;
if (percent > 0.95) {
percent = 0.95;
}
if (percent > self.previousPercent) {
self.previousPercent = percent;
} else {
percent = self.previousPercent;
}
self.option.progressHandler(self.key, percent);
};
ZYJQNCompleteBlock complete = ^(ZYJQNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody) {
[self collectHttpResponseInfo:httpResponseInfo fileOffset:ZYJQN_IntNotSet];
if (httpResponseInfo.isOK) {
self.option.progressHandler(self.key, 1.0);
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
self.complete(info, self.key, respBody);
} else if (httpResponseInfo.couldRetry) {
if (retried < self.config.retryMax) {
[self nextTask:retried + 1 needDelay:YES host:host param:param];
} else {
if (self.config.allowBackupHost) {
NSString *nextHost = [self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:host];
if (nextHost) {
[self nextTask:0 needDelay:YES host:nextHost param:param];
} else {
ZYJQNZonesInfo *zonesInfo = [self.config.zone getZonesInfoWithToken:self.token];
if (self.currentZoneType == ZYJQNZoneInfoTypeMain && zonesInfo.hasBackupZone) {
self.currentZoneType = ZYJQNZoneInfoTypeBackup;
[self nextTask:0 needDelay:YES host:[self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil] param:param];
} else {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
self.complete(info, self.key, respBody);
}
}
} else {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
self.complete(info, self.key, respBody);
}
}
} else {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
self.complete(info, self.key, respBody);
}
};
[self.sessionManager multipartPost:host
withData:self.data
withParams:param
withFileName:self.fileName
withMimeType:self.option.mimeType
withIdentifier:self.identifier
withCompleteBlock:complete
withProgressBlock:p
withCancelBlock:self.option.cancellationSignal
withAccess:self.access];
}
@end
//
//
// ZYJQNGetAddrInfo.h
// ZYJHappyDNS
//
// Created by bailong on 16/7/19.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#ifndef ZYJQNGetAddrInfo_h
#define ZYJQNGetAddrInfo_h
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ZYJQN_ips_ret {
char *ips[1];
} ZYJQN_ips_ret;
typedef ZYJQN_ips_ret *(*ZYJQN_dns_callback)(const char *host);
typedef void (*ZYJQN_ip_report_callback)(const char *ip, int code, int time_ms);
extern void ZYJQN_free_ips_ret(ZYJQN_ips_ret *ip_list);
extern int ZYJQN_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
extern void ZYJQN_freeaddrinfo(struct addrinfo *ai);
extern void ZYJQN_set_dns_callback(ZYJQN_dns_callback cb);
extern void ZYJQN_set_ip_report_callback(ZYJQN_ip_report_callback cb);
extern void ZYJQN_ip_report(const struct addrinfo *info, int code, int time_ms);
#ifdef __cplusplus
};
#endif
#endif /* ZYJQNGetAddrInfo_h */
//
//
// ZYJQNGetAddrInfo.c
// ZYJHappyDNS
//
// Created by bailong on 16/7/19.
// Copyright © 2016 Qiniu Cloud Storage. All rights reserved.
//
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include "ZYJQNGetAddrInfo.h"
//fast judge domain or ip, not verify ip right.
static int isIp(const char* domain) {
size_t l = strlen(domain);
if (l > 15 || l < 7) {
return 0;
}
for (const char* p = domain; p < domain + l; p++) {
if ((*p < '0' || *p > '9') && *p != '.') {
return 0;
}
}
return 1;
}
static struct addrinfo* addrinfo_clone(struct addrinfo* addr) {
struct addrinfo* ai;
ai = (struct addrinfo*)calloc(sizeof(struct addrinfo) + addr->ai_addrlen, 1);
if (ai) {
memcpy(ai, addr, sizeof(struct addrinfo));
ai->ai_addr = (struct sockaddr*)(ai + 1);
memcpy(ai->ai_addr, addr->ai_addr, addr->ai_addrlen);
if (addr->ai_canonname) {
ai->ai_canonname = strdup(addr->ai_canonname);
}
ai->ai_next = NULL;
}
return ai;
}
static void append_addrinfo(struct addrinfo** head, struct addrinfo* addr) {
if (*head == NULL) {
*head = addr;
return;
}
struct addrinfo* ai = *head;
while (ai->ai_next != NULL) {
ai = ai->ai_next;
}
ai->ai_next = addr;
}
void ZYJQN_free_ips_ret(ZYJQN_ips_ret* ip_list) {
if (ip_list == NULL) {
return;
}
char** p = ip_list->ips;
while (*p != NULL) {
free(*p);
p++;
}
free(ip_list);
}
static ZYJQN_dns_callback dns_callback = NULL;
int ZYJQN_getaddrinfo(const char* hostname, const char* servname, const struct addrinfo* hints, struct addrinfo** res) {
if (dns_callback == NULL || hostname == NULL || isIp(hostname)) {
return getaddrinfo(hostname, servname, hints, res);
}
ZYJQN_ips_ret* ret = dns_callback(hostname);
if (ret == NULL) {
return EAI_NODATA;
}
if (ret->ips[0] == NULL) {
ZYJQN_free_ips_ret(ret);
return EAI_NODATA;
}
int i;
struct addrinfo* ai = NULL;
struct addrinfo* store = NULL;
int r = 0;
for (i = 0; ret->ips[i] != NULL; i++) {
r = getaddrinfo(ret->ips[i], servname, hints, &ai);
if (r != 0) {
break;
}
struct addrinfo* temp = ai;
ai = addrinfo_clone(ai);
append_addrinfo(&store, ai);
freeaddrinfo(temp);
ai = NULL;
}
ZYJQN_free_ips_ret(ret);
if (r != 0) {
ZYJQN_freeaddrinfo(store);
return r;
}
*res = store;
return 0;
}
void ZYJQN_freeaddrinfo(struct addrinfo* ai) {
if (ai == NULL) {
return;
}
struct addrinfo* next;
do {
next = ai->ai_next;
if (ai->ai_canonname)
free(ai->ai_canonname);
/* no need to free(ai->ai_addr) */
free(ai);
ai = next;
} while (ai);
}
void ZYJQN_set_dns_callback(ZYJQN_dns_callback cb) {
dns_callback = cb;
}
static ZYJQN_ip_report_callback ip_report_cb = NULL;
void ZYJQN_set_ip_report_callback(ZYJQN_ip_report_callback cb) {
ip_report_cb = cb;
}
void ZYJQN_ip_report(const struct addrinfo* info, int code, int time_ms) {
if (ip_report_cb == NULL || info == NULL) {
return;
}
char ip_str_buf[32] = {0};
const char* c_ip;
if (info->ai_family == AF_INET6) {
c_ip = inet_ntop(info->ai_family, &((struct sockaddr_in6*)(info->ai_addr))->sin6_addr, ip_str_buf, sizeof(ip_str_buf));
} else {
c_ip = inet_ntop(info->ai_family, &((struct sockaddr_in*)(info->ai_addr))->sin_addr, ip_str_buf, sizeof(ip_str_buf));
}
if (c_ip == NULL) {
c_ip = "";
}
ip_report_cb(c_ip, code, time_ms);
}
//
//
// ZYJQNHex.h
// ZYJHappyDNS
//
// Created by bailong on 15/7/31.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
char *ZYJQN_encodeHexData(char *output_buf, const char *data, int data_size, BOOL up);
@interface ZYJQNHex : NSObject
+ (NSString *)encodeHexData:(NSData *)data;
+ (NSString *)encodeHexString:(NSString *)str;
+ (NSData *)decodeHexString:(NSString *)hex;
+ (NSString *)decodeHexToString:(NSString *)hex;
@end
//
//
// ZYJQNHex.m
// ZYJHappyDNS
//
// Created by bailong on 15/7/31.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNHex.h"
static char DIGITS_LOWER[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
static char DIGITS_UPPER[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
static int hexDigit(char c) {
int result = -1;
if ('0' <= c && c <= '9') {
result = c - '0';
} else if ('a' <= c && c <= 'f') {
result = 10 + (c - 'a');
} else if ('A' <= c && c <= 'F') {
result = 10 + (c - 'A');
}
return result;
}
static char *decodeHex(const char *data, int size) {
if ((size & 0x01) != 0) {
return NULL;
}
char *output = malloc(size / 2);
int outLimit = 0;
for (int i = 0, j = 0; j < size; i++) {
int f = hexDigit(data[j]);
if (f < 0) {
outLimit = 1;
break;
}
j++;
int f2 = hexDigit(data[j]);
if (f2 < 0) {
outLimit = 1;
break;
}
f = (f << 4) | f2;
j++;
output[i] = (char)(f & 0xff);
}
if (outLimit) {
free(output);
return NULL;
}
return output;
}
static char *encodeHexInternal(char *output_buf, const char *data, int size, char hexTable[]) {
for (int i = 0, j = 0; i < size; i++) {
output_buf[j++] = hexTable[((0XF0 & data[i]) >> 4) & 0X0F];
output_buf[j++] = hexTable[((0X0F & data[i])) & 0X0F];
}
return output_buf;
}
static char *encodeHex(const char *data, int size, char hexTable[]) {
char *output = malloc(size * 2);
return encodeHexInternal(output, data, size, hexTable);
}
char *ZYJQN_encodeHexData(char *buff, const char *data, int data_size, BOOL up) {
char *hexTable = DIGITS_UPPER;
if (!up) {
hexTable = DIGITS_LOWER;
}
return encodeHexInternal(buff, data, data_size, hexTable);
}
@implementation ZYJQNHex
+ (NSString *)encodeHexData:(NSData *)data {
char *e = encodeHex(data.bytes, (int)data.length, DIGITS_UPPER);
NSString *str = [[NSString alloc] initWithBytes:e length:data.length * 2 encoding:NSASCIIStringEncoding];
free(e);
return str;
}
+ (NSString *)encodeHexString:(NSString *)str {
return [ZYJQNHex encodeHexData:[str dataUsingEncoding:NSUTF8StringEncoding]];
}
+ (NSData *)decodeHexString:(NSString *)hex {
char *d = decodeHex(hex.UTF8String, (int)hex.length);
if (d == NULL) {
return nil;
}
NSData *data = [NSData dataWithBytes:d length:hex.length / 2];
free(d);
return data;
}
+ (NSString *)decodeHexToString:(NSString *)hex {
NSData *data = [ZYJQNHex decodeHexString:hex];
if (data == nil) {
return nil;
}
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
@end
//
//
// ZYJQNHijackingDetectWrapper.h
// ZYJHappyDNS
//
// Created by bailong on 15/7/16.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNResolverDelegate.h"
@class ZYJQNResolver;
@interface ZYJQNHijackingDetectWrapper : NSObject <ZYJQNResolverDelegate>
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error;
- (instancetype)initWithResolver:(ZYJQNResolver *)resolver;
@end
//
//
// ZYJQNHijackingDetectWrapper.m
// ZYJHappyDNS
//
// Created by bailong on 15/7/16.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNHijackingDetectWrapper.h"
#import "ZYJQNDomain.h"
#import "ZYJQNRecord.h"
#import "ZYJQNResolver.h"
@interface ZYJQNHijackingDetectWrapper ()
@property (nonatomic, readonly) ZYJQNResolver *resolver;
@end
@implementation ZYJQNHijackingDetectWrapper
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
NSArray *result = [_resolver query:domain networkInfo:netInfo error:error];
if (((!domain.hasCname) && domain.maxTtl == 0) || result == nil || result.count == 0) {
return result;
}
BOOL hasCname = NO;
BOOL outOfTtl = NO;
for (int i = 0; i < result.count; i++) {
ZYJQNRecord *record = [result objectAtIndex:i];
if (record.type == kZYJQNTypeCname) {
hasCname = YES;
}
if (domain.maxTtl > 0 && record.type == kZYJQNTypeA && record.ttl > domain.maxTtl) {
outOfTtl = YES;
}
}
if ((domain.hasCname && !hasCname) || outOfTtl) {
if (error != nil) {
*error = [[NSError alloc] initWithDomain:domain.domain code:kZYJQNDomainHijackingCode userInfo:nil];
}
return nil;
}
return result;
}
- (instancetype)initWithResolver:(ZYJQNResolver *)resolver {
if (self = [super init]) {
_resolver = resolver;
}
return self;
}
@end
//
//
// ZYJQNHosts.h
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNResolverDelegate.h"
#import <Foundation/Foundation.h>
@interface ZYJQNHosts : NSObject
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo;
- (void)put:(NSString *)domain ip:(NSString *)ip;
- (void)put:(NSString *)domain ip:(NSString *)ip provider:(int)provider;
- (instancetype)init;
@end
//
//
// ZYJQNHosts.m
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNHosts.h"
#import "ZYJQNDomain.h"
//#import "ZYJQNIP.h"
#import "ZYJQNNetworkInfo.h"
@interface ZYJQNHosts ()
@property (nonatomic) NSMutableDictionary *dict;
@end
@interface ZYJQNHostsValue : NSObject
@property (nonatomic, copy, readonly) NSString *ip;
@property (readonly) int provider;
@end
@implementation ZYJQNHostsValue
- (instancetype)init:(NSString *)ip provider:(int)provider {
if (self = [super init]) {
_ip = ip;
_provider = provider;
}
return self;
}
@end
static NSArray *filter(NSArray *input, int provider) {
NSMutableArray *normal = [[NSMutableArray alloc] initWithCapacity:input.count];
NSMutableArray *special = [[NSMutableArray alloc] init];
for (ZYJQNHostsValue *v in input) {
NSString *ip = v.ip;
if (v.provider == kZYJQNISP_GENERAL) {
[normal addObject:ip];
}
if (provider == v.provider && provider != kZYJQNISP_GENERAL) {
[special addObject:ip];
}
}
if (special.count != 0) {
return special;
}
return normal;
}
@implementation ZYJQNHosts
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo {
NSMutableArray *x;
@synchronized(_dict) {
x = [_dict objectForKey:domain.domain];
}
if (x == nil || x.count == 0) {
return nil;
}
if (x.count >= 2) {
ZYJQNHostsValue *first = [x firstObject];
[x removeObjectAtIndex:0];
[x addObject:first];
}
return filter(x, netInfo.provider);
}
- (void)put:(NSString *)domain ip:(NSString *)ip {
[self put:domain ip:ip provider:kZYJQNISP_GENERAL];
}
- (void)put:(NSString *)domain ip:(NSString *)ip provider:(int)provider {
ZYJQNHostsValue *v = [[ZYJQNHostsValue alloc] init:ip provider:provider];
@synchronized(_dict) {
NSMutableArray *x = [_dict objectForKey:domain];
if (x == nil) {
x = [[NSMutableArray alloc] init];
}
[x addObject:v];
[_dict setObject:x forKey:domain];
}
}
- (instancetype)init {
if (self = [super init]) {
_dict = [[NSMutableDictionary alloc] init];
}
return self;
}
@end
//
//
// ZYJQNHttpResponseInfo.h
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2020/4/19.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
@class ZYJQNSessionStatistics;
@interface ZYJQNHttpResponseInfo : NSObject
/**
* 状态码
*/
@property (nonatomic, assign, readonly) int64_t statusCode;
/**
* 服务器域名
*/
@property (nonatomic, copy, readonly) NSString *host;
/**
* 错误信息
*/
@property (nonatomic, copy, readonly) NSError *error;
/**
* 是否有httpResponse
*/
@property (nonatomic, assign, readonly) BOOL hasHttpResponse;
/**
* 七牛服务器生成的请求ID
*/
@property (nonatomic, copy, readonly) NSString *reqId;
/**
* 七牛服务器内部跟踪记录
*/
@property (nonatomic, copy, readonly) NSString *xlog;
/**
* cdn服务器内部跟踪记录
*/
@property (nonatomic, copy, readonly) NSString *xvia;
/**
* 成功的请求
*/
@property (nonatomic, assign, readonly, getter=isOK) BOOL ok;
/**
* 是否需要重试
*/
@property (nonatomic, assign, readonly) BOOL couldRetry;
/**
* 服务端ip
*/
@property (nonatomic, copy, readonly) NSString *remoteIp;
/**
* 服务端端口号
*/
@property (nonatomic, assign, readonly) int64_t port;
/**
* 当前时间戳
*/
@property (nonatomic, assign, readonly) int64_t timeStamp;
/**
* 从发送请求到收到响应之间的单调时间差,单位为毫秒
*/
@property (nonatomic, assign, readonly) int64_t totalElapsedTime;
/**
* 一次请求中 DNS 查询的耗时,单位为毫秒
*/
@property (nonatomic, assign, readonly) int64_t dnsElapsedTime;
/**
* ⼀次请求中建立网络连接的耗时,单位为毫秒
*/
@property (nonatomic, assign, readonly) int64_t connectElapsedTime;
/**
* ⼀次请求中建立安全⽹络连接的耗时,单位为毫秒
*/
@property (nonatomic, assign, readonly) int64_t tlsConnectElapsedTime;
/**
* ⼀次请求中发送请求的耗时,单位为毫秒
*/
@property (nonatomic, assign, readonly) int64_t requestElapsedTime;
/**
* ⼀次请求中从发送请求完毕到收到响应前的耗时,单位为毫秒
*/
@property (nonatomic, assign, readonly) int64_t waitElapsedTime;
/**
* ⼀次请求中读取响应的耗时,单位为毫秒
*/
@property (nonatomic, assign, readonly) int64_t responseElapsedTime;
/**
* 本次成功发送请求的请求体大⼩,单位为字节
*/
@property (nonatomic, assign, readonly) int64_t bytesSent;
/**
* 预期发送请求的请求体大小,单位为字节
*/
@property (nonatomic, assign, readonly) int64_t bytesTotal;
/**
* 错误类型 用于信息上报
*/
@property (nonatomic, copy, readonly) NSString *errorType;
/**
* 错误描述 用于信息上报
*/
@property (nonatomic, copy, readonly) NSString *errorDescription;
/**
* 请求是否经过代理服务器
*/
@property (nonatomic, assign, readonly, getter=isProxyConnection) BOOL proxyConnection;
/**
* 请求完成时回调的进程id
*/
@property (nonatomic, assign, readonly) int64_t pid;
/**
* 请求完成时回调的线程id
*/
@property (nonatomic, assign, readonly) int64_t tid;
/**
* 请求结束时的网络类型(需要访问私有属性 statusBar层级结构不稳定 暂不做统计)
*/
@property (nonatomic, copy, readonly) NSString *networkType;
/**
* 请求结束时的信号强度(需要访问私有属性 statusBar层级结构不稳定 暂不做统计)
*/
@property (nonatomic, assign, readonly) int64_t signalStrength;
/**
* 构造函数
*
* @param host 请求域名
* @param response httpReponse
* @param body httpBody
* @param error 错误信息
* @param sessionStatistics 上传统计数据
*
* @return 实例
*/
+ (ZYJQNHttpResponseInfo *)buildResponseInfoHost:(NSString *)host
response:(NSHTTPURLResponse *)response
body:(NSData *)body
error:(NSError *)error
sessionStatistics:(ZYJQNSessionStatistics *)sessionStatistics;
/**
* status == 200 时获取解析后的response body
*/
- (NSDictionary *)getResponseBody;
@end
//
//
// ZYJQNHttpResponseInfo.m
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2020/4/19.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNHttpResponseInfo.h"
#import "ZYJQNSystemTool.h"
#import "ZYJQNUploadInfoCollector.h"
#import "ZYJQNUserAgent.h"
#import "ZYJQNVersion.h"
#import "ZYJQNSessionManager.h"
@interface ZYJQNHttpResponseInfo ()
@property (nonatomic, strong) NSDictionary *responseBody;
@end
@implementation ZYJQNHttpResponseInfo
+ (ZYJQNHttpResponseInfo *)buildResponseInfoHost:(NSString *)host
response:(NSHTTPURLResponse *)response
body:(NSData *)body
error:(NSError *)error
sessionStatistics:(ZYJQNSessionStatistics *)sessionStatistics {
return [[[self class] alloc] initWithResponseInfoHost:host response:response body:body error:error sessionStatistics:sessionStatistics];
}
- (instancetype)initWithResponseInfoHost:(NSString *)host
response:(NSHTTPURLResponse *)response
body:(NSData *)body
error:(NSError *)error
sessionStatistics:(ZYJQNSessionStatistics *)sessionStatistics {
self = [super init];
if (self) {
_statusCode = ZYJQN_IntNotSet;
_signalStrength = ZYJQN_IntNotSet;
_proxyConnection = NO;
_hasHttpResponse = NO;
_host = host;
_pid = [ZYJQNSystemTool getCurrentProcessID];
_tid = [ZYJQNSystemTool getCurrentThreadID];
_timeStamp = [[NSDate date] timeIntervalSince1970];
_bytesSent = sessionStatistics.bytesSent;
_bytesTotal = sessionStatistics.bytesTotal;
_remoteIp = sessionStatistics.remoteIp;
_port = sessionStatistics.port;
_totalElapsedTime = sessionStatistics.totalElapsedTime;
_dnsElapsedTime = sessionStatistics.dnsElapsedTime;
_connectElapsedTime = sessionStatistics.connectElapsedTime;
_tlsConnectElapsedTime = sessionStatistics.tlsConnectElapsedTime;
_requestElapsedTime = sessionStatistics.requestElapsedTime;
_waitElapsedTime = sessionStatistics.waitElapsedTime;
_responseElapsedTime = sessionStatistics.responseElapsedTime;
_proxyConnection = sessionStatistics.isProxyConnection;
if (response) {
_hasHttpResponse = YES;
int statusCode = (int)[response statusCode];
NSDictionary *headers = [response allHeaderFields];
_statusCode = statusCode;
_reqId = headers[@"X-Reqid"];
_xlog = headers[@"X-Log"];
_xvia = !headers[@"X-Via"] ? (!headers[@"X-Px"] ? headers[@"Fw-Via"] : headers[@"X-Px"]) : headers[@"X-Via"];
if (statusCode != 200) {
if (response.statusCode / 100 == 4) {
_errorType = ZYJbad_request;
} else {
_errorType = ZYJresponse_error;
}
if (body == nil) {
_error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:nil];
} else {
NSError *tmp;
NSDictionary *uInfo = [NSJSONSerialization JSONObjectWithData:body options:NSJSONReadingMutableLeaves error:&tmp];
if (tmp != nil) {
// 出现错误时,如果信息是非UTF8编码会失败,返回nil
NSString *str = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
if (str == nil) {
str = @"";
}
uInfo = @{ @"error" : str };
}
_error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:uInfo];
}
} else if (body == nil || body.length == 0) {
NSDictionary *uInfo = @{ @"error" : @"no response json" };
_errorType = ZYJunknown_error;
_error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:uInfo];
} else {
NSError *tmp;
NSDictionary *responseBody = [NSJSONSerialization JSONObjectWithData:body options:NSJSONReadingMutableLeaves error:&tmp];
if (!error) {
_responseBody = responseBody;
} else {
NSDictionary *uInfo = @{ @"error" : @"JSON serialization failed" };
_errorType = ZYJparse_error;
_error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:uInfo];
}
}
} else {
_hasHttpResponse = NO;
if (error) {
_error = error;
_statusCode = (int)error.code;
_errorDescription = _error.localizedDescription;
if (self.isProxyConnection) {
_errorType = ZYJproxy_error;
} else {
if (error.code == -1 || error.code == -1009) {
_errorType = ZYJnetwork_error;
} else if (error.code == -1001) {
_errorType = ZYJnetwork_timeout;
} else if (error.code == -1003 || error.code == -1006) {
_errorType = ZYJunknown_host;
} else if (error.code == -1004) {
_errorType = ZYJcannot_connect_to_host;
} else if (error.code == -1005 || error.code == -1011) {
_errorType = ZYJtransmission_error;
} else if (error.code > -2001 && error.code < -1199) {
_errorType = ZYJssl_error;
} else if (error.code == -1007 || error.code == -1010) {
_errorType = ZYJmalicious_response;
} else if (error.code == -1015 || error.code == -1016 || error.code == -1017) {
_errorType = ZYJparse_error;
} else if (error.code == -999) {
_errorType = ZYJuser_canceled;
} else if (error.code == 100) {
_errorType = ZYJprotocol_error;
} else {
_errorType = ZYJunknown_error;
}
}
}
}
}
return self;
}
- (BOOL)isOK {
return _statusCode == 200 && _error == nil && _reqId != nil;
}
- (BOOL)couldRetry {
return (_statusCode >= 500 && _statusCode < 600 && _statusCode != 579) || _statusCode == 996 || _statusCode == 406 || (_statusCode == 200 && _error != nil) || _statusCode < -1000 || self.isNotQiniu;
}
- (BOOL)isNotQiniu {
return (_statusCode >= 200 && _statusCode < 500) && _reqId == nil;
}
- (NSDictionary *)getResponseBody {
return self.isOK ? self.responseBody : nil;
}
- (int64_t)getTimeintervalWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate {
if (!startDate || !endDate) return 0;
NSTimeInterval interval = [endDate timeIntervalSinceDate:startDate];
return interval * 1000;
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@= id: %@, ver: %@, status: %lld, requestId: %@, xlog: %@, xvia: %@, host: %@ duration: %.3f s time: %llu error: %@>", NSStringFromClass([self class]), [ZYJQNUserAgent sharedInstance].id, kQiniuVersion, _statusCode, _reqId, _xlog, _xvia, _host, _totalElapsedTime / 1000.0, _timeStamp, _error];
}
@end
//
//
// ZYJQNIPV6.h
// ZYJHappyDNS
//
// Created by bailong on 16/5/25.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
extern int ZYJQN_localIp(char *buf, int buf_size);
extern void ZYJQN_nat64(char *buf, int buf_size, uint32_t ipv4_addr);
@interface ZYJQNIP : NSObject
+ (BOOL)isV6;
+ (NSString *)adaptiveIp:(NSString *)ipv4;
+ (NSString *)local;
// ipv6 in url like http://[::xxx]/
+ (NSString *)ipHost:(NSString *)ip;
+ (NSString *)nat64:(NSString *)ip;
+ (BOOL)isIpV6FullySupported;
+ (BOOL)mayBeIpV4:(NSString *)domain;
@end
//
//
// ZYJQNIPV6.m
// ZYJHappyDNS
//
// Created by bailong on 16/5/25.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import <arpa/inet.h>
#import <netdb.h>
#import <netinet/in.h>
#import <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#import "ZYJQNHex.h"
#import "ZYJQNIP.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#import <MobileCoreServices/MobileCoreServices.h>
#import <UIKit/UIKit.h>
#endif
void ZYJQN_nat64(char *buf, int buf_size, uint32_t ipv4addr) {
bzero(buf, buf_size);
//nat 4 to ipv6
const char *p = (const char *)&ipv4addr;
const char prefix[] = "64:ff9b::";
memcpy(buf, prefix, sizeof(prefix));
char *phex = buf + sizeof(prefix) - 1;
ZYJQN_encodeHexData(phex, p, 2, false);
if (*phex == '0') {
memmove(phex, phex + 1, 3);
phex += 3;
} else {
phex += 4;
}
*phex = ':';
phex++;
ZYJQN_encodeHexData(phex, p + 2, 2, false);
if (*phex == '0') {
memmove(phex, phex + 1, 3);
phex[3] = 0;
}
}
int ZYJQN_local_ip_internal(char *buf, int buf_size, const char *t_ip) {
struct addrinfo hints = {0}, *ai;
int err = 0;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
int ret = getaddrinfo(t_ip, "53", &hints, &ai);
if (ret != 0) {
err = errno;
return err;
}
int family = ai->ai_family;
int sock = socket(family, ai->ai_socktype, 0);
if (sock < 0) {
err = errno;
freeaddrinfo(ai);
return err;
}
//fix getaddrinfo bug in ipv4 to ipv6
if (ai->ai_family == AF_INET6) {
((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53);
}
err = connect(sock, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
if (err < 0) {
close(sock);
err = errno;
return err;
}
uint32_t localAddress[16] = {0};
socklen_t addressLength = sizeof(localAddress);
err = getsockname(sock, (struct sockaddr *)&localAddress, &addressLength);
close(sock);
if (err != 0) {
return err;
}
void *addr;
if (family == AF_INET6) {
addr = &((struct sockaddr_in6 *)&localAddress)->sin6_addr;
} else {
addr = &((struct sockaddr_in *)&localAddress)->sin_addr;
}
const char *ip = inet_ntop(family, addr, buf, buf_size);
if (ip == nil) {
return -1;
}
return 0;
}
int ZYJQN_localIp(char *buf, int buf_size) {
int ret = ZYJQN_local_ip_internal(buf, buf_size, "8.8.8.8");
if (ret != 0) {
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
if (![ZYJQNIP isIpV6FullySupported]) {
ret = ZYJQN_local_ip_internal(buf, buf_size, "64:ff9b::808:808");
}
#endif
}
return ret;
}
@implementation ZYJQNIP
+ (BOOL)isV6 {
struct addrinfo hints = {0}, *ai;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int ret = getaddrinfo("8.8.8.8", "http", &hints, &ai);
if (ret != 0) {
return NO;
}
int family = ai->ai_family;
freeaddrinfo(ai);
BOOL result = family == AF_INET6;
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
if (![ZYJQNIP isIpV6FullySupported] && !ret) {
char buf[64] = {0};
ret = ZYJQN_local_ip_internal(buf, sizeof(buf), "64:ff9b::808:808");
if (strchr(buf, ':') != NULL) {
result = YES;
}
}
#endif
return result;
}
+ (NSString *)adaptiveIp:(NSString *)ipv4 {
struct addrinfo hints = {0}, *ai;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int ret = getaddrinfo(ipv4.UTF8String, "http", &hints, &ai);
if (ret != 0) {
return nil;
}
int family = ai->ai_family;
void *addr;
if (family == AF_INET6) {
addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
} else {
addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
}
char buf[64] = {0};
const char *ip = inet_ntop(family, addr, buf, sizeof(buf));
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
if (![ZYJQNIP isIpV6FullySupported] && family == AF_INET) {
char buf2[64] = {0};
ret = ZYJQN_local_ip_internal(buf2, sizeof(buf2), "64:ff9b::808:808");
if (strchr(buf2, ':') != NULL) {
bzero(buf, sizeof(buf));
ZYJQN_nat64(buf, sizeof(buf), *((uint32_t *)addr));
}
}
#endif
freeaddrinfo(ai);
return [NSString stringWithUTF8String:ip];
}
+ (NSString *)local {
char buf[64] = {0};
int err = ZYJQN_localIp(buf, sizeof(buf));
if (err != 0) {
return nil;
}
return [NSString stringWithUTF8String:buf];
}
+ (NSString *)ipHost:(NSString *)ip {
NSRange range = [ip rangeOfString:@":"];
if (range.location != NSNotFound) {
return [NSString stringWithFormat:@"[%@]", ip];
}
return ip;
}
+ (NSString *)nat64:(NSString *)ip {
struct in_addr s = {0};
inet_pton(AF_INET, ip.UTF8String, (void *)&s);
char buf[64] = {0};
ZYJQN_nat64(buf, sizeof(buf), (uint32_t)s.s_addr);
return [NSString stringWithUTF8String:buf];
}
+ (BOOL)isIpV6FullySupported {
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED)
float sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (sysVersion < 9.0) {
return NO;
}
#else
NSOperatingSystemVersion sysVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
if (sysVersion.majorVersion < 10) {
return NO;
} else if (sysVersion.majorVersion == 10) {
return sysVersion.minorVersion >= 11;
}
#endif
return YES;
}
+ (BOOL)mayBeIpV4:(NSString *)domain {
NSUInteger l = domain.length;
if (l > 15 || l < 7) {
return NO;
}
const char *str = domain.UTF8String;
if (str == nil) {
return NO;
}
for (const char *p = str; p < str + l; p++) {
if ((*p < '0' || *p > '9') && *p != '.') {
return NO;
}
}
return YES;
}
@end
//
//
// ZYJQNInetAddress.h
// ZYJQiniuSDK
//
// Created by 杨森 on 2020/7/27.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNDns.h"
NS_ASSUME_NONNULL_BEGIN
@interface ZYJQNInetAddress : NSObject <ZYJQNInetAddressDelegate>
@property(nonatomic, copy)NSString *hostValue;
@property(nonatomic, copy)NSString *ipValue;
@property(nonatomic, strong)NSNumber *ttlValue;
@property(nonatomic, strong)NSNumber *timestampValue;
/// 构造方法 addressData为json String / Dictionary / Data / 遵循 ZYJQNInetAddressDelegate的实例
+ (instancetype)inetAddress:(id)addressInfo;
/// 是否有效,根据时间戳判断
- (BOOL)isValid;
/// 对象转json
- (NSString *)toJsonInfo;
/// 对象转字典
- (NSDictionary *)toDictionary;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNInetAddress.m
// ZYJQiniuSDK
//
// Created by 杨森 on 2020/7/27.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNInetAddress.h"
@interface ZYJQNInetAddress()
@end
@implementation ZYJQNInetAddress
+ (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(ZYJQNInetAddressDelegate)]){
id <ZYJQNInetAddressDelegate> address = (id <ZYJQNInetAddressDelegate> )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) {
ZYJQNInetAddress *address = [[ZYJQNInetAddress 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
//
//
// HistoryModel.h
// ZYJHappyDNS
//
// Created by bailong on 16/7/19.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYJQNIpModel : NSObject
@end
//
//
// HistoryModel.m
// ZYJHappyDNS
//
// Created by bailong on 16/7/19.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNIpModel.h"
@implementation ZYJQNIpModel
@end
//
//
// ZYJQNLruCache.h
// ZYJHappyDNS
//
// Created by bailong on 16/7/5.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYJQNLruCache : NSObject
- (instancetype)init:(NSUInteger)limit;
- (void)removeAllObjects;
- (void)removeObjectForKey:(NSString *)key;
- (id)objectForKey:(NSString *)key;
- (void)setObject:(id)obj forKey:(NSString *)key;
@end
//
//
// ZYJQNLruCache.m
// ZYJHappyDNS
//
// Created by bailong on 16/7/5.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNLruCache.h"
@interface ZYJQNLruCache ()
@property (nonatomic, readonly) NSUInteger limit;
@property (nonatomic, readonly) NSMutableDictionary* cache;
@property (nonatomic, readonly) NSMutableArray* list;
@end
@interface _ZYJQNElement : NSObject
@property (nonatomic, readonly, strong) NSString* key;
@property (nonatomic, strong) id obj;
- (instancetype)initObject:(id)obj forKey:(NSString*)key;
@end
@implementation _ZYJQNElement
- (instancetype)initObject:(id)obj forKey:(NSString*)key {
if (self = [super init]) {
_key = key;
_obj = obj;
}
return self;
}
@end
@implementation ZYJQNLruCache
- (instancetype)init:(NSUInteger)limit {
if (self = [super init]) {
_limit = limit;
_cache = [NSMutableDictionary new];
_list = [NSMutableArray new];
}
return self;
}
- (void)removeAllObjects {
[_cache removeAllObjects];
[_list removeAllObjects];
}
- (void)removeObjectForKey:(NSString*)key {
_ZYJQNElement* obj = [_cache objectForKey:key];
if (obj == nil) {
return;
}
[_cache removeObjectForKey:key];
[_list removeObjectIdenticalTo:obj];
}
- (id)objectForKey:(NSString*)key {
_ZYJQNElement* obj = [_cache objectForKey:key];
if (obj != nil) {
[_list removeObjectIdenticalTo:obj];
[_list insertObject:obj atIndex:0];
}
return obj.obj;
}
- (void)setObject:(id)obj forKey:(NSString*)key {
_ZYJQNElement* old = [_cache objectForKey:key];
if (old) {
old.obj = obj;
[_list removeObjectIdenticalTo:old];
[_list insertObject:old atIndex:0];
return;
} else if (_list.count == _limit) {
old = [_list lastObject];
[_list removeLastObject];
[_cache removeObjectForKey:old.key];
}
_ZYJQNElement* newElement = [[_ZYJQNElement alloc] initObject:obj forKey:key];
[_cache setObject:newElement forKey:key];
[_list insertObject:newElement atIndex:0];
}
@end
//
//
// ZYJQNMD5.h
// ZYJHappyDNS_Mac
//
// Created by 何昊宇 on 2018/4/25.
// Copyright © 2018年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYJQNMD5 : NSObject
+(NSString *)MD5:(NSString *)string;
@end
//
//
// ZYJQNMD5.m
// ZYJHappyDNS_Mac
//
// Created by 何昊宇 on 2018/4/25.
// Copyright © 2018年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNMD5.h"
#import <CommonCrypto/CommonDigest.h>
@implementation ZYJQNMD5
+ (NSString *)MD5:(NSString *)string{
const char* input = [string UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(input, (CC_LONG)strlen(input), result);
NSMutableString *digest = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for (NSInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[digest appendFormat:@"%02x", result[i]];
}
return digest;
}
@end
//
//
// ZYJQNNetworkInfo.h
// ZYJHappyDNS
//
// Created by bailong on 15/6/25.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
extern const int kZYJQNNO_NETWORK;
extern const int kZYJQNWIFI;
extern const int kZYJQNMOBILE;
extern const int kZYJQNISP_GENERAL;
extern const int kZYJQNISP_CTC;
extern const int kZYJQNISP_DIANXIN;
extern const int kZYJQNISP_CNC;
extern const int kZYJQNISP_LIANTONG;
extern const int kZYJQNISP_CMCC;
extern const int kZYJQNISP_YIDONG;
extern const int kZYJQNISP_OTHER;
@interface ZYJQNNetworkInfo : NSObject
@property (nonatomic, readonly) int networkConnection;
@property (nonatomic, readonly) int provider;
- (instancetype)init:(int)connecton provider:(int)provider;
- (BOOL)isEqual:(id)other;
- (BOOL)isEqualToInfo:(ZYJQNNetworkInfo *)info;
+ (instancetype)noNet;
+ (instancetype)normal;
+ (BOOL)isNetworkChanged;
+ (NSString *)getIp;
@end
//
//
// ZYJQNNetworkInfo.m
// ZYJHappyDNS
//
// Created by bailong on 15/6/25.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#import "ZYJQNIP.h"
#import "ZYJQNNetworkInfo.h"
const int kZYJQNNO_NETWORK = -1;
const int kZYJQNWIFI = 1;
const int kZYJQNMOBILE = 2;
const int kZYJQNISP_GENERAL = 0;
const int kZYJQNISP_CTC = 1;
const int kZYJQNISP_DIANXIN = kZYJQNISP_CTC;
const int kZYJQNISP_CNC = 2;
const int kZYJQNISP_LIANTONG = kZYJQNISP_CNC;
const int kZYJQNISP_CMCC = 3;
const int kZYJQNISP_YIDONG = kZYJQNISP_CMCC;
const int kZYJQNISP_OTHER = 999;
#define IPLength 64
static char previousIp[IPLength] = {0};
static NSString *lock = @"";
@implementation ZYJQNNetworkInfo
- (instancetype)init:(int)connecton provider:(int)provider {
if (self = [super init]) {
_networkConnection = connecton;
_provider = provider;
}
return self;
}
+ (instancetype)noNet {
return [[ZYJQNNetworkInfo alloc] init:kZYJQNNO_NETWORK provider:kZYJQNISP_GENERAL];
}
+ (instancetype)normal {
return [[ZYJQNNetworkInfo alloc] init:kZYJQNISP_GENERAL provider:kZYJQNISP_GENERAL];
}
- (BOOL)isEqualToInfo:(ZYJQNNetworkInfo *)info {
if (self == info)
return YES;
return self.provider == info.provider && self.networkConnection == info.networkConnection;
}
- (BOOL)isEqual:(id)other {
if (other == self)
return YES;
if (!other || ![other isKindOfClass:[self class]])
return NO;
return [self isEqualToInfo:other];
}
+ (BOOL)isNetworkChanged {
@synchronized(lock) {
char local[IPLength] = {0};
int err = ZYJQN_localIp(local, sizeof(local));
if (err != 0) {
return YES;
}
if (memcmp(previousIp, local, sizeof(local)) != 0) {
memcpy(previousIp, local, sizeof(local));
return YES;
}
return NO;
}
}
+ (NSString *)getIp {
return [ZYJQNIP local];
}
@end
//
//
// ZYJQNPHAssetFile.h
// Pods
//
// Created by 何舒 on 15/10/21.
//
//
#import <Foundation/Foundation.h>
#import "ZYJQNFileDelegate.h"
@class PHAsset;
API_AVAILABLE(ios(9.1)) @interface ZYJQNPHAssetFile : NSObject <ZYJQNFileDelegate>
/**
* 打开指定文件
*
* @param phAsset 文件资源
* @param error 输出的错误信息
*
* @return 实例
*/
- (instancetype)init:(PHAsset *)phAsset
error:(NSError *__autoreleasing *)error;
@end
//
//
// ZYJQNPHAssetFile.m
// Pods
//
// Created by 何舒 on 15/10/21.
//
//
#import "ZYJQNPHAssetFile.h"
#import <Photos/Photos.h>
#import "ZYJQNResponseInfo.h"
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100)
@interface ZYJQNPHAssetFile ()
@property (nonatomic) PHAsset *phAsset;
@property (nonatomic) int64_t fileSize;
@property (nonatomic) int64_t fileModifyTime;
@property (nonatomic, strong) NSData *assetData;
@property (nonatomic, strong) NSURL *assetURL;
@property (nonatomic, readonly) NSString *filepath;
@property (nonatomic) NSFileHandle *file;
@property (nonatomic, strong) NSLock *lock;
@end
@implementation ZYJQNPHAssetFile
- (instancetype)init:(PHAsset *)phAsset error:(NSError *__autoreleasing *)error {
if (self = [super init]) {
NSDate *createTime = phAsset.creationDate;
int64_t t = 0;
if (createTime != nil) {
t = [createTime timeIntervalSince1970];
}
_fileModifyTime = t;
_phAsset = phAsset;
_filepath = [self getInfo];
_lock = [[NSLock alloc] init];
if (PHAssetMediaTypeVideo == self.phAsset.mediaType) {
NSError *error2 = nil;
NSDictionary *fileAttr = [[NSFileManager defaultManager] attributesOfItemAtPath:_filepath error:&error2];
if (error2 != nil) {
if (error != nil) {
*error = error2;
}
return self;
}
_fileSize = [fileAttr fileSize];
NSFileHandle *f = nil;
NSData *d = nil;
if (_fileSize > 16 * 1024 * 1024) {
f = [NSFileHandle fileHandleForReadingAtPath:_filepath];
if (f == nil) {
if (error != nil) {
*error = [[NSError alloc] initWithDomain:_filepath code:kZYJQNFileError userInfo:nil];
}
return self;
}
} else {
d = [NSData dataWithContentsOfFile:_filepath options:NSDataReadingMappedIfSafe error:&error2];
if (error2 != nil) {
if (error != nil) {
*error = error2;
}
return self;
}
}
_file = f;
_assetData = d;
}
}
return self;
}
- (NSData *)read:(long)offset
size:(long)size
error:(NSError **)error {
NSData *data = nil;
@try {
[_lock lock];
if (_assetData != nil) {
data = [_assetData subdataWithRange:NSMakeRange(offset, (unsigned int)size)];
} else {
[_file seekToFileOffset:offset];
data = [_file readDataOfLength:size];
}
} @catch (NSException *exception) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:kZYJQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}];
NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols);
} @finally {
[_lock unlock];
}
return data;
}
- (NSData *)readAllWithError:(NSError **)error {
return [self read:0 size:(long)_fileSize error:error];
}
- (void)close {
if (PHAssetMediaTypeVideo == self.phAsset.mediaType) {
if (_file != nil) {
[_file closeFile];
}
[[NSFileManager defaultManager] removeItemAtPath:_filepath error:nil];
}
}
- (NSString *)path {
return _filepath;
}
- (int64_t)modifyTime {
return _fileModifyTime;
}
- (int64_t)size {
return _fileSize;
}
- (NSString *)getInfo {
__block NSString *filePath = nil;
if (PHAssetMediaTypeImage == self.phAsset.mediaType) {
PHImageRequestOptions *options = [PHImageRequestOptions new];
options.version = PHImageRequestOptionsVersionCurrent;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.resizeMode = PHImageRequestOptionsResizeModeNone;
//不支持icloud上传
options.networkAccessAllowed = NO;
options.synchronous = YES;
[[PHImageManager defaultManager] requestImageDataForAsset:self.phAsset
options:options
resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
self.assetData = imageData;
self.fileSize = imageData.length;
self.assetURL = [NSURL URLWithString:self.phAsset.localIdentifier];
filePath = self.assetURL.path;
}];
} else if (PHAssetMediaTypeVideo == self.phAsset.mediaType) {
NSArray *assetResources = [PHAssetResource assetResourcesForAsset:self.phAsset];
PHAssetResource *resource;
for (PHAssetResource *assetRes in assetResources) {
if (assetRes.type == PHAssetResourceTypePairedVideo || assetRes.type == PHAssetResourceTypeVideo) {
resource = assetRes;
}
}
NSString *fileName = @"tempAssetVideo.mov";
if (resource.originalFilename) {
fileName = resource.originalFilename;
}
PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new];
//不支持icloud上传
options.networkAccessAllowed = NO;
NSString *PATH_VIDEO_FILE = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
[[NSFileManager defaultManager] removeItemAtPath:PATH_VIDEO_FILE error:nil];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[[PHAssetResourceManager defaultManager] writeDataForAssetResource:resource toFile:[NSURL fileURLWithPath:PATH_VIDEO_FILE] options:options completionHandler:^(NSError *_Nullable error) {
if (error) {
filePath = nil;
} else {
filePath = PATH_VIDEO_FILE;
}
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
return filePath;
}
@end
#endif
//
//
// ZYJQNPHAssetResource.h
// ZYJQiniuSDK
//
// Created by 何舒 on 16/2/14.
// Copyright © 2016年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNFileDelegate.h"
@class PHAssetResource;
API_AVAILABLE(ios(9.0)) @interface ZYJQNPHAssetResource : NSObject <ZYJQNFileDelegate>
/**
* 打开指定文件
*
* @param phAssetResource PHLivePhoto的PHAssetResource文件
* @param error 输出的错误信息
*
* @return 实例
*/
- (instancetype)init:(PHAssetResource *)phAssetResource
error:(NSError *__autoreleasing *)error;
@end
//
//
// ZYJQNPHAssetResource.m
// ZYJQiniuSDK
//
// Created by 何舒 on 16/2/14.
// Copyright © 2016年 Qiniu. All rights reserved.
//
#import "ZYJQNPHAssetResource.h"
#import <Photos/Photos.h>
#import "ZYJQNResponseInfo.h"
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000)
enum {
kAMASSETMETADATA_PENDINGREADS = 1,
kAMASSETMETADATA_ALLFINISHED = 0
};
@interface ZYJQNPHAssetResource () {
BOOL _hasGotInfo;
}
@property (nonatomic) PHAsset *phAsset;
@property (nonatomic) PHAssetResource *phAssetResource;
@property (nonatomic) int64_t fileSize;
@property (nonatomic) int64_t fileModifyTime;
@property (nonatomic, strong) NSData *assetData;
@property (nonatomic, strong) NSURL *assetURL;
@property (nonatomic, strong) NSLock *lock;
@end
@implementation ZYJQNPHAssetResource
- (instancetype)init:(PHAssetResource *)phAssetResource
error:(NSError *__autoreleasing *)error {
if (self = [super init]) {
PHAsset *phasset = [PHAsset fetchAssetsWithBurstIdentifier:self.phAssetResource.assetLocalIdentifier options:nil][0];
NSDate *createTime = phasset.creationDate;
int64_t t = 0;
if (createTime != nil) {
t = [createTime timeIntervalSince1970];
}
_fileModifyTime = t;
_phAssetResource = phAssetResource;
_lock = [[NSLock alloc] init];
[self getInfo];
}
return self;
}
- (NSData *)read:(long)offset
size:(long)size
error:(NSError **)error {
NSData *data = nil;
@try {
[_lock lock];
NSRange subRange = NSMakeRange(offset, size);
if (!self.assetData) {
self.assetData = [self fetchDataFromAsset:self.phAssetResource error:error];
}
data = [self.assetData subdataWithRange:subRange];
} @catch (NSException *exception) {
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:kZYJQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}];
NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols);
} @finally {
[_lock unlock];
}
return data;
}
- (NSData *)readAllWithError:(NSError **)error {
return [self read:0 size:(long)_fileSize error:error];
}
- (void)close {
}
- (NSString *)path {
return self.assetURL.path;
}
- (int64_t)modifyTime {
return _fileModifyTime;
}
- (int64_t)size {
return _fileSize;
}
- (void)getInfo {
if (!_hasGotInfo) {
_hasGotInfo = YES;
NSConditionLock *assetReadLock = [[NSConditionLock alloc] initWithCondition:kAMASSETMETADATA_PENDINGREADS];
NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingString:self.phAssetResource.originalFilename];
NSURL *localpath = [NSURL fileURLWithPath:pathToWrite];
PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new];
options.networkAccessAllowed = YES;
[[PHAssetResourceManager defaultManager] writeDataForAssetResource:self.phAssetResource toFile:localpath options:options completionHandler:^(NSError *_Nullable error) {
if (error == nil) {
AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:localpath options:nil];
NSNumber *fileSize = nil;
[urlAsset.URL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:nil];
self.fileSize = [fileSize unsignedLongLongValue];
self.assetURL = urlAsset.URL;
self.assetData = [NSData dataWithData:[NSData dataWithContentsOfURL:urlAsset.URL]];
} else {
NSLog(@"%@", error);
}
BOOL blHave = [[NSFileManager defaultManager] fileExistsAtPath:pathToWrite];
if (!blHave) {
return;
} else {
[[NSFileManager defaultManager] removeItemAtPath:pathToWrite error:nil];
}
[assetReadLock lock];
[assetReadLock unlockWithCondition:kAMASSETMETADATA_ALLFINISHED];
}];
[assetReadLock lockWhenCondition:kAMASSETMETADATA_ALLFINISHED];
[assetReadLock unlock];
assetReadLock = nil;
}
}
- (NSData *)fetchDataFromAsset:(PHAssetResource *)videoResource error:(NSError **)err {
__block NSData *tmpData = [NSData data];
__block NSError *innerError = *err;
NSConditionLock *assetReadLock = [[NSConditionLock alloc] initWithCondition:kAMASSETMETADATA_PENDINGREADS];
NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingString:videoResource.originalFilename];
NSURL *localpath = [NSURL fileURLWithPath:pathToWrite];
PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new];
options.networkAccessAllowed = YES;
[[PHAssetResourceManager defaultManager] writeDataForAssetResource:videoResource toFile:localpath options:options completionHandler:^(NSError *_Nullable error) {
if (error == nil) {
AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:localpath options:nil];
NSData *videoData = [NSData dataWithContentsOfURL:urlAsset.URL];
tmpData = [NSData dataWithData:videoData];
} else {
innerError = error;
}
BOOL blHave = [[NSFileManager defaultManager] fileExistsAtPath:pathToWrite];
if (!blHave) {
return;
} else {
[[NSFileManager defaultManager] removeItemAtPath:pathToWrite error:nil];
}
[assetReadLock lock];
[assetReadLock unlockWithCondition:kAMASSETMETADATA_ALLFINISHED];
}];
[assetReadLock lockWhenCondition:kAMASSETMETADATA_ALLFINISHED];
[assetReadLock unlock];
assetReadLock = nil;
return tmpData;
}
@end
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment