Commit 9c7f79da by zhangyunjie

重编译七牛SDK

parent 925afddc
......@@ -210,6 +210,67 @@
A9D1B33A24FE2DAC000F4662 /* oimcore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9D1B33824FE2DA7000F4662 /* oimcore.framework */; };
A9D1B33B24FE2DAC000F4662 /* oimcore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A9D1B33824FE2DA7000F4662 /* oimcore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
A9D1B33E24FE3BE6000F4662 /* OffcnIMSqliteTestVC.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B33D24FE3BE6000F4662 /* OffcnIMSqliteTestVC.m */; };
A9D1B60624FE765F000F4662 /* ZYJQNFile.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B58324FE765E000F4662 /* ZYJQNFile.m */; };
A9D1B60724FE765F000F4662 /* ZYJQNDnsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B58424FE765E000F4662 /* ZYJQNDnsManager.m */; };
A9D1B60824FE765F000F4662 /* ZYJQNURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B58724FE765E000F4662 /* ZYJQNURLProtocol.m */; };
A9D1B60924FE765F000F4662 /* ZYJQNGetAddrInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B58B24FE765E000F4662 /* ZYJQNGetAddrInfo.m */; };
A9D1B60A24FE765F000F4662 /* ZYJQNDnsPrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B58C24FE765E000F4662 /* ZYJQNDnsPrefetcher.m */; };
A9D1B60B24FE765F000F4662 /* ZYJQNEtag.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B58D24FE765E000F4662 /* ZYJQNEtag.m */; };
A9D1B60C24FE765F000F4662 /* ZYJQNHijackingDetectWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B58E24FE765E000F4662 /* ZYJQNHijackingDetectWrapper.m */; };
A9D1B60D24FE765F000F4662 /* ZYJQNZoneInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B59224FE765E000F4662 /* ZYJQNZoneInfo.m */; };
A9D1B60E24FE765F000F4662 /* ZYJQNCrc32.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B59424FE765E000F4662 /* ZYJQNCrc32.m */; };
A9D1B60F24FE765F000F4662 /* NSURLRequest+ZYJQNRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B59524FE765E000F4662 /* NSURLRequest+ZYJQNRequest.m */; };
A9D1B61024FE765F000F4662 /* ZYJQNFileRecorder.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5A024FE765E000F4662 /* ZYJQNFileRecorder.m */; };
A9D1B61124FE765F000F4662 /* NSObject+ZYJQNSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5A124FE765E000F4662 /* NSObject+ZYJQNSwizzle.m */; };
A9D1B61224FE765F000F4662 /* ZYJQNLruCache.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5A224FE765E000F4662 /* ZYJQNLruCache.m */; };
A9D1B61324FE765F000F4662 /* ZYJQNDnsCacheInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5A524FE765E000F4662 /* ZYJQNDnsCacheInfo.m */; };
A9D1B61424FE765F000F4662 /* ZYJQNZone.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5A924FE765E000F4662 /* ZYJQNZone.m */; };
A9D1B61524FE765F000F4662 /* ZYJQNDes.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5AC24FE765E000F4662 /* ZYJQNDes.m */; };
A9D1B61624FE765F000F4662 /* ZYJQNDnspodFree.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5AE24FE765E000F4662 /* ZYJQNDnspodFree.m */; };
A9D1B61724FE765F000F4662 /* ZYJQNAutoZone.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5AF24FE765E000F4662 /* ZYJQNAutoZone.m */; };
A9D1B61824FE765F000F4662 /* ZYJQNRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5B024FE765E000F4662 /* ZYJQNRecord.m */; };
A9D1B61924FE765F000F4662 /* ZYJQNTransactionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5B424FE765E000F4662 /* ZYJQNTransactionManager.m */; };
A9D1B61A24FE765F000F4662 /* ZYJQNUploadInfoReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5B924FE765E000F4662 /* ZYJQNUploadInfoReporter.m */; };
A9D1B61B24FE765F000F4662 /* ZYJQNInetAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5BB24FE765E000F4662 /* ZYJQNInetAddress.m */; };
A9D1B61C24FE765F000F4662 /* ZYJQNDnspodEnterprise.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5BC24FE765E000F4662 /* ZYJQNDnspodEnterprise.m */; };
A9D1B61D24FE765F000F4662 /* ZYJQNUserAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5BE24FE765E000F4662 /* ZYJQNUserAgent.m */; };
A9D1B61E24FE765F000F4662 /* ZYJQNHttpResponseInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5BF24FE765E000F4662 /* ZYJQNHttpResponseInfo.m */; };
A9D1B61F24FE765F000F4662 /* ZYJQNDomain.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5C024FE765E000F4662 /* ZYJQNDomain.m */; };
A9D1B62024FE765F000F4662 /* ZYJQNAssessment.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5C124FE765E000F4662 /* ZYJQNAssessment.m */; };
A9D1B62124FE765F000F4662 /* ZYJQNHex.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5C224FE765E000F4662 /* ZYJQNHex.m */; };
A9D1B62224FE765F000F4662 /* ZYJQNFixedZone.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5C524FE765E000F4662 /* ZYJQNFixedZone.m */; };
A9D1B62324FE765F000F4662 /* ZYJQNTxtResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5C624FE765E000F4662 /* ZYJQNTxtResolver.m */; };
A9D1B62424FE765F000F4662 /* ZYJQNConcurrentResumeUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5CB24FE765E000F4662 /* ZYJQNConcurrentResumeUpload.m */; };
A9D1B62524FE765F000F4662 /* ZYJQNUrlSafeBase64.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5CD24FE765E000F4662 /* ZYJQNUrlSafeBase64.m */; };
A9D1B62624FE765F000F4662 /* ZYJQNResolvUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5CE24FE765E000F4662 /* ZYJQNResolvUtil.m */; };
A9D1B62724FE765F000F4662 /* ZYJQN_GTM_Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5D624FE765E000F4662 /* ZYJQN_GTM_Base64.m */; };
A9D1B62824FE765F000F4662 /* ZYJQNCFHttpClient.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5D724FE765E000F4662 /* ZYJQNCFHttpClient.m */; };
A9D1B62924FE765F000F4662 /* ZYJQNResponseInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5D824FE765E000F4662 /* ZYJQNResponseInfo.m */; };
A9D1B62A24FE765F000F4662 /* ZYJQNResumeUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5D924FE765E000F4662 /* ZYJQNResumeUpload.m */; };
A9D1B62B24FE765F000F4662 /* ZYJQNFormUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5DA24FE765E000F4662 /* ZYJQNFormUpload.m */; };
A9D1B62C24FE765F000F4662 /* ZYJQNUploadInfoCollector.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5DB24FE765E000F4662 /* ZYJQNUploadInfoCollector.m */; };
A9D1B62D24FE765F000F4662 /* ZYJQNPHAssetResource.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5DC24FE765E000F4662 /* ZYJQNPHAssetResource.m */; };
A9D1B62E24FE765F000F4662 /* ZYJQNMD5.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5DF24FE765E000F4662 /* ZYJQNMD5.m */; };
A9D1B62F24FE765F000F4662 /* ZYJQNResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5E024FE765E000F4662 /* ZYJQNResolver.m */; };
A9D1B63024FE765F000F4662 /* ZYJQNSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5E124FE765E000F4662 /* ZYJQNSessionManager.m */; };
A9D1B63124FE765F000F4662 /* ZYJQNPHAssetFile.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5E324FE765E000F4662 /* ZYJQNPHAssetFile.m */; };
A9D1B63224FE765F000F4662 /* ZYJQNIpModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5E424FE765E000F4662 /* ZYJQNIpModel.m */; };
A9D1B63324FE765F000F4662 /* ZYJQNHosts.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5E524FE765E000F4662 /* ZYJQNHosts.m */; };
A9D1B63424FE765F000F4662 /* ZYJQNALAssetFile.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5E624FE765E000F4662 /* ZYJQNALAssetFile.m */; };
A9D1B63524FE765F000F4662 /* ZYJQNBaseUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5E724FE765E000F4662 /* ZYJQNBaseUpload.m */; };
A9D1B63624FE765F000F4662 /* ZYJQNSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5E924FE765E000F4662 /* ZYJQNSystem.m */; };
A9D1B63724FE765F000F4662 /* ZYJQNUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5EA24FE765E000F4662 /* ZYJQNUtils.m */; };
A9D1B63824FE765F000F4662 /* ZYJQNNetworkInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5EB24FE765E000F4662 /* ZYJQNNetworkInfo.m */; };
A9D1B63924FE765F000F4662 /* ZYJQNDnsCacheFile.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5EC24FE765E000F4662 /* ZYJQNDnsCacheFile.m */; };
A9D1B63A24FE765F000F4662 /* ZYJQNUploadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5F024FE765E000F4662 /* ZYJQNUploadManager.m */; };
A9D1B63B24FE765F000F4662 /* ZYJQNPipeline.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5F324FE765E000F4662 /* ZYJQNPipeline.m */; };
A9D1B63C24FE765F000F4662 /* ZYJQNAsyncRun.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5F424FE765E000F4662 /* ZYJQNAsyncRun.m */; };
A9D1B63D24FE765F000F4662 /* ZYJQNConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5F524FE765E000F4662 /* ZYJQNConfiguration.m */; };
A9D1B63E24FE765F000F4662 /* ZYJQNUploadOption.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5F624FE765F000F4662 /* ZYJQNUploadOption.m */; };
A9D1B63F24FE765F000F4662 /* ZYJQNRefresher.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5F824FE765F000F4662 /* ZYJQNRefresher.m */; };
A9D1B64024FE765F000F4662 /* ZYJQNUpToken.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5F924FE765F000F4662 /* ZYJQNUpToken.m */; };
A9D1B64124FE765F000F4662 /* ZYJQNIP.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B5FC24FE765F000F4662 /* ZYJQNIP.m */; };
A9D1B64224FE765F000F4662 /* ZYJQNSystemTool.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1B60224FE765F000F4662 /* ZYJQNSystemTool.m */; };
B94FCB1053F8932068A11CC9 /* libPods-OffcnIMSDKiOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 49CE5E230A14D9B821170F61 /* libPods-OffcnIMSDKiOS.a */; };
/* End PBXBuildFile section */
......@@ -650,6 +711,137 @@
A9D1B33824FE2DA7000F4662 /* oimcore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = oimcore.framework; sourceTree = "<group>"; };
A9D1B33C24FE3BE6000F4662 /* OffcnIMSqliteTestVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OffcnIMSqliteTestVC.h; sourceTree = "<group>"; };
A9D1B33D24FE3BE6000F4662 /* OffcnIMSqliteTestVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OffcnIMSqliteTestVC.m; sourceTree = "<group>"; };
A9D1B58324FE765E000F4662 /* ZYJQNFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNFile.m; sourceTree = "<group>"; };
A9D1B58424FE765E000F4662 /* ZYJQNDnsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNDnsManager.m; sourceTree = "<group>"; };
A9D1B58524FE765E000F4662 /* ZYJQNUrlSafeBase64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNUrlSafeBase64.h; sourceTree = "<group>"; };
A9D1B58624FE765E000F4662 /* ZYJQNResolvUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNResolvUtil.h; sourceTree = "<group>"; };
A9D1B58724FE765E000F4662 /* ZYJQNURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNURLProtocol.m; sourceTree = "<group>"; };
A9D1B58824FE765E000F4662 /* ZYJQNResolverDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNResolverDelegate.h; sourceTree = "<group>"; };
A9D1B58924FE765E000F4662 /* ZYJQNRecorderDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNRecorderDelegate.h; sourceTree = "<group>"; };
A9D1B58A24FE765E000F4662 /* ZYJQNConcurrentResumeUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNConcurrentResumeUpload.h; sourceTree = "<group>"; };
A9D1B58B24FE765E000F4662 /* ZYJQNGetAddrInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNGetAddrInfo.m; sourceTree = "<group>"; };
A9D1B58C24FE765E000F4662 /* ZYJQNDnsPrefetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNDnsPrefetcher.m; sourceTree = "<group>"; };
A9D1B58D24FE765E000F4662 /* ZYJQNEtag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNEtag.m; sourceTree = "<group>"; };
A9D1B58E24FE765E000F4662 /* ZYJQNHijackingDetectWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNHijackingDetectWrapper.m; sourceTree = "<group>"; };
A9D1B58F24FE765E000F4662 /* ZYJQNIpModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNIpModel.h; sourceTree = "<group>"; };
A9D1B59024FE765E000F4662 /* ZYJHappyDNS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJHappyDNS.h; sourceTree = "<group>"; };
A9D1B59124FE765E000F4662 /* ZYJQNPHAssetFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNPHAssetFile.h; sourceTree = "<group>"; };
A9D1B59224FE765E000F4662 /* ZYJQNZoneInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNZoneInfo.m; sourceTree = "<group>"; };
A9D1B59324FE765E000F4662 /* ZYJQNSessionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNSessionManager.h; sourceTree = "<group>"; };
A9D1B59424FE765E000F4662 /* ZYJQNCrc32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNCrc32.m; sourceTree = "<group>"; };
A9D1B59524FE765E000F4662 /* NSURLRequest+ZYJQNRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLRequest+ZYJQNRequest.m"; sourceTree = "<group>"; };
A9D1B59624FE765E000F4662 /* ZYJQNMD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNMD5.h; sourceTree = "<group>"; };
A9D1B59724FE765E000F4662 /* ZYJQNResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNResolver.h; sourceTree = "<group>"; };
A9D1B59824FE765E000F4662 /* ZYJQNPHAssetResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNPHAssetResource.h; sourceTree = "<group>"; };
A9D1B59924FE765E000F4662 /* ZYJQNFileDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNFileDelegate.h; sourceTree = "<group>"; };
A9D1B59A24FE765E000F4662 /* ZYJQNUploadInfoCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNUploadInfoCollector.h; sourceTree = "<group>"; };
A9D1B59B24FE765E000F4662 /* ZYJQNResumeUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNResumeUpload.h; sourceTree = "<group>"; };
A9D1B59C24FE765E000F4662 /* ZYJQNResponseInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNResponseInfo.h; sourceTree = "<group>"; };
A9D1B59D24FE765E000F4662 /* ZYJQNFormUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNFormUpload.h; sourceTree = "<group>"; };
A9D1B59E24FE765E000F4662 /* ZYJQNCFHttpClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNCFHttpClient.h; sourceTree = "<group>"; };
A9D1B59F24FE765E000F4662 /* ZYJQN_GTM_Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQN_GTM_Base64.h; sourceTree = "<group>"; };
A9D1B5A024FE765E000F4662 /* ZYJQNFileRecorder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNFileRecorder.m; sourceTree = "<group>"; };
A9D1B5A124FE765E000F4662 /* NSObject+ZYJQNSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+ZYJQNSwizzle.m"; sourceTree = "<group>"; };
A9D1B5A224FE765E000F4662 /* ZYJQNLruCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNLruCache.m; sourceTree = "<group>"; };
A9D1B5A324FE765E000F4662 /* ZYJQNUpToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNUpToken.h; sourceTree = "<group>"; };
A9D1B5A424FE765E000F4662 /* ZYJQNRefresher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNRefresher.h; sourceTree = "<group>"; };
A9D1B5A524FE765E000F4662 /* ZYJQNDnsCacheInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNDnsCacheInfo.m; sourceTree = "<group>"; };
A9D1B5A624FE765E000F4662 /* ZYJQNConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNConfiguration.h; sourceTree = "<group>"; };
A9D1B5A724FE765E000F4662 /* ZYJQNVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNVersion.h; sourceTree = "<group>"; };
A9D1B5A824FE765E000F4662 /* ZYJQNUploadOption.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNUploadOption.h; sourceTree = "<group>"; };
A9D1B5A924FE765E000F4662 /* ZYJQNZone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNZone.m; sourceTree = "<group>"; };
A9D1B5AA24FE765E000F4662 /* ZYJQNAsyncRun.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNAsyncRun.h; sourceTree = "<group>"; };
A9D1B5AB24FE765E000F4662 /* ZYJQNPipeline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNPipeline.h; sourceTree = "<group>"; };
A9D1B5AC24FE765E000F4662 /* ZYJQNDes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNDes.m; sourceTree = "<group>"; };
A9D1B5AD24FE765E000F4662 /* ZYJQNUploadManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNUploadManager.h; sourceTree = "<group>"; };
A9D1B5AE24FE765E000F4662 /* ZYJQNDnspodFree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNDnspodFree.m; sourceTree = "<group>"; };
A9D1B5AF24FE765E000F4662 /* ZYJQNAutoZone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNAutoZone.m; sourceTree = "<group>"; };
A9D1B5B024FE765E000F4662 /* ZYJQNRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNRecord.m; sourceTree = "<group>"; };
A9D1B5B124FE765E000F4662 /* ZYJQNDnsCacheFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNDnsCacheFile.h; sourceTree = "<group>"; };
A9D1B5B224FE765E000F4662 /* ZYJQNNetworkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNNetworkInfo.h; sourceTree = "<group>"; };
A9D1B5B324FE765E000F4662 /* ZYJQNUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNUtils.h; sourceTree = "<group>"; };
A9D1B5B424FE765E000F4662 /* ZYJQNTransactionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNTransactionManager.m; sourceTree = "<group>"; };
A9D1B5B524FE765E000F4662 /* ZYJQNSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNSystem.h; sourceTree = "<group>"; };
A9D1B5B624FE765E000F4662 /* ZYJQNHosts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNHosts.h; sourceTree = "<group>"; };
A9D1B5B724FE765E000F4662 /* ZYJQNALAssetFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNALAssetFile.h; sourceTree = "<group>"; };
A9D1B5B824FE765E000F4662 /* ZYJQNBaseUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNBaseUpload.h; sourceTree = "<group>"; };
A9D1B5B924FE765E000F4662 /* ZYJQNUploadInfoReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNUploadInfoReporter.m; sourceTree = "<group>"; };
A9D1B5BA24FE765E000F4662 /* ZYJQNSystemTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNSystemTool.h; sourceTree = "<group>"; };
A9D1B5BB24FE765E000F4662 /* ZYJQNInetAddress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNInetAddress.m; sourceTree = "<group>"; };
A9D1B5BC24FE765E000F4662 /* ZYJQNDnspodEnterprise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNDnspodEnterprise.m; sourceTree = "<group>"; };
A9D1B5BD24FE765E000F4662 /* ZYJQiniuSDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQiniuSDK.h; sourceTree = "<group>"; };
A9D1B5BE24FE765E000F4662 /* ZYJQNUserAgent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNUserAgent.m; sourceTree = "<group>"; };
A9D1B5BF24FE765E000F4662 /* ZYJQNHttpResponseInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNHttpResponseInfo.m; sourceTree = "<group>"; };
A9D1B5C024FE765E000F4662 /* ZYJQNDomain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNDomain.m; sourceTree = "<group>"; };
A9D1B5C124FE765E000F4662 /* ZYJQNAssessment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNAssessment.m; sourceTree = "<group>"; };
A9D1B5C224FE765E000F4662 /* ZYJQNHex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNHex.m; sourceTree = "<group>"; };
A9D1B5C324FE765E000F4662 /* ZYJQNIP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNIP.h; sourceTree = "<group>"; };
A9D1B5C424FE765E000F4662 /* ZYJQNUploadOption+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ZYJQNUploadOption+Private.h"; sourceTree = "<group>"; };
A9D1B5C524FE765E000F4662 /* ZYJQNFixedZone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNFixedZone.m; sourceTree = "<group>"; };
A9D1B5C624FE765E000F4662 /* ZYJQNTxtResolver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNTxtResolver.m; sourceTree = "<group>"; };
A9D1B5C724FE765E000F4662 /* ZYJQNHijackingDetectWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNHijackingDetectWrapper.h; sourceTree = "<group>"; };
A9D1B5C824FE765E000F4662 /* ZYJQNEtag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNEtag.h; sourceTree = "<group>"; };
A9D1B5C924FE765E000F4662 /* ZYJQNDnsPrefetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNDnsPrefetcher.h; sourceTree = "<group>"; };
A9D1B5CA24FE765E000F4662 /* ZYJQNGetAddrInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNGetAddrInfo.h; sourceTree = "<group>"; };
A9D1B5CB24FE765E000F4662 /* ZYJQNConcurrentResumeUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNConcurrentResumeUpload.m; sourceTree = "<group>"; };
A9D1B5CC24FE765E000F4662 /* ZYJQNURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNURLProtocol.h; sourceTree = "<group>"; };
A9D1B5CD24FE765E000F4662 /* ZYJQNUrlSafeBase64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNUrlSafeBase64.m; sourceTree = "<group>"; };
A9D1B5CE24FE765E000F4662 /* ZYJQNResolvUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNResolvUtil.m; sourceTree = "<group>"; };
A9D1B5CF24FE765E000F4662 /* ZYJQNDnsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNDnsManager.h; sourceTree = "<group>"; };
A9D1B5D024FE765E000F4662 /* ZYJQNFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNFile.h; sourceTree = "<group>"; };
A9D1B5D124FE765E000F4662 /* ZYJQNDns.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNDns.h; sourceTree = "<group>"; };
A9D1B5D224FE765E000F4662 /* ZYJQNLruCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNLruCache.h; sourceTree = "<group>"; };
A9D1B5D324FE765E000F4662 /* ZYJQNConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNConfig.h; sourceTree = "<group>"; };
A9D1B5D424FE765E000F4662 /* ZYJQNFileRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNFileRecorder.h; sourceTree = "<group>"; };
A9D1B5D524FE765E000F4662 /* NSObject+ZYJQNSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+ZYJQNSwizzle.h"; sourceTree = "<group>"; };
A9D1B5D624FE765E000F4662 /* ZYJQN_GTM_Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQN_GTM_Base64.m; sourceTree = "<group>"; };
A9D1B5D724FE765E000F4662 /* ZYJQNCFHttpClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNCFHttpClient.m; sourceTree = "<group>"; };
A9D1B5D824FE765E000F4662 /* ZYJQNResponseInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNResponseInfo.m; sourceTree = "<group>"; };
A9D1B5D924FE765E000F4662 /* ZYJQNResumeUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNResumeUpload.m; sourceTree = "<group>"; };
A9D1B5DA24FE765E000F4662 /* ZYJQNFormUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNFormUpload.m; sourceTree = "<group>"; };
A9D1B5DB24FE765E000F4662 /* ZYJQNUploadInfoCollector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNUploadInfoCollector.m; sourceTree = "<group>"; };
A9D1B5DC24FE765E000F4662 /* ZYJQNPHAssetResource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNPHAssetResource.m; sourceTree = "<group>"; };
A9D1B5DD24FE765E000F4662 /* NSURLRequest+ZYJQNRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLRequest+ZYJQNRequest.h"; sourceTree = "<group>"; };
A9D1B5DE24FE765E000F4662 /* ZYJQNCrc32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNCrc32.h; sourceTree = "<group>"; };
A9D1B5DF24FE765E000F4662 /* ZYJQNMD5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNMD5.m; sourceTree = "<group>"; };
A9D1B5E024FE765E000F4662 /* ZYJQNResolver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNResolver.m; sourceTree = "<group>"; };
A9D1B5E124FE765E000F4662 /* ZYJQNSessionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNSessionManager.m; sourceTree = "<group>"; };
A9D1B5E224FE765E000F4662 /* ZYJQNZoneInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNZoneInfo.h; sourceTree = "<group>"; };
A9D1B5E324FE765E000F4662 /* ZYJQNPHAssetFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNPHAssetFile.m; sourceTree = "<group>"; };
A9D1B5E424FE765E000F4662 /* ZYJQNIpModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNIpModel.m; sourceTree = "<group>"; };
A9D1B5E524FE765E000F4662 /* ZYJQNHosts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNHosts.m; sourceTree = "<group>"; };
A9D1B5E624FE765E000F4662 /* ZYJQNALAssetFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNALAssetFile.m; sourceTree = "<group>"; };
A9D1B5E724FE765E000F4662 /* ZYJQNBaseUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNBaseUpload.m; sourceTree = "<group>"; };
A9D1B5E824FE765E000F4662 /* ZYJQNTransactionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNTransactionManager.h; sourceTree = "<group>"; };
A9D1B5E924FE765E000F4662 /* ZYJQNSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNSystem.m; sourceTree = "<group>"; };
A9D1B5EA24FE765E000F4662 /* ZYJQNUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNUtils.m; sourceTree = "<group>"; };
A9D1B5EB24FE765E000F4662 /* ZYJQNNetworkInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNNetworkInfo.m; sourceTree = "<group>"; };
A9D1B5EC24FE765E000F4662 /* ZYJQNDnsCacheFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNDnsCacheFile.m; sourceTree = "<group>"; };
A9D1B5ED24FE765E000F4662 /* ZYJQNAutoZone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNAutoZone.h; sourceTree = "<group>"; };
A9D1B5EE24FE765E000F4662 /* ZYJQNRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNRecord.h; sourceTree = "<group>"; };
A9D1B5EF24FE765E000F4662 /* ZYJQNDnspodFree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNDnspodFree.h; sourceTree = "<group>"; };
A9D1B5F024FE765E000F4662 /* ZYJQNUploadManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNUploadManager.m; sourceTree = "<group>"; };
A9D1B5F124FE765E000F4662 /* ZYJQNDes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNDes.h; sourceTree = "<group>"; };
A9D1B5F224FE765E000F4662 /* ZYJQNZone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNZone.h; sourceTree = "<group>"; };
A9D1B5F324FE765E000F4662 /* ZYJQNPipeline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNPipeline.m; sourceTree = "<group>"; };
A9D1B5F424FE765E000F4662 /* ZYJQNAsyncRun.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNAsyncRun.m; sourceTree = "<group>"; };
A9D1B5F524FE765E000F4662 /* ZYJQNConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNConfiguration.m; sourceTree = "<group>"; };
A9D1B5F624FE765F000F4662 /* ZYJQNUploadOption.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNUploadOption.m; sourceTree = "<group>"; };
A9D1B5F724FE765F000F4662 /* ZYJQNDnsCacheInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNDnsCacheInfo.h; sourceTree = "<group>"; };
A9D1B5F824FE765F000F4662 /* ZYJQNRefresher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNRefresher.m; sourceTree = "<group>"; };
A9D1B5F924FE765F000F4662 /* ZYJQNUpToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNUpToken.m; sourceTree = "<group>"; };
A9D1B5FA24FE765F000F4662 /* ZYJQNTxtResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNTxtResolver.h; sourceTree = "<group>"; };
A9D1B5FB24FE765F000F4662 /* ZYJQNFixedZone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNFixedZone.h; sourceTree = "<group>"; };
A9D1B5FC24FE765F000F4662 /* ZYJQNIP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNIP.m; sourceTree = "<group>"; };
A9D1B5FD24FE765F000F4662 /* ZYJQNHex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNHex.h; sourceTree = "<group>"; };
A9D1B5FE24FE765F000F4662 /* ZYJQNAssessment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNAssessment.h; sourceTree = "<group>"; };
A9D1B5FF24FE765F000F4662 /* ZYJQNDomain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNDomain.h; sourceTree = "<group>"; };
A9D1B60024FE765F000F4662 /* ZYJQNUserAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNUserAgent.h; sourceTree = "<group>"; };
A9D1B60124FE765F000F4662 /* ZYJQNHttpResponseInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNHttpResponseInfo.h; sourceTree = "<group>"; };
A9D1B60224FE765F000F4662 /* ZYJQNSystemTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYJQNSystemTool.m; sourceTree = "<group>"; };
A9D1B60324FE765F000F4662 /* ZYJQNDnspodEnterprise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNDnspodEnterprise.h; sourceTree = "<group>"; };
A9D1B60424FE765F000F4662 /* ZYJQNInetAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNInetAddress.h; sourceTree = "<group>"; };
A9D1B60524FE765F000F4662 /* ZYJQNUploadInfoReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYJQNUploadInfoReporter.h; sourceTree = "<group>"; };
D7DCDED1DEE7F99F223D5C73 /* Pods-OffcnIMSDKiOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OffcnIMSDKiOS.release.xcconfig"; path = "Target Support Files/Pods-OffcnIMSDKiOS/Pods-OffcnIMSDKiOS.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
......@@ -726,7 +918,7 @@
A9661F8124EA7AD10024EB54 /* Tools-(工具) */ = {
isa = PBXGroup;
children = (
A9D1B33324FD1308000F4662 /* ZYJQiniu */,
A9D1B33324FD1308000F4662 /* ZYJQiniuManager */,
A9661FE824EA80A50024EB54 /* OffcnZYJFMDBHandler */,
A9661FF624EA80A50024EB54 /* ZYJLibs */,
A9661F8224EA7AD10024EB54 /* LoadingView */,
......@@ -937,6 +1129,7 @@
A9661FF624EA80A50024EB54 /* ZYJLibs */ = {
isa = PBXGroup;
children = (
A9D1B58224FE765E000F4662 /* ZYJQiniu */,
A9661FF724EA80A50024EB54 /* ZYJMJExtension */,
A966200D24EA80A50024EB54 /* ZYJMasonry */,
A966202724EA80A50024EB54 /* ZYJRealReachability */,
......@@ -1462,12 +1655,150 @@
path = "ExposedInterface-(外放接口)";
sourceTree = "<group>";
};
A9D1B33324FD1308000F4662 /* ZYJQiniu */ = {
A9D1B33324FD1308000F4662 /* ZYJQiniuManager */ = {
isa = PBXGroup;
children = (
A9D1B31624EFAD8C000F4662 /* OffcnUploadManager.h */,
A9D1B31724EFAD8C000F4662 /* OffcnUploadManager.m */,
);
path = ZYJQiniuManager;
sourceTree = "<group>";
};
A9D1B58224FE765E000F4662 /* ZYJQiniu */ = {
isa = PBXGroup;
children = (
A9D1B58324FE765E000F4662 /* ZYJQNFile.m */,
A9D1B58424FE765E000F4662 /* ZYJQNDnsManager.m */,
A9D1B58524FE765E000F4662 /* ZYJQNUrlSafeBase64.h */,
A9D1B58624FE765E000F4662 /* ZYJQNResolvUtil.h */,
A9D1B58724FE765E000F4662 /* ZYJQNURLProtocol.m */,
A9D1B58824FE765E000F4662 /* ZYJQNResolverDelegate.h */,
A9D1B58924FE765E000F4662 /* ZYJQNRecorderDelegate.h */,
A9D1B58A24FE765E000F4662 /* ZYJQNConcurrentResumeUpload.h */,
A9D1B58B24FE765E000F4662 /* ZYJQNGetAddrInfo.m */,
A9D1B58C24FE765E000F4662 /* ZYJQNDnsPrefetcher.m */,
A9D1B58D24FE765E000F4662 /* ZYJQNEtag.m */,
A9D1B58E24FE765E000F4662 /* ZYJQNHijackingDetectWrapper.m */,
A9D1B58F24FE765E000F4662 /* ZYJQNIpModel.h */,
A9D1B59024FE765E000F4662 /* ZYJHappyDNS.h */,
A9D1B59124FE765E000F4662 /* ZYJQNPHAssetFile.h */,
A9D1B59224FE765E000F4662 /* ZYJQNZoneInfo.m */,
A9D1B59324FE765E000F4662 /* ZYJQNSessionManager.h */,
A9D1B59424FE765E000F4662 /* ZYJQNCrc32.m */,
A9D1B59524FE765E000F4662 /* NSURLRequest+ZYJQNRequest.m */,
A9D1B59624FE765E000F4662 /* ZYJQNMD5.h */,
A9D1B59724FE765E000F4662 /* ZYJQNResolver.h */,
A9D1B59824FE765E000F4662 /* ZYJQNPHAssetResource.h */,
A9D1B59924FE765E000F4662 /* ZYJQNFileDelegate.h */,
A9D1B59A24FE765E000F4662 /* ZYJQNUploadInfoCollector.h */,
A9D1B59B24FE765E000F4662 /* ZYJQNResumeUpload.h */,
A9D1B59C24FE765E000F4662 /* ZYJQNResponseInfo.h */,
A9D1B59D24FE765E000F4662 /* ZYJQNFormUpload.h */,
A9D1B59E24FE765E000F4662 /* ZYJQNCFHttpClient.h */,
A9D1B59F24FE765E000F4662 /* ZYJQN_GTM_Base64.h */,
A9D1B5A024FE765E000F4662 /* ZYJQNFileRecorder.m */,
A9D1B5A124FE765E000F4662 /* NSObject+ZYJQNSwizzle.m */,
A9D1B5A224FE765E000F4662 /* ZYJQNLruCache.m */,
A9D1B5A324FE765E000F4662 /* ZYJQNUpToken.h */,
A9D1B5A424FE765E000F4662 /* ZYJQNRefresher.h */,
A9D1B5A524FE765E000F4662 /* ZYJQNDnsCacheInfo.m */,
A9D1B5A624FE765E000F4662 /* ZYJQNConfiguration.h */,
A9D1B5A724FE765E000F4662 /* ZYJQNVersion.h */,
A9D1B5A824FE765E000F4662 /* ZYJQNUploadOption.h */,
A9D1B5A924FE765E000F4662 /* ZYJQNZone.m */,
A9D1B5AA24FE765E000F4662 /* ZYJQNAsyncRun.h */,
A9D1B5AB24FE765E000F4662 /* ZYJQNPipeline.h */,
A9D1B5AC24FE765E000F4662 /* ZYJQNDes.m */,
A9D1B5AD24FE765E000F4662 /* ZYJQNUploadManager.h */,
A9D1B5AE24FE765E000F4662 /* ZYJQNDnspodFree.m */,
A9D1B5AF24FE765E000F4662 /* ZYJQNAutoZone.m */,
A9D1B5B024FE765E000F4662 /* ZYJQNRecord.m */,
A9D1B5B124FE765E000F4662 /* ZYJQNDnsCacheFile.h */,
A9D1B5B224FE765E000F4662 /* ZYJQNNetworkInfo.h */,
A9D1B5B324FE765E000F4662 /* ZYJQNUtils.h */,
A9D1B5B424FE765E000F4662 /* ZYJQNTransactionManager.m */,
A9D1B5B524FE765E000F4662 /* ZYJQNSystem.h */,
A9D1B5B624FE765E000F4662 /* ZYJQNHosts.h */,
A9D1B5B724FE765E000F4662 /* ZYJQNALAssetFile.h */,
A9D1B5B824FE765E000F4662 /* ZYJQNBaseUpload.h */,
A9D1B5B924FE765E000F4662 /* ZYJQNUploadInfoReporter.m */,
A9D1B5BA24FE765E000F4662 /* ZYJQNSystemTool.h */,
A9D1B5BB24FE765E000F4662 /* ZYJQNInetAddress.m */,
A9D1B5BC24FE765E000F4662 /* ZYJQNDnspodEnterprise.m */,
A9D1B5BD24FE765E000F4662 /* ZYJQiniuSDK.h */,
A9D1B5BE24FE765E000F4662 /* ZYJQNUserAgent.m */,
A9D1B5BF24FE765E000F4662 /* ZYJQNHttpResponseInfo.m */,
A9D1B5C024FE765E000F4662 /* ZYJQNDomain.m */,
A9D1B5C124FE765E000F4662 /* ZYJQNAssessment.m */,
A9D1B5C224FE765E000F4662 /* ZYJQNHex.m */,
A9D1B5C324FE765E000F4662 /* ZYJQNIP.h */,
A9D1B5C424FE765E000F4662 /* ZYJQNUploadOption+Private.h */,
A9D1B5C524FE765E000F4662 /* ZYJQNFixedZone.m */,
A9D1B5C624FE765E000F4662 /* ZYJQNTxtResolver.m */,
A9D1B5C724FE765E000F4662 /* ZYJQNHijackingDetectWrapper.h */,
A9D1B5C824FE765E000F4662 /* ZYJQNEtag.h */,
A9D1B5C924FE765E000F4662 /* ZYJQNDnsPrefetcher.h */,
A9D1B5CA24FE765E000F4662 /* ZYJQNGetAddrInfo.h */,
A9D1B5CB24FE765E000F4662 /* ZYJQNConcurrentResumeUpload.m */,
A9D1B5CC24FE765E000F4662 /* ZYJQNURLProtocol.h */,
A9D1B5CD24FE765E000F4662 /* ZYJQNUrlSafeBase64.m */,
A9D1B5CE24FE765E000F4662 /* ZYJQNResolvUtil.m */,
A9D1B5CF24FE765E000F4662 /* ZYJQNDnsManager.h */,
A9D1B5D024FE765E000F4662 /* ZYJQNFile.h */,
A9D1B5D124FE765E000F4662 /* ZYJQNDns.h */,
A9D1B5D224FE765E000F4662 /* ZYJQNLruCache.h */,
A9D1B5D324FE765E000F4662 /* ZYJQNConfig.h */,
A9D1B5D424FE765E000F4662 /* ZYJQNFileRecorder.h */,
A9D1B5D524FE765E000F4662 /* NSObject+ZYJQNSwizzle.h */,
A9D1B5D624FE765E000F4662 /* ZYJQN_GTM_Base64.m */,
A9D1B5D724FE765E000F4662 /* ZYJQNCFHttpClient.m */,
A9D1B5D824FE765E000F4662 /* ZYJQNResponseInfo.m */,
A9D1B5D924FE765E000F4662 /* ZYJQNResumeUpload.m */,
A9D1B5DA24FE765E000F4662 /* ZYJQNFormUpload.m */,
A9D1B5DB24FE765E000F4662 /* ZYJQNUploadInfoCollector.m */,
A9D1B5DC24FE765E000F4662 /* ZYJQNPHAssetResource.m */,
A9D1B5DD24FE765E000F4662 /* NSURLRequest+ZYJQNRequest.h */,
A9D1B5DE24FE765E000F4662 /* ZYJQNCrc32.h */,
A9D1B5DF24FE765E000F4662 /* ZYJQNMD5.m */,
A9D1B5E024FE765E000F4662 /* ZYJQNResolver.m */,
A9D1B5E124FE765E000F4662 /* ZYJQNSessionManager.m */,
A9D1B5E224FE765E000F4662 /* ZYJQNZoneInfo.h */,
A9D1B5E324FE765E000F4662 /* ZYJQNPHAssetFile.m */,
A9D1B5E424FE765E000F4662 /* ZYJQNIpModel.m */,
A9D1B5E524FE765E000F4662 /* ZYJQNHosts.m */,
A9D1B5E624FE765E000F4662 /* ZYJQNALAssetFile.m */,
A9D1B5E724FE765E000F4662 /* ZYJQNBaseUpload.m */,
A9D1B5E824FE765E000F4662 /* ZYJQNTransactionManager.h */,
A9D1B5E924FE765E000F4662 /* ZYJQNSystem.m */,
A9D1B5EA24FE765E000F4662 /* ZYJQNUtils.m */,
A9D1B5EB24FE765E000F4662 /* ZYJQNNetworkInfo.m */,
A9D1B5EC24FE765E000F4662 /* ZYJQNDnsCacheFile.m */,
A9D1B5ED24FE765E000F4662 /* ZYJQNAutoZone.h */,
A9D1B5EE24FE765E000F4662 /* ZYJQNRecord.h */,
A9D1B5EF24FE765E000F4662 /* ZYJQNDnspodFree.h */,
A9D1B5F024FE765E000F4662 /* ZYJQNUploadManager.m */,
A9D1B5F124FE765E000F4662 /* ZYJQNDes.h */,
A9D1B5F224FE765E000F4662 /* ZYJQNZone.h */,
A9D1B5F324FE765E000F4662 /* ZYJQNPipeline.m */,
A9D1B5F424FE765E000F4662 /* ZYJQNAsyncRun.m */,
A9D1B5F524FE765E000F4662 /* ZYJQNConfiguration.m */,
A9D1B5F624FE765F000F4662 /* ZYJQNUploadOption.m */,
A9D1B5F724FE765F000F4662 /* ZYJQNDnsCacheInfo.h */,
A9D1B5F824FE765F000F4662 /* ZYJQNRefresher.m */,
A9D1B5F924FE765F000F4662 /* ZYJQNUpToken.m */,
A9D1B5FA24FE765F000F4662 /* ZYJQNTxtResolver.h */,
A9D1B5FB24FE765F000F4662 /* ZYJQNFixedZone.h */,
A9D1B5FC24FE765F000F4662 /* ZYJQNIP.m */,
A9D1B5FD24FE765F000F4662 /* ZYJQNHex.h */,
A9D1B5FE24FE765F000F4662 /* ZYJQNAssessment.h */,
A9D1B5FF24FE765F000F4662 /* ZYJQNDomain.h */,
A9D1B60024FE765F000F4662 /* ZYJQNUserAgent.h */,
A9D1B60124FE765F000F4662 /* ZYJQNHttpResponseInfo.h */,
A9D1B60224FE765F000F4662 /* ZYJQNSystemTool.m */,
A9D1B60324FE765F000F4662 /* ZYJQNDnspodEnterprise.h */,
A9D1B60424FE765F000F4662 /* ZYJQNInetAddress.h */,
A9D1B60524FE765F000F4662 /* ZYJQNUploadInfoReporter.h */,
);
path = ZYJQiniu;
sourceTree = "<group>";
};
......@@ -1585,6 +1916,7 @@
A96621B124EA80A60024EB54 /* ZYJOSSGetSymlinkRequest.m in Sources */,
A966218A24EA80A60024EB54 /* UIScrollView+ZYJMJRefresh.m in Sources */,
A966216624EA80A60024EB54 /* ZYJMASLayoutConstraint.m in Sources */,
A9D1B63D24FE765F000F4662 /* ZYJQNConfiguration.m in Sources */,
A9661FCF24EA7AD10024EB54 /* DSToast.m in Sources */,
A96621C724EA80A60024EB54 /* ZYJaos_crc64.c in Sources */,
A96621C624EA80A60024EB54 /* ZYJOSSUtil.m in Sources */,
......@@ -1596,18 +1928,27 @@
A966219E24EA80A60024EB54 /* ZYJOSSConstants.m in Sources */,
A96621B524EA80A60024EB54 /* NSMutableData+ZYJOSS_CRC.m in Sources */,
A96621C924EA80A60024EB54 /* ZYJMBProgressHUD.m in Sources */,
A9D1B61224FE765F000F4662 /* ZYJQNLruCache.m in Sources */,
A9D1B63624FE765F000F4662 /* ZYJQNSystem.m in Sources */,
A9D1B60D24FE765F000F4662 /* ZYJQNZoneInfo.m in Sources */,
A9661FD524EA7AD10024EB54 /* NSDictionary+NullReplacement.m in Sources */,
A96621BC24EA80A60024EB54 /* ZYJOSSExecutor.m in Sources */,
A9D1B62E24FE765F000F4662 /* ZYJQNMD5.m in Sources */,
A9D1B64124FE765F000F4662 /* ZYJQNIP.m in Sources */,
A96621E124EA80A60024EB54 /* UIProgressView+ZYJAFNetworking.m in Sources */,
A966217D24EA80A60024EB54 /* ZYJSDWebImageDecoder.m in Sources */,
A9661FDB24EA7AD10024EB54 /* NSFileManager+Paths.m in Sources */,
A9661FCD24EA7AD10024EB54 /* CJLoadingView.m in Sources */,
A9D1B61124FE765F000F4662 /* NSObject+ZYJQNSwizzle.m in Sources */,
A96621A824EA80A60024EB54 /* ZYJOSSPutSymlinkResult.m in Sources */,
A96621DC24EA80A60024EB54 /* ZYJMQTTSSLSecurityPolicyDecoder.m in Sources */,
A9661FE124EA7AD10024EB54 /* NSString+Extension.m in Sources */,
A966218424EA80A60024EB54 /* ZYJSDImageCache.m in Sources */,
A966216F24EA80A60024EB54 /* ZYJReachStateLoading.m in Sources */,
A9D1B62824FE765F000F4662 /* ZYJQNCFHttpClient.m in Sources */,
A9661FE424EA7AD10024EB54 /* CLSlider.m in Sources */,
A9D1B62A24FE765F000F4662 /* ZYJQNResumeUpload.m in Sources */,
A9D1B61524FE765F000F4662 /* ZYJQNDes.m in Sources */,
A966217224EA80A60024EB54 /* ZYJReachStateWWAN.m in Sources */,
A966217024EA80A60024EB54 /* ZYJReachStateUnReachable.m in Sources */,
A966215524EA80A60024EB54 /* OffcnIMZYJFMDBHandler.m in Sources */,
......@@ -1624,42 +1965,55 @@
A966218824EA80A60024EB54 /* ZYJMJRefreshConst.m in Sources */,
A9661FDE24EA7AD10024EB54 /* UIViewExt.m in Sources */,
A966218024EA80A60024EB54 /* ZYJSDWebImageManager.m in Sources */,
A9D1B60E24FE765F000F4662 /* ZYJQNCrc32.m in Sources */,
A96621A124EA80A60024EB54 /* ZYJOSSGetObjectACLResult.m in Sources */,
A9D1B62424FE765F000F4662 /* ZYJQNConcurrentResumeUpload.m in Sources */,
A966218524EA80A60024EB54 /* ZYJSDWebImageDownloader.m in Sources */,
A96621AD24EA80A60024EB54 /* ZYJOSSFileLogger.m in Sources */,
A966217624EA80A60024EB54 /* UIImageView+ZYJWebCache.m in Sources */,
A9D1B61624FE765F000F4662 /* ZYJQNDnspodFree.m in Sources */,
A96621B024EA80A60024EB54 /* ZYJOSSNetworking.m in Sources */,
A96621ED24EA80A60024EB54 /* ZYJAFSecurityPolicy.m in Sources */,
A9D1B60924FE765F000F4662 /* ZYJQNGetAddrInfo.m in Sources */,
A96621BE24EA80A60024EB54 /* ZYJOSSGetBucketInfoResult.m in Sources */,
A9D1B63C24FE765F000F4662 /* ZYJQNAsyncRun.m in Sources */,
A9661FD724EA7AD10024EB54 /* UIBarButtonItem+WNXBarButtonItem.m in Sources */,
A966216A24EA80A60024EB54 /* ZYJPingFoundation.m in Sources */,
A9D1B31824EFAD8C000F4662 /* OffcnUploadManager.m in Sources */,
A96621D424EA80A60024EB54 /* ZYJForegroundReconnection.m in Sources */,
A966218924EA80A60024EB54 /* UIScrollView+ZYJMJExtension.m in Sources */,
A9D1B60C24FE765F000F4662 /* ZYJQNHijackingDetectWrapper.m in Sources */,
A966218D24EA80A60024EB54 /* ZYJMJRefreshBackStateFooter.m in Sources */,
A966219724EA80A60024EB54 /* ZYJMJRefreshBackFooter.m in Sources */,
A966217424EA80A60024EB54 /* ZYJFSMEngine.m in Sources */,
A966217924EA80A60024EB54 /* UIImage+ZYJGIF.m in Sources */,
A9661FCE24EA7AD10024EB54 /* SDTool.m in Sources */,
A9D1B61B24FE765F000F4662 /* ZYJQNInetAddress.m in Sources */,
A966218B24EA80A60024EB54 /* UIView+ZYJMJExtension.m in Sources */,
A9D1B32224F50973000F4662 /* OffcnIMModel.m in Sources */,
A9661B6124EA72900024EB54 /* ViewController.mm in Sources */,
A9D1B63424FE765F000F4662 /* ZYJQNALAssetFile.m in Sources */,
A9661FDC24EA7AD10024EB54 /* UIView+bezierShape.m in Sources */,
A966215224EA80A60024EB54 /* ZYJZYJFMDatabase.m in Sources */,
A966217E24EA80A60024EB54 /* UIImage+ZYJMultiFormat.m in Sources */,
A9D1B63724FE765F000F4662 /* ZYJQNUtils.m in Sources */,
A9D1B62124FE765F000F4662 /* ZYJQNHex.m in Sources */,
A966215B24EA80A60024EB54 /* ZYJMJFoundation.m in Sources */,
A9661FE624EA7AD10024EB54 /* SDGeneralTool.m in Sources */,
A966219924EA80A60024EB54 /* ZYJMJRefreshHeader.m in Sources */,
A9661FD924EA7AD10024EB54 /* SDButton.m in Sources */,
A9D1B61724FE765F000F4662 /* ZYJQNAutoZone.m in Sources */,
A966219024EA80A60024EB54 /* ZYJMJRefreshAutoNormalFooter.m in Sources */,
A96621CA24EA80A60024EB54 /* ZYJMQTTCFSocketEncoder.m in Sources */,
A9D1B32E24F7BE7B000F4662 /* OffcnZYJTestDataStorageView.m in Sources */,
A9D1B63E24FE765F000F4662 /* ZYJQNUploadOption.m in Sources */,
A966218224EA80A60024EB54 /* ZYJSDWebImagePrefetcher.m in Sources */,
A966216B24EA80A60024EB54 /* ZYJPingHelper.m in Sources */,
A966217324EA80A60024EB54 /* ZYJReachStateWIFI.m in Sources */,
A9661B6024EA72900024EB54 /* AppDelegate.m in Sources */,
A96621EC24EA80A60024EB54 /* ZYJAFHTTPSessionManager.m in Sources */,
A966218124EA80A60024EB54 /* NSImage+ZYJWebCache.m in Sources */,
A9D1B62324FE765F000F4662 /* ZYJQNTxtResolver.m in Sources */,
A96621D524EA80A60024EB54 /* ZYJMQTTDecoder.m in Sources */,
A96621D924EA80A60024EB54 /* ZYJReconnectTimer.m in Sources */,
A96621DB24EA80A60024EB54 /* ZYJMQTTStrict.m in Sources */,
......@@ -1678,21 +2032,30 @@
A96621BB24EA80A60024EB54 /* ZYJOSSCancellationToken.m in Sources */,
A966219324EA80A60024EB54 /* ZYJMJRefreshGifHeader.m in Sources */,
A9661FE524EA7AD10024EB54 /* DataSafe.m in Sources */,
A9D1B63824FE765F000F4662 /* ZYJQNNetworkInfo.m in Sources */,
A966215324EA80A60024EB54 /* ZYJZYJFMDatabaseAdditions.m in Sources */,
A9D1B61024FE765F000F4662 /* ZYJQNFileRecorder.m in Sources */,
A96621E224EA80A60024EB54 /* UIActivityIndicatorView+ZYJAFNetworking.m in Sources */,
A9D1B63924FE765F000F4662 /* ZYJQNDnsCacheFile.m in Sources */,
A966215824EA80A60024EB54 /* ZYJMJProperty.m in Sources */,
A966217F24EA80A60024EB54 /* UIButton+ZYJWebCache.m in Sources */,
A966216C24EA80A60024EB54 /* ZYJLocalConnection.m in Sources */,
A96621D724EA80A60024EB54 /* ZYJMQTTSession.m in Sources */,
A96621D624EA80A60024EB54 /* ZYJMQTTInMemoryPersistence.m in Sources */,
A9D1B63A24FE765F000F4662 /* ZYJQNUploadManager.m in Sources */,
A9D1B60824FE765F000F4662 /* ZYJQNURLProtocol.m in Sources */,
A966217724EA80A60024EB54 /* UIView+ZYJWebCache.m in Sources */,
A96621CD24EA80A60024EB54 /* ZYJMQTTLog.m in Sources */,
A9D1B60A24FE765F000F4662 /* ZYJQNDnsPrefetcher.m in Sources */,
A966219F24EA80A60024EB54 /* ZYJOSSDeleteMultipleObjectsRequest.m in Sources */,
A96621EA24EA80A60024EB54 /* ZYJAFURLRequestSerialization.m in Sources */,
A966219824EA80A60024EB54 /* ZYJMJRefreshFooter.m in Sources */,
A9D1B61824FE765F000F4662 /* ZYJQNRecord.m in Sources */,
A966216924EA80A60024EB54 /* ZYJMASViewAttribute.m in Sources */,
A9D1B63124FE765F000F4662 /* ZYJQNPHAssetFile.m in Sources */,
A966215424EA80A60024EB54 /* ZYJZYJFMResultSet.m in Sources */,
A966219D24EA80A60024EB54 /* NSMutableDictionary+ZYJOSS.m in Sources */,
A9D1B60F24FE765F000F4662 /* NSURLRequest+ZYJQNRequest.m in Sources */,
A9D1B31B24F34C25000F4662 /* OffcnIMSocketManager.m in Sources */,
A96621A424EA80A60024EB54 /* ZYJOSSNetworkingRequestDelegate.m in Sources */,
A966216E24EA80A60024EB54 /* ZYJReachStateUnloaded.m in Sources */,
......@@ -1700,16 +2063,23 @@
A966218324EA80A60024EB54 /* UIView+ZYJWebCacheOperation.m in Sources */,
A96621E024EA80A60024EB54 /* UIRefreshControl+ZYJAFNetworking.m in Sources */,
A9661FDD24EA7AD10024EB54 /* UIView+IBExtension.m in Sources */,
A9D1B62C24FE765F000F4662 /* ZYJQNUploadInfoCollector.m in Sources */,
A96621D224EA80A60024EB54 /* ZYJMQTTTransport.m in Sources */,
A9D1B63F24FE765F000F4662 /* ZYJQNRefresher.m in Sources */,
A96621DD24EA80A60024EB54 /* ZYJGCDTimer.m in Sources */,
A96621BD24EA80A60024EB54 /* ZYJOSSCompat.m in Sources */,
A966218C24EA80A60024EB54 /* ZYJMJRefreshBackNormalFooter.m in Sources */,
A9D1B62F24FE765F000F4662 /* ZYJQNResolver.m in Sources */,
A9D1B60724FE765F000F4662 /* ZYJQNDnsManager.m in Sources */,
A96621DA24EA80A60024EB54 /* ZYJMQTTSessionSynchron.m in Sources */,
A966215024EA80A60024EB54 /* ZYJZYJFMDatabaseQueue.m in Sources */,
A966219624EA80A60024EB54 /* ZYJMJRefreshComponent.m in Sources */,
A966219424EA80A60024EB54 /* ZYJMJRefreshStateHeader.m in Sources */,
A9D1B63524FE765F000F4662 /* ZYJQNBaseUpload.m in Sources */,
A96621CC24EA80A60024EB54 /* ZYJMQTTSSLSecurityPolicyTransport.m in Sources */,
A9D1B61424FE765F000F4662 /* ZYJQNZone.m in Sources */,
A96621BF24EA80A60024EB54 /* ZYJOSSRequest.m in Sources */,
A9D1B61324FE765F000F4662 /* ZYJQNDnsCacheInfo.m in Sources */,
A9661FD224EA7AD10024EB54 /* UIImage+Extension.m in Sources */,
A96621E624EA80A60024EB54 /* ZYJAFAutoPurgingImageCache.m in Sources */,
A966219C24EA80A60024EB54 /* ZYJOSSGetObjectACLRequest.m in Sources */,
......@@ -1717,36 +2087,52 @@
A96621C824EA80A60024EB54 /* ZYJOSSDeleteMultipleObjectsResult.m in Sources */,
A966217A24EA80A60024EB54 /* ZYJSDWebImageCompat.m in Sources */,
A966215E24EA80A60024EB54 /* NSString+ZYJMJExtension.m in Sources */,
A9D1B62024FE765F000F4662 /* ZYJQNAssessment.m in Sources */,
A966216324EA80A60024EB54 /* ZYJMASCompositeConstraint.m in Sources */,
A96621D124EA80A60024EB54 /* ZYJMQTTProperties.m in Sources */,
A9D1B60B24FE765F000F4662 /* ZYJQNEtag.m in Sources */,
A96621B324EA80A60024EB54 /* ZYJOSSURLRequestRetryHandler.m in Sources */,
A96621A624EA80A60024EB54 /* ZYJOSSModel.m in Sources */,
A9D1B63324FE765F000F4662 /* ZYJQNHosts.m in Sources */,
A96621AE24EA80A60024EB54 /* ZYJOSSInputStreamHelper.m in Sources */,
A96621A924EA80A60024EB54 /* ZYJOSSHttpResponseParser.m in Sources */,
A966216824EA80A60024EB54 /* ZYJMASConstraint.m in Sources */,
A96621A024EA80A60024EB54 /* NSDate+ZYJOSS.m in Sources */,
A9D1B61E24FE765F000F4662 /* ZYJQNHttpResponseInfo.m in Sources */,
A9D1B62B24FE765F000F4662 /* ZYJQNFormUpload.m in Sources */,
A96621E524EA80A60024EB54 /* ZYJAFNetworkActivityIndicatorManager.m in Sources */,
A9D1B61F24FE765F000F4662 /* ZYJQNDomain.m in Sources */,
A96621B624EA80A60024EB54 /* ZYJOSSCancellationTokenRegistration.m in Sources */,
A9D1B62724FE765F000F4662 /* ZYJQN_GTM_Base64.m in Sources */,
A9D1B63B24FE765F000F4662 /* ZYJQNPipeline.m in Sources */,
A966216524EA80A60024EB54 /* NSArray+ZYJMASAdditions.m in Sources */,
A96621B224EA80A60024EB54 /* ZYJOSSHttpdns.m in Sources */,
A9D1B61924FE765F000F4662 /* ZYJQNTransactionManager.m in Sources */,
A966215624EA80A60024EB54 /* NSObject+ZYJMJCoding.m in Sources */,
A96621B924EA80A60024EB54 /* ZYJOSSBolts.m in Sources */,
A966215A24EA80A60024EB54 /* NSObject+ZYJMJProperty.m in Sources */,
A966216224EA80A60024EB54 /* ViewController+ZYJMASAdditions.m in Sources */,
A9661FE324EA7AD10024EB54 /* NSString+MD5.m in Sources */,
A96621E324EA80A60024EB54 /* UIImageView+ZYJAFNetworking.m in Sources */,
A9D1B62624FE765F000F4662 /* ZYJQNResolvUtil.m in Sources */,
A96621E924EA80A60024EB54 /* ZYJAFURLResponseSerialization.m in Sources */,
A96621A324EA80A60024EB54 /* ZYJOSSLog.m in Sources */,
A9D1B61C24FE765F000F4662 /* ZYJQNDnspodEnterprise.m in Sources */,
A9D1B63024FE765F000F4662 /* ZYJQNSessionManager.m in Sources */,
A96621D824EA80A60024EB54 /* ZYJMQTTCoreDataPersistence.m in Sources */,
A9661FE224EA7AD10024EB54 /* NSMutableAttributedString+SDSize.m in Sources */,
A9D1B33E24FE3BE6000F4662 /* OffcnIMSqliteTestVC.m in Sources */,
A9D1B62224FE765F000F4662 /* ZYJQNFixedZone.m in Sources */,
A9D1B62924FE765F000F4662 /* ZYJQNResponseInfo.m in Sources */,
A966218F24EA80A60024EB54 /* ZYJMJRefreshAutoStateFooter.m in Sources */,
A96621E824EA80A60024EB54 /* ZYJAFNetworkReachabilityManager.m in Sources */,
A96621A524EA80A60024EB54 /* ZYJOSSGetBucketInfoRequest.m in Sources */,
A9D1B61A24FE765F000F4662 /* ZYJQNUploadInfoReporter.m in Sources */,
A9661FD324EA7AD10024EB54 /* UIImage+Color.m in Sources */,
A96621CE24EA80A60024EB54 /* ZYJMQTTMessage.m in Sources */,
A966217B24EA80A60024EB54 /* ZYJSDImageCacheConfig.m in Sources */,
A966218E24EA80A60024EB54 /* ZYJMJRefreshBackGifFooter.m in Sources */,
A9D1B62524FE765F000F4662 /* ZYJQNUrlSafeBase64.m in Sources */,
A96621C224EA80A60024EB54 /* ZYJOSSXMLDictionary.m in Sources */,
A96621C124EA80A60024EB54 /* ZYJOSSRestoreObjectRequest.m in Sources */,
A966216124EA80A60024EB54 /* ZYJMASConstraintMaker.m in Sources */,
......@@ -1755,9 +2141,12 @@
A966219524EA80A60024EB54 /* NSBundle+ZYJMJRefresh.m in Sources */,
A966215724EA80A60024EB54 /* ZYJMJPropertyType.m in Sources */,
A966216424EA80A60024EB54 /* ZYJMASViewConstraint.m in Sources */,
A9D1B64024FE765F000F4662 /* ZYJQNUpToken.m in Sources */,
A9661FE724EA7AD10024EB54 /* OffcnToast.m in Sources */,
A966215F24EA80A60024EB54 /* ZYJMJPropertyKey.m in Sources */,
A96621C024EA80A60024EB54 /* ZYJOSSPutSymlinkRequest.m in Sources */,
A9D1B62D24FE765F000F4662 /* ZYJQNPHAssetResource.m in Sources */,
A9D1B64224FE765F000F4662 /* ZYJQNSystemTool.m in Sources */,
A96621A224EA80A60024EB54 /* ZYJOSSClient.m in Sources */,
A96621D324EA80A60024EB54 /* ZYJMQTTSSLSecurityPolicy.m in Sources */,
A96621AB24EA80A60024EB54 /* ZYJOSSNSLogger.m in Sources */,
......@@ -1765,14 +2154,17 @@
A966217124EA80A60024EB54 /* ZYJFSMStateUtil.m in Sources */,
A966216724EA80A60024EB54 /* NSLayoutConstraint+ZYJMASDebugAdditions.m in Sources */,
A9661B5624EA64F20024EB54 /* main.m in Sources */,
A9D1B61D24FE765F000F4662 /* ZYJQNUserAgent.m in Sources */,
A966215D24EA80A60024EB54 /* ZYJMJExtensionConst.m in Sources */,
A966219B24EA80A60024EB54 /* ZYJOSSGetSymlinkResult.m in Sources */,
A9661FE024EA7AD10024EB54 /* NSString+JSON.m in Sources */,
A9661FD124EA7AD10024EB54 /* OffcnBaseNetworking.m in Sources */,
A96621AC24EA80A60024EB54 /* ZYJOSSDDLog.m in Sources */,
A966217524EA80A60024EB54 /* ZYJRealReachability.m in Sources */,
A9D1B60624FE765F000F4662 /* ZYJQNFile.m in Sources */,
A96621B424EA80A60024EB54 /* ZYJOSSRestoreObjectResult.m in Sources */,
A96621DF24EA80A60024EB54 /* ZYJMQTTCFSocketDecoder.m in Sources */,
A9D1B63224FE765F000F4662 /* ZYJQNIpModel.m in Sources */,
A966219224EA80A60024EB54 /* ZYJMJRefreshNormalHeader.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
......
//
//
......@@ -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
//
//
// ZYJQNHttpClient.m
// AppTest
//
// Created by yangsen on 2020/4/7.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "ZYJQNCFHttpClient.h"
#import "NSURLRequest+ZYJQNRequest.h"
@interface ZYJQNCFHttpClient()<NSStreamDelegate>
@property(nonatomic, strong)NSMutableURLRequest *request;
@property(nonatomic, assign)BOOL isReadResponseHeader;
@property(nonatomic, assign)BOOL isInputStreamEvaluated;
@property(nonatomic, strong)NSInputStream *inputStream;
@property(nonatomic, strong)NSRunLoop *inputStreamRunLoop;
// 模拟上传进度
@property(nonatomic, strong)NSTimer *progressTimer; // 进度定时器
@property(nonatomic, assign)int64_t totalBytesSent; // 已上传大小
@property(nonatomic, assign)int64_t bytesSent; // 模拟每次上传大小
@property(nonatomic, assign)int64_t maxBytesSent; // 模拟上传最大值
@property(nonatomic, assign)int64_t totalBytesExpectedToSend; // 总大小
@end
@implementation ZYJQNCFHttpClient
+ (instancetype)client:(NSURLRequest *)request{
if (!request) {
return nil;
}
ZYJQNCFHttpClient *client = [[ZYJQNCFHttpClient alloc] init];
[client setup:request];
return client;
}
- (void)setup:(NSURLRequest *)request{
@autoreleasepool {
self.request = [request mutableCopy];
NSInputStream *inputStream = [self createInputStream:self.request];
NSString *host = [self.request ZYJQN_domain];
if ([self.request ZYJQN_isHttps]) {
[self setInputStreamSNI:inputStream sni:host];
}
[self setupProgress];
self.inputStream = inputStream;
}
}
- (void)startLoading{
[self openInputStream];
[self startProgress];
}
- (void)stopLoading{
[self closeInputStream];
[self endProgress:YES];
}
//MARK: -- rquest -> stream
- (NSInputStream *)createInputStream:(NSURLRequest *)urlRequest{
CFStringRef urlString = (__bridge CFStringRef) [urlRequest.URL absoluteString];
CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault,
urlString,
NULL);
CFStringRef httpMethod = (__bridge CFStringRef) urlRequest.HTTPMethod;
CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
httpMethod,
url,
kCFHTTPVersion1_1);
CFRelease(url);
NSDictionary *headFieldInfo = self.request.ZYJQN_allHTTPHeaderFields;
for (NSString *headerField in headFieldInfo) {
CFStringRef headerFieldP = (__bridge CFStringRef)headerField;
CFStringRef headerFieldValueP = (__bridge CFStringRef)(headFieldInfo[headerField]);
CFHTTPMessageSetHeaderFieldValue(request, headerFieldP, headerFieldValueP);
}
NSData *httpBody = [self.request ZYJQN_getHttpBody];
if (httpBody) {
CFDataRef bodyData = (__bridge CFDataRef) httpBody;
CFHTTPMessageSetBody(request, bodyData);
}
CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
NSInputStream *inputStream = (__bridge_transfer NSInputStream *) readStream;
CFRelease(request);
return inputStream;
}
- (void)setInputStreamSNI:(NSInputStream *)inputStream sni:(NSString *)sni{
if (!sni || sni.length == 0) {
return;
}
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
[settings setObject:NSStreamSocketSecurityLevelNegotiatedSSL
forKey:NSStreamSocketSecurityLevelKey];
[settings setObject:sni
forKey:(NSString *)kCFStreamSSLPeerName];
[inputStream setProperty:settings forKey:(NSString *)CFBridgingRelease(kCFStreamPropertySSLSettings)];
}
//MARK: -- stream action
- (void)openInputStream{
if (!self.inputStreamRunLoop) {
self.inputStreamRunLoop = [NSRunLoop currentRunLoop];
}
[self.inputStream scheduleInRunLoop:self.inputStreamRunLoop
forMode:NSRunLoopCommonModes];
self.inputStream.delegate = self;
[self.inputStream open];
}
- (void)closeInputStream {
[self.inputStream removeFromRunLoop:self.inputStreamRunLoop forMode:NSRunLoopCommonModes];
[self.inputStream setDelegate:nil];
[self.inputStream close];
self.inputStream = nil;
}
- (BOOL)shouldEvaluateInputStreamServerTrust{
if (![self.request ZYJQN_isHttps] || self.isInputStreamEvaluated) {
return NO;
} else {
return YES;
}
}
- (void)evaluateInputStreamServerTrust{
if (self.isInputStreamEvaluated) {
return;
}
SecTrustRef trust = (__bridge SecTrustRef) [self.inputStream propertyForKey:(__bridge NSString *) kCFStreamPropertySSLPeerTrust];
NSString *host = [self.request allHTTPHeaderFields][@"host"];
if ([self delegate_evaluateServerTrust:trust forDomain:host]) {
self.isInputStreamEvaluated = YES;
} else {
[self delegate_onError:[NSError errorWithDomain:@"CFNetwork SSLHandshake failed"
code:-9807
userInfo:nil]];
}
}
- (void)inputStreamGetAndNotifyHttpResponse{
CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream;
CFHTTPMessageRef httpMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(httpMessage);
NSDictionary *headInfo = (__bridge_transfer NSDictionary *)headerFields;
CFStringRef httpVersion = CFHTTPMessageCopyVersion(httpMessage);
NSString *httpVersionInfo = (__bridge_transfer NSString *)httpVersion;
CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(httpMessage);
if (![self isHttpRedirectStatusCode:statusCode]) {
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:statusCode HTTPVersion:httpVersionInfo headerFields:headInfo];
[self delegate_onReceiveResponse:response];
}
CFRelease(httpMessage);
}
- (void)inputStreamGetAndNotifyHttpData{
UInt8 buffer[16 * 1024];
UInt8 *buf = NULL;
NSUInteger length = 0;
if (![self.inputStream getBuffer:&buf length:&length]) {
NSInteger amount = [self.inputStream read:buffer maxLength:sizeof(buffer)];
buf = buffer;
length = amount;
}
NSData *data = [[NSData alloc] initWithBytes:buf length:length];
[self delegate_didLoadData:data];
}
- (void)inputStreamDidLoadHttpResponse{
[self delegate_didFinish];
}
- (BOOL)isInputStreamHttpResponseHeaderComplete{
CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream;
CFHTTPMessageRef responseMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
BOOL isComplete = CFHTTPMessageIsHeaderComplete(responseMessage);
CFRelease(responseMessage);
return isComplete;
}
- (BOOL)shouldInputStreamRedirect{
CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream;
CFHTTPMessageRef responseMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(responseMessage);
CFRelease(responseMessage);
return [self isHttpRedirectStatusCode:statusCode];
}
- (BOOL)isHttpRedirectStatusCode:(NSInteger)code{
if (code >= 300 && code < 400) {
return YES;
} else {
return NO;
}
}
- (void)inputStreamRedirect{
CFReadStreamRef readStream = (__bridge CFReadStreamRef)self.inputStream;
CFHTTPMessageRef responseMessage = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(responseMessage);
NSDictionary *headInfo = (__bridge_transfer NSDictionary *)headerFields;
NSString *urlString = headInfo[@"Location"];
if (!urlString) {
urlString = headInfo[@"location"];
}
if (!urlString) {
return;
}
CFStringRef httpVersion = CFHTTPMessageCopyVersion(responseMessage);
NSString *httpVersionString = (__bridge_transfer NSString *)httpVersion;
CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(responseMessage);
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"GET";
NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL
statusCode:statusCode
HTTPVersion:httpVersionString
headerFields:headInfo];
[self delegate_redirectedToRequest:request redirectResponse:response];
CFRelease(responseMessage);
}
//MARK: -- NSStreamDelegate
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
@autoreleasepool {
switch (eventCode) {
case NSStreamEventHasBytesAvailable:{
if (![self isInputStreamHttpResponseHeaderComplete]) {
break;
}
if ([self shouldEvaluateInputStreamServerTrust]) {
[self evaluateInputStreamServerTrust];
}
if (self.isReadResponseHeader == NO) {
self.isReadResponseHeader = YES;
[self inputStreamGetAndNotifyHttpResponse];
}
[self inputStreamGetAndNotifyHttpData];
}
break;
case NSStreamEventHasSpaceAvailable:
break;
case NSStreamEventErrorOccurred:{
[self endProgress: YES];
[self closeInputStream];
[self delegate_onError:[self.inputStream streamError]];
}
break;
case NSStreamEventEndEncountered:{
if ([self shouldInputStreamRedirect]) {
[self inputStreamRedirect];
} else {
[self endProgress: NO];
[self inputStreamDidLoadHttpResponse];
}
}
break;
default:
break;
}
}
}
//MARK: -- progress and timer action
- (void)setupProgress{
self.bytesSent = 256 * 1024;
self.totalBytesExpectedToSend = [self.request.ZYJQN_getHttpBody length];
self.maxBytesSent = self.totalBytesExpectedToSend * 0.5;
}
- (void)startProgress{
[self createTimer];
}
- (void)endProgress:(BOOL)hasError{
[self invalidateTimer];
if (!hasError) {
[self delegate_didSendBodyData:self.totalBytesExpectedToSend - self.totalBytesSent
totalBytesSent:self.totalBytesExpectedToSend
totalBytesExpectedToSend:self.totalBytesExpectedToSend];
}
}
- (void)createTimer{
if (_progressTimer) {
[self invalidateTimer];
}
__weak typeof(self) weakSelf = self;
NSTimer *timer = [NSTimer timerWithTimeInterval:0.5
target:weakSelf
selector:@selector(timerAction)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode];
[self timerAction];
_progressTimer = timer;
}
- (void)invalidateTimer{
[self.progressTimer invalidate];
self.progressTimer = nil;
}
- (void)timerAction{
self.totalBytesSent += self.bytesSent;
if (self.totalBytesSent < self.maxBytesSent) {
[self delegate_didSendBodyData:self.bytesSent
totalBytesSent:self.totalBytesSent
totalBytesExpectedToSend:self.totalBytesExpectedToSend];
}
}
//MARK: -- delegate action
- (void)delegate_redirectedToRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse{
if ([self.delegate respondsToSelector:@selector(redirectedToRequest:redirectResponse:)]) {
[self.delegate redirectedToRequest:request redirectResponse:redirectResponse];
}
}
- (BOOL)delegate_evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain{
if ([self.delegate respondsToSelector:@selector(evaluateServerTrust:forDomain:)]) {
return [self.delegate evaluateServerTrust:serverTrust forDomain:domain];
} else {
return NO;
}
}
- (void)delegate_onError:(NSError *)error{
if ([self.delegate respondsToSelector:@selector(onError:)]) {
[self.delegate onError:error];
}
}
- (void)delegate_didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
if ([self.delegate respondsToSelector:@selector(didSendBodyData:
totalBytesSent:
totalBytesExpectedToSend:)]) {
[self.delegate didSendBodyData:bytesSent
totalBytesSent:totalBytesSent
totalBytesExpectedToSend:totalBytesExpectedToSend];
}
}
- (void)delegate_onReceiveResponse:(NSURLResponse *)response{
if ([self.delegate respondsToSelector:@selector(onReceiveResponse:)]) {
[self.delegate onReceiveResponse:response];
}
}
- (void)delegate_didLoadData:(NSData *)data{
if ([self.delegate respondsToSelector:@selector(didLoadData:)]) {
[self.delegate didLoadData:data];
}
}
- (void)delegate_didFinish{
if ([self.delegate respondsToSelector:@selector(didFinish)]) {
[self.delegate didFinish];
}
}
@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
//
//
// ZYJQNConcurrentResumeUpload.m
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2019/7/15.
// Copyright © 2019 Qiniu. All rights reserved.
//
#import "ZYJQNConcurrentResumeUpload.h"
@interface ZYJQNConcurrentRecorderInfo : NSObject
@property (nonatomic, strong) NSNumber *totalSize; // total size of the file
@property (nonatomic, strong) NSNumber *modifyTime; // modify time of the file
@property (nonatomic, copy) NSString *host; // upload host used last time
@property (nonatomic, strong) NSArray<NSDictionary *> *contextsInfo; // concurrent upload contexts info
- (instancetype)init __attribute__((unavailable("use recorderInfoWithTotalSize:totalSize:modifyTime:host:contextsInfo: instead.")));
@end
@implementation ZYJQNConcurrentRecorderInfo
+ (instancetype)recorderInfoWithTotalSize:(NSNumber *)totalSize modifyTime:(NSNumber *)modifyTime host:(NSString *)host contextsInfo:(NSArray<NSDictionary *> *)contextsInfo {
return [[ZYJQNConcurrentRecorderInfo alloc] initWithTotalSize:totalSize modifyTime:modifyTime host:host contextsInfo:contextsInfo];
}
- (instancetype)initWithTotalSize:(NSNumber *)totalSize modifyTime:(NSNumber *)modifyTime host:(NSString *)host contextsInfo:(NSArray<NSDictionary *> *)contextsInfo {
self = [super init];
if (self) {
_totalSize = totalSize ? totalSize : @0;
_modifyTime = modifyTime ? modifyTime : @0;
_host = host ? host : @"";
_contextsInfo = contextsInfo ? contextsInfo : @[];
}
return self;
}
- (NSData *)buildRecorderInfoJsonData:(NSError **)error {
NSDictionary *recorderInfo = @{
@"total_size": _totalSize,
@"modify_time": _modifyTime,
@"host": _host,
@"contexts_info": _contextsInfo
};
NSData *data = [NSJSONSerialization dataWithJSONObject:recorderInfo options:NSJSONWritingPrettyPrinted error:error];
return data;
}
+ (ZYJQNConcurrentRecorderInfo *)buildRecorderInfoWithData:(NSData *)data error:(NSError **)error {
NSDictionary *recorderInfo = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:error];
return [[self class] recorderInfoWithTotalSize:recorderInfo[@"total_size"] modifyTime:recorderInfo[@"modify_time"] host:recorderInfo[@"host"] contextsInfo:recorderInfo[@"contexts_info"]];
}
@end
@interface ZYJQNConcurrentTask: NSObject
@property (nonatomic, assign) int index; // block index in the file
@property (nonatomic, assign) UInt32 size; // total size of the block
@property (atomic, assign) UInt32 uploadedSize; // uploaded size of the block
@property (nonatomic, copy) NSString *context;
@property (nonatomic, assign) BOOL isTaskCompleted;
- (instancetype)init __attribute__((unavailable("use concurrentTaskWithBlockIndex:blockSize: instead.")));
@end
@implementation ZYJQNConcurrentTask
+ (instancetype)concurrentTaskWithBlockIndex:(int)index blockSize:(UInt32)size {
return [[ZYJQNConcurrentTask alloc] initWithBlockIndex:index blockSize:size];
}
- (instancetype)initWithBlockIndex:(int)index blockSize:(UInt32)size
{
self = [super init];
if (self) {
_isTaskCompleted = NO;
_uploadedSize = 0;
_size = size;
_index = index;
}
return self;
}
@end
@interface ZYJQNConcurrentTaskQueue: NSObject
@property (nonatomic, strong) id<ZYJQNFileDelegate> file;
@property (nonatomic, strong) ZYJQNConfiguration *config;
@property (nonatomic, strong) ZYJQNUpToken *token; // token
@property (nonatomic, assign) UInt32 totalSize; // 文件总大小
@property (nonatomic, strong) NSArray<NSDictionary *> *contextsInfo; // 续传context信息
@property (nonatomic, strong) NSMutableArray<ZYJQNConcurrentTask *> *taskQueueArray; // block 任务队列
@property (nonatomic, assign) UInt32 taskQueueCount; // 实际并发任务数量
@property (atomic, assign) int nextTaskIndex; // 下一个任务的index
@property (nonatomic, assign, getter=isAllCompleted) BOOL isAllCompleted; // completed
@property (nonatomic, assign, getter=totalPercent) float totalPercent; // 上传总进度
@property (nonatomic, assign) BOOL isConcurrentTaskError; // error
@property (nonatomic, strong) ZYJQNResponseInfo *info; // errorInfo if error
@property (nonatomic, strong) NSDictionary *resp; // errorResp if error
- (instancetype)init __attribute__((unavailable("use taskQueueWithFile:config:totalSize:recordInfo:token: instead.")));
@end
@implementation ZYJQNConcurrentTaskQueue
+ (instancetype)taskQueueWithFile:(id<ZYJQNFileDelegate>)file
config:(ZYJQNConfiguration *)config
totalSize:(UInt32)totalSize
contextsInfo:(NSArray<NSDictionary *> *)contextsInfo
token:(ZYJQNUpToken *)token {
return [[ZYJQNConcurrentTaskQueue alloc] initWithFile:file
config:config
totalSize:totalSize
contextsInfo:contextsInfo
token:token];
}
- (instancetype)initWithFile:(id<ZYJQNFileDelegate>)file
config:(ZYJQNConfiguration *)config
totalSize:(UInt32)totalSize
contextsInfo:(NSArray<NSDictionary *> *)contextsInfo
token:(ZYJQNUpToken *)token {
self = [super init];
if (self) {
_file = file;
_config = config;
_totalSize = totalSize;
_contextsInfo = contextsInfo;
_token = token;
_taskQueueArray = [NSMutableArray array];
_isConcurrentTaskError = NO;
_nextTaskIndex = 0;
_taskQueueCount = 0;
[self initTaskQueue];
}
return self;
}
- (void)initTaskQueue {
// add recover task
if (_contextsInfo.count > 0) {
for (NSDictionary *info in _contextsInfo) {
int block_index = [info[@"block_index"] intValue];
UInt32 block_size = [info[@"block_size"] unsignedIntValue];
NSString *context = info[@"context"];
ZYJQNConcurrentTask *recoveryTask = [ZYJQNConcurrentTask concurrentTaskWithBlockIndex:block_index blockSize:block_size];
recoveryTask.uploadedSize = block_size;
recoveryTask.context = context;
recoveryTask.isTaskCompleted = YES;
[_taskQueueArray addObject:recoveryTask];
}
}
int blockCount = _totalSize % kZYJQNBlockSize == 0 ? _totalSize / kZYJQNBlockSize : _totalSize / kZYJQNBlockSize + 1;
_taskQueueCount = blockCount > _config.concurrentTaskCount ? _config.concurrentTaskCount : blockCount;
for (int i = 0; i < blockCount; i++) {
BOOL isTaskExisted = NO;
for (int j = 0; j < _taskQueueArray.count; j++) {
if (_taskQueueArray[j].index == i) {
isTaskExisted = YES;
break;
}
}
if (!isTaskExisted) {
UInt32 left = _totalSize - i * kZYJQNBlockSize;
UInt32 blockSize = left < kZYJQNBlockSize ? left : kZYJQNBlockSize;
ZYJQNConcurrentTask *task = [ZYJQNConcurrentTask concurrentTaskWithBlockIndex:i blockSize:blockSize];
[_taskQueueArray addObject:task];
}
}
}
- (ZYJQNConcurrentTask *)getNextTask {
ZYJQNConcurrentTask *nextTask = nil;
while (_nextTaskIndex < _taskQueueArray.count) {
ZYJQNConcurrentTask *task = _taskQueueArray[_nextTaskIndex];
_nextTaskIndex++;
if (!task.isTaskCompleted) {
nextTask = task;
break;
}
}
return nextTask;
}
- (void)reset {
// reset
_contextsInfo = nil;
_resp = nil;
_info = nil;
_nextTaskIndex = 0;
_taskQueueCount = 0;
_isConcurrentTaskError = NO;
[_taskQueueArray removeAllObjects];
[self initTaskQueue];
}
- (void)buildErrorWithInfo:(ZYJQNResponseInfo *)info resp:(NSDictionary *)resp {
if (_isConcurrentTaskError) return;
_isConcurrentTaskError = YES;
_info = info;
_resp = resp;
}
- (BOOL)completeTask:(ZYJQNConcurrentTask *)task withContext:(NSString *)context {
task.uploadedSize = task.size;
task.context = context;
task.isTaskCompleted = YES;
return _nextTaskIndex < _taskQueueArray.count;
}
- (NSArray *)getRecordInfo {
NSMutableArray *infoArray = [NSMutableArray array];
for (ZYJQNConcurrentTask *task in _taskQueueArray) {
if (task.isTaskCompleted) {
[infoArray addObject:@{
@"block_index":@(task.index),
@"block_size":@(task.size),
@"context":task.context
}];
}
}
return infoArray;
}
- (NSArray *)getContexts {
NSArray *sortedTaskQueueArray = [_taskQueueArray sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
ZYJQNConcurrentTask *task1 = obj1;
ZYJQNConcurrentTask *task2 = obj2;
return task1.index > task2.index;
}];
NSMutableArray *contextArray = [NSMutableArray arrayWithCapacity:sortedTaskQueueArray.count];
for (ZYJQNConcurrentTask *task in sortedTaskQueueArray) {
if (task.isTaskCompleted) {
[contextArray addObject:task.context];
}
}
return contextArray;
}
- (BOOL)isAllCompleted {
BOOL isAllTaskCompleted = YES;
for (ZYJQNConcurrentTask *task in _taskQueueArray) {
if (!task.isTaskCompleted) {
isAllTaskCompleted = NO;
break;
}
}
return isAllTaskCompleted && !_isConcurrentTaskError && !_info && !_resp;
}
- (float)totalPercent {
long long totalUploadSize = 0;
for (ZYJQNConcurrentTask *task in _taskQueueArray) {
totalUploadSize += task.uploadedSize;
}
return totalUploadSize / (float)_totalSize < 0.95 ? totalUploadSize / (float)_totalSize : 0.95;
}
@end
@interface ZYJQNConcurrentResumeUpload ()
@property (nonatomic, strong) id<ZYJQNRecorderDelegate> recorder;
@property (nonatomic, strong) id<ZYJQNFileDelegate> file;
@property (nonatomic, strong) ZYJQNConcurrentTaskQueue *taskQueue;
@property (nonatomic, strong) ZYJQNConcurrentRecorderInfo *recordInfo; // 续传信息
@property (nonatomic, copy) NSString *recorderKey;
@property (nonatomic, strong) NSDictionary *headers;
@property (nonatomic, strong) dispatch_group_t uploadGroup;
@property (nonatomic, strong) dispatch_queue_t uploadQueue;
@property (nonatomic, copy) NSString *upHost;
@property (nonatomic, assign) UInt32 retriedTimes; // 当前域名重试次数
@property (nonatomic, assign) int64_t modifyTime;
@property (nonatomic, assign, getter=isResettingTaskQueue) BOOL resettingTaskQueue;
@end
@implementation ZYJQNConcurrentResumeUpload
- (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 {
if (self = [super init]) {
self.file = file;
self.size = (UInt32)[file size];
self.key = key;
self.recorder = recorder;
self.recorderKey = recorderKey;
self.modifyTime = [file modifyTime];
self.option = option != nil ? option : [ZYJQNUploadOption defaultOptions];
self.complete = block;
self.headers = @{@"Authorization" : [NSString stringWithFormat:@"UpToken %@", token.token], @"Content-Type" : @"application/octet-stream"};
self.config = config;
self.token = token;
self.access = token.access;
self.sessionManager = sessionManager;
self.identifier = identifier;
self.resettingTaskQueue = NO;
self.retriedTimes = 0;
self.currentZoneType = ZYJQNZoneInfoTypeMain;
self.uploadGroup = dispatch_group_create();
self.uploadQueue = dispatch_queue_create("com.qiniu.concurrentUpload", DISPATCH_QUEUE_SERIAL);
self.recordInfo = [self recoveryFromRecord];
self.taskQueue = [ZYJQNConcurrentTaskQueue
taskQueueWithFile:file
config:config
totalSize:self.size
contextsInfo:self.recordInfo.contextsInfo
token:self.token];
[Collector update:ZYJCK_blockApiVersion value:@1 identifier:self.identifier];
}
return self;
}
- (void)run {
self.requestType = ZYJQNRequestType_mkblk;
if (self.recordInfo.host && ![self.recordInfo.host isEqualToString:@""]) {
self.upHost = self.recordInfo.host;
} else {
self.upHost = [self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil];
}
for (int i = 0; i < _taskQueue.taskQueueCount; i++) {
dispatch_group_enter(_uploadGroup);
dispatch_group_async(_uploadGroup, _uploadQueue, ^{
[self putBlockWithTask:[self.taskQueue getNextTask] host:self.upHost];
});
}
dispatch_group_notify(_uploadGroup, _uploadQueue, ^{
if (self.taskQueue.isAllCompleted) {
self.requestType = ZYJQNRequestType_mkfile;
[self makeFile];
} else {
if (self.isResettingTaskQueue) {
self.resettingTaskQueue = NO;
[self removeRecord];
[self.taskQueue reset];
[self run];
} else {
self.complete(self.taskQueue.info, self.key, self.taskQueue.resp);
}
}
});
}
- (void)retryWithDelay:(BOOL)needDelay task:(ZYJQNConcurrentTask *)task host:(NSString *)host {
if (needDelay) {
ZYJQNAsyncRunAfter(self.config.retryInterval, self.uploadQueue, ^{
switch (self.requestType) {
case ZYJQNRequestType_mkblk:
[self putBlockWithTask:task host:host];
break;
case ZYJQNRequestType_mkfile:
[self makeFile];
break;
default:
break;
}
});
} else {
switch (self.requestType) {
case ZYJQNRequestType_mkblk:
[self putBlockWithTask:task host:host];
break;
case ZYJQNRequestType_mkfile:
[self makeFile];
break;
default:
break;
}
}
}
- (void)putBlockWithTask:(ZYJQNConcurrentTask *)task host:(NSString *)host {
if (self.taskQueue.isConcurrentTaskError) {
dispatch_group_leave(self.uploadGroup);
return;
}
if (self.option.cancellationSignal()) {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector userCancel:self.identifier];
[self invalidateTasksWithErrorInfo:info resp:nil];
dispatch_group_leave(self.uploadGroup);
return;
}
NSError *error;
NSData *data = [self.file read:task.index * kZYJQNBlockSize size:task.size error:&error];
if (error) {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithLocalIOError:error identifier:self.identifier];
[self invalidateTasksWithErrorInfo:info resp:nil];
dispatch_group_leave(self.uploadGroup);
return;
}
UInt32 blockCrc = [ZYJQNCrc32 data:data];
ZYJQNInternalProgressBlock progressBlock = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
if (self.taskQueue.isConcurrentTaskError) return;
if (totalBytesWritten >= task.uploadedSize) {
task.uploadedSize = (unsigned int)totalBytesWritten;
}
self.option.progressHandler(self.key, self.taskQueue.totalPercent);
};
ZYJQNCompleteBlock completionHandler = ^(ZYJQNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody) {
dispatch_async(self.uploadQueue, ^{
if (self.taskQueue.isConcurrentTaskError) {
dispatch_group_leave(self.uploadGroup);
return;
}
[self collectHttpResponseInfo:httpResponseInfo fileOffset:task.index * task.size];
NSString *ctx = respBody[@"ctx"];
NSNumber *crc = respBody[@"crc32"];
if (httpResponseInfo.isOK && ctx && crc && [crc unsignedLongValue] == blockCrc) {
self.option.progressHandler(self.key, self.taskQueue.totalPercent);
BOOL hasMore = [self.taskQueue completeTask:task withContext:ctx];
[self record];
if (hasMore) {
[self retryWithDelay:YES task:[self.taskQueue getNextTask] host:self.upHost];
} else {
dispatch_group_leave(self.uploadGroup);
}
} else if (httpResponseInfo.couldRetry) {
if (self.retriedTimes < self.config.retryMax) {
if ([host isEqualToString:self.upHost]) {
self.retriedTimes++;
}
[self retryWithDelay:YES task:task host:self.upHost];
} else {
self.retriedTimes = 0;
if (self.config.allowBackupHost) {
if (self.recordInfo.host) {
self.currentZoneType = ZYJQNZoneInfoTypeMain;
[self invalidateTasksWithErrorInfo:nil resp:nil];
self.resettingTaskQueue = YES;
dispatch_group_leave(self.uploadGroup);
} else {
NSString *nextHost = [self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:host];
if (nextHost) {
self.upHost = nextHost;
[self retryWithDelay:YES task:task host:self.upHost];
} else {
ZYJQNZonesInfo *zonesInfo = [self.config.zone getZonesInfoWithToken:self.token];
if (self.currentZoneType == ZYJQNZoneInfoTypeMain && zonesInfo.hasBackupZone) {
self.currentZoneType = ZYJQNZoneInfoTypeBackup;
[self invalidateTasksWithErrorInfo:nil resp:nil];
self.resettingTaskQueue = YES;
} else {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
[self invalidateTasksWithErrorInfo:info resp:respBody];
}
dispatch_group_leave(self.uploadGroup);
}
}
} else {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
[self invalidateTasksWithErrorInfo:info resp:respBody];
dispatch_group_leave(self.uploadGroup);
}
}
} else {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
[self invalidateTasksWithErrorInfo:info resp:respBody];
dispatch_group_leave(self.uploadGroup);
}
});
};
NSString *url = [[NSString alloc] initWithFormat:@"%@/mkblk/%u", host, (unsigned int)task.size];
[self post:url withData:data withCompleteBlock:completionHandler withProgressBlock:progressBlock];
}
- (void)makeFile {
NSString *mime = [[NSString alloc] initWithFormat:@"/mimeType/%@", [ZYJQNUrlSafeBase64 encodeString:self.option.mimeType]];
__block NSString *url = [[NSString alloc] initWithFormat:@"%@/mkfile/%u%@", self.upHost, (unsigned int)self.size, mime];
if (self.key != nil) {
NSString *keyStr = [[NSString alloc] initWithFormat:@"/key/%@", [ZYJQNUrlSafeBase64 encodeString:self.key]];
url = [NSString stringWithFormat:@"%@%@", url, keyStr];
}
[self.option.params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
url = [NSString stringWithFormat:@"%@/%@/%@", url, key, [ZYJQNUrlSafeBase64 encodeString:obj]];
}];
//添加路径
NSString *fname = [[NSString alloc] initWithFormat:@"/fname/%@", [ZYJQNUrlSafeBase64 encodeString:[[_file path] lastPathComponent]]];
url = [NSString stringWithFormat:@"%@%@", url, fname];
NSArray *contextArray = [_taskQueue getContexts];
NSString *bodyStr = [contextArray componentsJoinedByString:@","];
NSMutableData *postData = [NSMutableData data];
[postData appendData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]];
ZYJQNCompleteBlock completionHandler = ^(ZYJQNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody) {
dispatch_async(self.uploadQueue, ^{
[self collectHttpResponseInfo:httpResponseInfo fileOffset:self.size];
if (httpResponseInfo.isOK) {
[self removeRecord];
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 (self.retriedTimes < self.config.retryMax) {
self.retriedTimes++;
[self retryWithDelay:YES task:nil host:nil];
} else {
self.retriedTimes = 0;
if (self.config.allowBackupHost) {
if (self.recordInfo.host) {
self.currentZoneType = ZYJQNZoneInfoTypeMain;
[self.taskQueue reset];
[self removeRecord];
[self run];
} else {
NSString *nextHost = [self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:self.upHost];
if (nextHost) {
self.upHost = nextHost;
[self retryWithDelay:YES task:nil host:nil];
} else {
ZYJQNZonesInfo *zonesInfo = [self.config.zone getZonesInfoWithToken:self.token];
if (self.currentZoneType == ZYJQNZoneInfoTypeMain && zonesInfo.hasBackupZone) {
self.currentZoneType = ZYJQNZoneInfoTypeBackup;
[self.taskQueue reset];
[self removeRecord];
[self run];
} 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 post:url withData:postData withCompleteBlock:completionHandler withProgressBlock:nil];
}
- (void)record {
NSString *key = self.recorderKey;
if (self.recorder == nil || key == nil || [key isEqualToString:@""]) {
return;
}
NSNumber *total_size = @(self.size);
NSNumber *modify_time = [NSNumber numberWithLongLong:_modifyTime];
ZYJQNConcurrentRecorderInfo *recorderInfo = [ZYJQNConcurrentRecorderInfo recorderInfoWithTotalSize:total_size
modifyTime:modify_time
host:self.upHost
contextsInfo:[self.taskQueue getRecordInfo]];
NSError *error;
NSData *recorderInfoData = [recorderInfo buildRecorderInfoJsonData:&error];
if (error != nil) {
NSLog(@"up record json error %@ %@", key, error);
return;
}
error = [self.recorder set:key data:recorderInfoData];
if (error != nil) {
NSLog(@"up record set error %@ %@", key, error);
}
}
- (void)removeRecord {
if (self.recorder == nil) {
return;
}
self.recordInfo = nil;
[self.recorder del:self.recorderKey];
}
- (ZYJQNConcurrentRecorderInfo *)recoveryFromRecord {
NSString *key = self.recorderKey;
if (self.recorder == nil || key == nil || [key isEqualToString:@""]) {
return nil;
}
NSData *data = [self.recorder get:key];
if (data == nil) {
return nil;
}
NSError *error;
ZYJQNConcurrentRecorderInfo *recordInfo = [ZYJQNConcurrentRecorderInfo buildRecorderInfoWithData:data error:&error];
if (error != nil) {
NSLog(@"recovery error %@ %@", key, error);
[self.recorder del:self.key];
return nil;
}
if (recordInfo.totalSize == nil || recordInfo.modifyTime == nil || recordInfo.contextsInfo == nil || recordInfo.contextsInfo.count == 0) {
return nil;
}
UInt32 size = [recordInfo.totalSize unsignedIntValue];
if (size != self.size) {
return nil;
}
UInt32 t = [recordInfo.modifyTime unsignedIntValue];
if (t != self.modifyTime) {
NSLog(@"modify time changed %u, %llu", (unsigned int)t, self.modifyTime);
return nil;
}
return recordInfo;
}
- (void)post:(NSString *)url
withData:(NSData *)data
withCompleteBlock:(ZYJQNCompleteBlock)completeBlock
withProgressBlock:(ZYJQNInternalProgressBlock)progressBlock {
[self.sessionManager post:url withData:data withParams:nil withHeaders:self.headers withIdentifier:self.identifier withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:self.option.cancellationSignal withAccess:self.access];
}
- (void)invalidateTasksWithErrorInfo:(ZYJQNResponseInfo *)info resp:(NSDictionary *)resp {
if (self.taskQueue.isConcurrentTaskError) return;
[self.taskQueue buildErrorWithInfo:info resp:resp];
[self.sessionManager invalidateSessionWithIdentifier:self.identifier];
}
@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
//
//
// ZYJQNDnsManager.m
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNDnsManager.h"
#import "ZYJQNDomain.h"
#import "ZYJQNHosts.h"
#import "ZYJQNIP.h"
#import "ZYJQNLruCache.h"
#import "ZYJQNNetworkInfo.h"
#import "ZYJQNRecord.h"
#import "ZYJQNResolverDelegate.h"
#include "ZYJQNGetAddrInfo.h"
const int kZYJQNDomainHijackingCode = -7001;
const int kZYJQNDomainNotOwnCode = -7002;
const int kZYJQNDomainSeverError = -7003;
@interface ZYJQNDnsManager ()
@property (nonatomic, strong) ZYJQNLruCache *cache;
@property (atomic) ZYJQNNetworkInfo *curNetwork;
@property (nonatomic) NSArray *resolvers;
@property (atomic) UInt32 resolverStatus;
@property (nonatomic) ZYJQNHosts *hosts;
@property (nonatomic, strong) id<ZYJQNIpSorter> sorter;
@end
//static inline BOOL bits_isSet(UInt32 v, int index) {
// return (v & (1 << index)) != 0;
//}
static inline UInt32 bits_set(UInt32 v, int bitIndex) {
return v |= (1 << bitIndex);
}
static inline UInt32 bits_leadingZeros(UInt32 x) {
UInt32 y;
int n = 32;
y = x >> 16;
if (y != 0) {
n = n - 16;
x = y;
}
y = x >> 8;
if (y != 0) {
n = n - 8;
x = y;
}
y = x >> 4;
if (y != 0) {
n = n - 4;
x = y;
}
y = x >> 2;
if (y != 0) {
n = n - 2;
x = y;
}
y = x >> 1;
if (y != 0) {
return n - 2;
}
return n - x;
}
static NSMutableArray *trimCname(NSArray *records) {
NSMutableArray *array = [[NSMutableArray alloc] init];
for (ZYJQNRecord *r in records) {
if (r.type == kZYJQNTypeA || r.type == kZYJQNTypeAAAA) {
[array addObject:r];
}
}
return array;
}
static NSArray *records2Ips(NSArray *records) {
NSMutableArray *array = [[NSMutableArray alloc] init];
for (ZYJQNRecord *r in records) {
[array addObject:r.value];
}
return array;
}
@interface ZYJDummySorter : NSObject <ZYJQNIpSorter>
@end
@implementation ZYJDummySorter
//sorted already
- (NSArray *)sort:(NSArray *)ips {
return ips;
}
@end
@implementation ZYJQNDnsManager
- (NSArray <NSString *> *)query:(NSString *)domain {
return [self queryWithDomain:[[ZYJQNDomain alloc] init:domain]];
}
- (NSArray <ZYJQNRecord *> *)queryRecords:(NSString *)domain{
if (domain == nil) {
return nil;
}
if ([ZYJQNIP mayBeIpV4:domain]) {
return [NSArray arrayWithObject:domain];
}
NSArray *ips = [self queryInternalWithDomain:[[ZYJQNDomain alloc] init:domain] needRecordInfo:YES];
return [_sorter sort:ips];
}
- (NSArray <NSString *> *)queryWithDomain:(ZYJQNDomain *)domain {
if (domain.domain == nil) {
return nil;
}
if ([ZYJQNIP mayBeIpV4:domain.domain]) {
return [NSArray arrayWithObject:domain.domain];
}
NSArray *ips = [self queryInternalWithDomain:domain needRecordInfo:NO];
return [_sorter sort:ips];
}
- (NSArray *)queryInternalWithDomain:(ZYJQNDomain *)domain needRecordInfo:(BOOL)needRecordInfo {
if (domain.hostsFirst) {
NSArray *ret = [_hosts query:domain networkInfo:_curNetwork];
if (ret != nil && ret.count != 0) {
if (needRecordInfo) {
NSMutableArray *retP = [NSMutableArray array];
for (NSString *host in ret) {
ZYJQNRecord *record = [[ZYJQNRecord alloc] init:host ttl:self.defaultTtl type:kZYJQNTypeA source:ZYJQNRecordSourceUnknown];
[retP addObject:record];
}
return [retP copy];
} else {
return ret;
}
}
}
NSMutableArray *result;
if ([_curNetwork isEqualToInfo:[ZYJQNNetworkInfo normal]] && [ZYJQNNetworkInfo isNetworkChanged]) {
@synchronized(_cache) {
[_cache removeAllObjects];
}
_resolverStatus = 0;
} else {
@synchronized(_cache) {
result = [_cache objectForKey:domain.domain];
if (result != nil && result.count > 1) {
ZYJQNRecord *first = [result firstObject];
[result removeObjectAtIndex:0];
[result addObject:first];
}
}
}
@synchronized(_cache) {
if (result != nil && result.count > 0) {
ZYJQNRecord *record = [result objectAtIndex:0];
if (![record expired:[[NSDate date] timeIntervalSince1970]]) {
if (needRecordInfo) {
return result;
} else {
return records2Ips(result);
}
}
}
}
NSArray *records = nil;
NSError *error = nil;
int firstOk = 32 - bits_leadingZeros(_resolverStatus);
for (int i = 0; i < _resolvers.count; i++) {
int pos = (firstOk + i) % _resolvers.count;
id<ZYJQNResolverDelegate> resolver = [_resolvers objectAtIndex:pos];
ZYJQNNetworkInfo *previousNetwork = _curNetwork;
NSString *previousIp = [ZYJQNNetworkInfo getIp];
records = [resolver query:domain networkInfo:previousNetwork error:&error];
if (error != nil) {
NSError *tmp = error;
error = nil;
if (tmp.code == kZYJQNDomainNotOwnCode) {
continue;
}
if (self.queryErrorHandler) {
self.queryErrorHandler(error, domain.domain);
}
}
if (records == nil || records.count == 0) {
if (_curNetwork == previousNetwork && [previousIp isEqualToString:[ZYJQNNetworkInfo getIp]]) {
_resolverStatus = bits_set(_resolverStatus, pos);
}
} else {
NSMutableArray *ret = trimCname(records);
if (_curNetwork == previousNetwork && [previousIp isEqualToString:[ZYJQNNetworkInfo getIp]]) {
@synchronized(_cache) {
[_cache setObject:ret forKey:domain.domain];
}
}
if (needRecordInfo) {
return ret;
} else {
return records2Ips(ret);
}
}
}
if (!domain.hostsFirst) {
NSArray *ret = [_hosts query:domain networkInfo:_curNetwork];
if (needRecordInfo) {
NSMutableArray *retP = [NSMutableArray array];
for (NSString *host in ret) {
ZYJQNRecord *record = [[ZYJQNRecord alloc] init:host ttl:self.defaultTtl type:kZYJQNTypeA source:ZYJQNRecordSourceUnknown];
[retP addObject:record];
}
return [retP copy];
} else {
return ret;
}
}
return nil;
}
- (instancetype)init:(NSArray *)resolvers networkInfo:(ZYJQNNetworkInfo *)netInfo {
return [self init:resolvers networkInfo:netInfo sorter:nil];
}
- (instancetype)init:(NSArray *)resolvers networkInfo:(ZYJQNNetworkInfo *)netInfo sorter:(id<ZYJQNIpSorter>)sorter {
if (self = [super init]) {
_cache = [[ZYJQNLruCache alloc] init:1024];
_curNetwork = netInfo;
_resolvers = [[NSArray alloc] initWithArray:resolvers];
_hosts = [[ZYJQNHosts alloc] init];
if (sorter == nil) {
_sorter = [[ZYJDummySorter alloc] init];
} else {
_sorter = sorter;
}
}
return self;
}
- (void)onNetworkChange:(ZYJQNNetworkInfo *)netInfo {
@synchronized(_cache) {
[_cache removeAllObjects];
}
_curNetwork = netInfo;
}
- (instancetype)putHosts:(NSString *)domain ip:(NSString *)ip {
[_hosts put:domain ip:ip];
return self;
}
- (instancetype)putHosts:(NSString *)domain ip:(NSString *)ip provider:(int)provider {
[_hosts put:domain ip:ip provider:provider];
return self;
}
- (NSURL *)queryAndReplaceWithIP:(NSURL *)url {
NSURLComponents *urlComponents = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:YES];
if (!urlComponents) {
return nil;
}
NSString *host = urlComponents.host;
NSArray *ips = [self query:host];
NSURL *URL = nil;
if (ips && ips.count > 0) {
urlComponents.host = [ZYJQNIP ipHost:ips[0]];
}
URL = urlComponents.URL;
return URL;
}
static ZYJQNGetAddrInfoCallback getAddrInfoCallback = nil;
static ZYJQN_ips_ret *dns_callback_internal(const char *host) {
if (getAddrInfoCallback == nil) {
return NULL;
}
NSString *s = [[NSString alloc] initWithUTF8String:host];
if (s == nil) {
return NULL;
}
NSArray *ips = getAddrInfoCallback(s);
if (ips == nil) {
return NULL;
}
ZYJQN_ips_ret *ret = calloc(sizeof(char *), ips.count + 1);
for (int i = 0; i < ips.count; i++) {
NSString *ip = ips[i];
char *ip2 = strdup([ip cStringUsingEncoding:NSUTF8StringEncoding]);
ret->ips[i] = ip2;
}
return ret;
}
static ZYJQN_ips_ret *dns_callback(const char *host) {
ZYJQN_ips_ret *ret = dns_callback_internal(host);
if (ret == NULL) {
//only for compatible
ZYJQN_ips_ret *ret = calloc(sizeof(char *), 2);
ret->ips[0] = strdup(host);
}
return ret;
}
static ZYJQNIpStatusCallback ipStatusCallback = nil;
static void ip_status_callback(const char *ip, int code, int time_ms) {
if (ipStatusCallback == nil) {
return;
}
NSString *s = [[NSString alloc] initWithUTF8String:ip];
if (s == nil) {
return;
}
ipStatusCallback(s, code, time_ms);
}
+ (void)setGetAddrInfoBlock:(ZYJQNGetAddrInfoCallback)block {
if ([ZYJQNIP isIpV6FullySupported] || ![ZYJQNIP isV6]) {
getAddrInfoCallback = block;
ZYJQN_set_dns_callback(dns_callback);
}
}
+ (void)setDnsManagerForGetAddrInfo:(ZYJQNDnsManager *)dns {
[ZYJQNDnsManager setGetAddrInfoBlock:^NSArray *(NSString *host) {
return [dns query:host];
}];
}
+ (void)setIpStatusCallback:(ZYJQNIpStatusCallback)block {
ipStatusCallback = block;
ZYJQN_set_ip_report_callback(ip_status_callback);
}
+ (BOOL)needHttpDns {
NSTimeZone *timeZone = [NSTimeZone localTimeZone];
NSString *tzName = [timeZone name];
return [tzName isEqual:@"Asia/Shanghai"] || [tzName isEqual:@"Asia/Chongqing"] || [tzName isEqual:@"Asia/Harbin"] || [tzName isEqual:@"Asia/Urumqi"];
}
@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
//
//
// ZYJQNDnsPrefetcher.m
// ZYJQNDNS
//
// Created by yangsen on 2020/3/26.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "ZYJQNDnsPrefetcher.h"
#import "ZYJQNInetAddress.h"
#import "ZYJQNDnsCacheInfo.h"
#import "ZYJQNConfig.h"
#import "ZYJQNDnsCacheFile.h"
#import "ZYJQNUpToken.h"
#import "ZYJQNUtils.h"
#import "ZYJQNAsyncRun.h"
#import "ZYJQNFixedZone.h"
#import "ZYJQNAutoZone.h"
#import "ZYJHappyDNS.h"
//MARK: -- ZYJHappyDNS 适配
@interface ZYJQNRecord(DNS)<ZYJQNInetAddressDelegate>
@end
@implementation ZYJQNRecord(DNS)
- (NSString *)hostValue{
return nil;
}
- (NSString *)ipValue{
return self.value;
}
- (NSNumber *)ttlValue{
return @(self.ttl);
}
- (NSNumber *)timestampValue{
return @(self.timeStamp);
}
@end
@interface ZYJQNDnsManager(DNS)<ZYJQNDnsDelegate>
@end
@implementation ZYJQNDnsManager(DNS)
- (NSArray<id<ZYJQNInetAddressDelegate>> *)lookup:(NSString *)host{
return [self queryRecords:host];
}
@end
//MARK: -- DNS Prefetcher
@interface ZYJQNDnsPrefetcher()
/// 是否正在预取,正在预取会直接取消新的预取操作请求
@property(atomic, assign)BOOL isPrefetching;
/// 获取AutoZone时的同步锁
@property(nonatomic, strong)dispatch_semaphore_t getAutoZoneSemaphore;
/// DNS信息本地缓存key
@property(nonatomic, strong)ZYJQNDnsCacheInfo *dnsCacheInfo;
/// happy的dns解析对象列表,会使用多个dns解析对象 包括系统解析
@property(nonatomic, strong)ZYJQNDnsManager * httpDns;
/// 缓存DNS解析结果
@property(nonatomic, strong)NSMutableDictionary <NSString *, NSArray<ZYJQNInetAddress *>*> *addressDictionary;
@end
@implementation ZYJQNDnsPrefetcher
+ (instancetype)shared{
static ZYJQNDnsPrefetcher *prefetcher = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
prefetcher = [[ZYJQNDnsPrefetcher alloc] init];
});
return prefetcher;
}
- (instancetype)init{
if (self = [super init]) {
_isPrefetching = NO;
}
return self;
}
//MARK: -- uploadManager初始化时,加载本地缓存到内存
/// 同步本地预取缓存 如果存在且满足使用返回false,反之为true
- (BOOL)recoverCache{
NSLog(@"== recoverCache");
id <ZYJQNRecorderDelegate> recorder = nil;
NSError *error;
recorder = [ZYJQNDnsCacheFile dnsCacheFile:kZYJQNGlobalConfiguration.dnscacheDir
error:&error];
if (error) {
return YES;
}
NSData *data = [recorder get:[ZYJQNIP local]];
if (!data) {
return YES;
}
ZYJQNDnsCacheInfo *cacheInfo = [ZYJQNDnsCacheInfo dnsCacheInfo:data];
if (!cacheInfo) {
return YES;
}
NSString *localIp = [ZYJQNIP local];
if (!localIp || localIp.length == 0) {
return YES;
}
if (![cacheInfo.localIp isEqualToString:localIp]) {
return YES;
}
[self setDnsCacheInfo:cacheInfo];
return [self recoverDnsCache:cacheInfo.info];
}
/// 本地缓存读取失败后,加载本地域名,预取DNS解析信息
- (void)localFetch{
if ([self prepareToPreFetch] == NO) {
return;
}
NSLog(@"== localFetch");
[self preFetchHosts:[self getLocalPreHost]];
[self recorderDnsCache];
[self endPreFetch];
}
//MARK: -- 检测并预取
/// 根据token检测Dns缓存信息时效,无效则预取。 完成预取操作返回YES,反之返回NO
- (void)checkAndPrefetchDnsIfNeed:(ZYJQNZone *)currentZone token:(NSString *)token{
if ([self prepareToPreFetch] == NO) {
return;
}
[self preFetchHosts:[self getCurrentZoneHosts:currentZone token:token]];
[self recorderDnsCache];
[self endPreFetch];
}
/// 检测已预取dns是否还有效,无效则重新预取
- (void)checkWhetherCachedDnsValid{
if ([self prepareToPreFetch] == NO) {
return;
}
[self preFetchHosts:[self.addressDictionary allKeys]];
[self recorderDnsCache];
[self endPreFetch];
}
//MARK: -- 强制无效缓存
// 无效缓存,会根据inetAddress的host,无效host对应的ip缓存
- (void)invalidInetAdress:(id <ZYJQNInetAddressDelegate>)inetAddress{
NSArray *inetAddressList = self.addressDictionary[inetAddress.hostValue];
NSMutableArray *inetAddressListNew = [NSMutableArray array];
for (id <ZYJQNInetAddressDelegate> inetAddressP in inetAddressList) {
if (![inetAddress.ipValue isEqualToString:inetAddressP.ipValue]) {
[inetAddressListNew addObject:inetAddressP];
}
}
[self.addressDictionary setObject:[inetAddressListNew copy] forKey:inetAddress.hostValue];
}
//MARK: -- 读取缓存的DNS信息
/// 根据host从缓存中读取DNS信息
- (NSArray <id <ZYJQNInetAddressDelegate> > *)getInetAddressByHost:(NSString *)host{
if ([self isDnsOpen] == NO) {
return nil;
}
NSArray <ZYJQNInetAddress *> *addressList = self.addressDictionary[host];
if (![addressList.firstObject isValid]) {
ZYJQNAsyncRun(^{
[[ZYJQNTransactionManager shared] setDnsCheckWhetherCachedValidTransactionAction];
});
}
return addressList;
}
//MARK: --
//MARK: -- 根据dns预取
- (BOOL)prepareToPreFetch{
if ([self isDnsOpen] == NO) {
return NO;
}
if (self.isPrefetching == YES) {
return NO;
}
NSString *localIp = [ZYJQNIP local];
if (localIp == nil ||
(self.dnsCacheInfo && ![localIp isEqualToString:self.dnsCacheInfo.localIp])) {
[self clearPreHosts];
}
self.isPrefetching = YES;
return YES;
}
- (void)endPreFetch{
self.isPrefetching = NO;
}
- (void)preFetchHosts:(NSArray <NSString *> *)fetchHosts{
self.httpDns.defaultTtl = kZYJQNGlobalConfiguration.dnsCacheTime;
NSArray *nextFetchHosts = fetchHosts;
nextFetchHosts = [self preFetchHosts:nextFetchHosts
dns:kZYJQNGlobalConfiguration.dns];
nextFetchHosts = [self preFetchHosts:nextFetchHosts
dns:self.httpDns];
}
- (NSArray *)preFetchHosts:(NSArray <NSString *> *)preHosts
dns:(id <ZYJQNDnsDelegate>)dns{
if (!preHosts || preHosts.count == 0) {
return nil;
}
if (!dns) {
return [preHosts copy];
}
NSMutableArray *failHosts = [NSMutableArray array];
for (NSString *host in preHosts) {
int rePreNum = 0;
BOOL isSuccess = NO;
while (rePreNum < kZYJQNGlobalConfiguration.dnsRepreHostNum) {
if ([self preFetchHost:host dns:dns]) {
isSuccess = YES;
break;
}
}
if (!isSuccess) {
[failHosts addObject:host];
}
}
return [failHosts copy];
}
- (BOOL)preFetchHost:(NSString *)preHost
dns:(id <ZYJQNDnsDelegate>)dns{
if (!preHost || preHost.length == 0) {
return NO;
}
NSArray<ZYJQNInetAddress *>* preAddressList = self.addressDictionary[preHost];
if (preAddressList && [preAddressList.firstObject isValid]) {
return YES;
}
NSArray <id <ZYJQNInetAddressDelegate> > * addressList = [dns lookup:preHost];
if (addressList && addressList.count > 0) {
NSMutableArray *addressListP = [NSMutableArray array];
for (id <ZYJQNInetAddressDelegate>inetAddress in addressList) {
ZYJQNInetAddress *address = [ZYJQNInetAddress inetAddress:inetAddress];
if (address) {
address.hostValue = preHost;
if (!address.ttlValue) {
address.ttlValue = @(kZYJQNDefaultDnsCacheTime);
}
if (!address.timestampValue) {
address.timestampValue = @([[NSDate date] timeIntervalSince1970]);
}
[addressListP addObject:address];
}
}
self.addressDictionary[preHost] = [addressListP copy];
return YES;
} else {
return NO;
}
}
//MARK: -- 加载和存储缓存信息
- (BOOL)recoverDnsCache:(NSDictionary *)dataDic{
if (dataDic == nil) {
return NO;
}
NSMutableDictionary *newAddressDictionary = [NSMutableDictionary dictionary];
for (NSString *key in dataDic.allKeys) {
NSArray *ips = dataDic[key];
if ([ips isKindOfClass:[NSArray class]]) {
NSMutableArray <ZYJQNInetAddress *> * addressList = [NSMutableArray array];
for (NSDictionary *ipInfo in ips) {
if ([ipInfo isKindOfClass:[NSDictionary class]]) {
ZYJQNInetAddress *address = [ZYJQNInetAddress inetAddress:ipInfo];
if (address) {
[addressList addObject:address];
}
}
}
if (addressList.count > 0) {
newAddressDictionary[key] = [addressList copy];
}
}
}
self.addressDictionary = newAddressDictionary;
NSLog(@"== recoverDnsCache");
return NO;
}
- (BOOL)recorderDnsCache{
NSTimeInterval currentTime = [ZYJQNUtils currentTimestamp];
NSString *localIp = [ZYJQNIP local];
if (localIp == nil || localIp.length == 0) {
return NO;
}
NSError *error;
id <ZYJQNRecorderDelegate> recorder = [ZYJQNDnsCacheFile dnsCacheFile:kZYJQNGlobalConfiguration.dnscacheDir
error:&error];
if (error) {
return NO;
}
NSMutableDictionary *addressInfo = [NSMutableDictionary dictionary];
for (NSString *key in self.addressDictionary.allKeys) {
NSArray *addressModelList = self.addressDictionary[key];
NSMutableArray * addressDicList = [NSMutableArray array];
for (ZYJQNInetAddress *ipInfo in addressModelList) {
NSDictionary *addressDic = [ipInfo toDictionary];
if (addressDic) {
[addressDicList addObject:addressDic];
}
}
if (addressDicList.count > 0) {
addressInfo[key] = addressDicList;
}
}
ZYJQNDnsCacheInfo *cacheInfo = [ZYJQNDnsCacheInfo dnsCacheInfo:[NSString stringWithFormat:@"%.0lf",currentTime]
localIp:localIp
info:addressInfo];
NSData *cacheData = [cacheInfo jsonData];
if (!cacheData) {
return NO;
}
[self setDnsCacheInfo:cacheInfo];
[recorder set:localIp data:cacheData];
return true;
}
- (void)clearPreHosts{
[self.addressDictionary removeAllObjects];
}
//MARK: -- 获取预取hosts
- (NSArray <NSString *> *)getLocalPreHost{
NSMutableArray *localHosts = [NSMutableArray array];
NSArray *fixedHosts = [self getFixedZoneHosts];
[localHosts addObjectsFromArray:fixedHosts];
NSString *ucHost = kZYJQNPreQueryHost;
[localHosts addObject:ucHost];
return [localHosts copy];
}
- (NSArray <NSString *> *)getAllPreHost:(ZYJQNZone *)currentZone
token:(NSString *)token{
NSMutableSet *set = [NSMutableSet set];
NSMutableArray *fetchHosts = [NSMutableArray array];
NSArray *fixedHosts = [self getFixedZoneHosts];
[fetchHosts addObjectsFromArray:fixedHosts];
NSArray *autoHosts = [self getCurrentZoneHosts:currentZone token:token];
[fetchHosts addObjectsFromArray:autoHosts];
NSString *ucHost = kZYJQNPreQueryHost;
[fetchHosts addObject:ucHost];
NSArray *cacheHost = [self getCacheHosts];
[fetchHosts addObjectsFromArray:cacheHost];
NSMutableArray *fetchHostsFiltered = [NSMutableArray array];
for (NSString *host in fetchHosts) {
NSInteger countBeforeAdd = set.count;
[set addObject:host];
NSInteger countAfterAdd = set.count;
if (countBeforeAdd < countAfterAdd) {
[fetchHostsFiltered addObject:host];
}
}
return [fetchHostsFiltered copy];
}
- (NSArray <NSString *> *)getCurrentZoneHosts:(ZYJQNZone *)currentZone
token:(NSString *)token{
if (!currentZone || !token) {
return nil;
}
[currentZone preQuery:[ZYJQNUpToken parse:token] on:^(int code, ZYJQNHttpResponseInfo *httpResponseInfo) {
dispatch_semaphore_signal(self.semaphore);
}];
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
ZYJQNZonesInfo *autoZonesInfo = [currentZone getZonesInfoWithToken:[ZYJQNUpToken parse:token]];
NSMutableArray *autoHosts = [NSMutableArray array];
NSArray *zoneInfoList = autoZonesInfo.zonesInfo;
for (ZYJQNZoneInfo *info in zoneInfoList) {
for (NSString *host in info.upDomainsList) {
[autoHosts addObject:host];
}
}
return [autoHosts copy];
}
- (NSArray <NSString *> *)getFixedZoneHosts{
NSArray <ZYJQNFixedZone *> *fixedZones = [ZYJQNFixedZone localsZoneInfo];
NSMutableArray *localHosts = [NSMutableArray array];
for (ZYJQNFixedZone *fixZone in fixedZones) {
ZYJQNZonesInfo *zonesInfo = [fixZone getZonesInfoWithToken:nil];
for (ZYJQNZoneInfo *zoneInfo in zonesInfo.zonesInfo) {
for (NSString *host in zoneInfo.upDomainsList) {
[localHosts addObject:host];
}
}
}
return [localHosts copy];
}
- (NSArray <NSString *> *)getCacheHosts{
return self.addressDictionary.allKeys;
}
//MARK: --
- (BOOL)isDnsOpen{
return [kZYJQNGlobalConfiguration isDnsOpen];
}
- (NSMutableDictionary<NSString *,NSArray<ZYJQNInetAddress *> *> *)addressDictionary{
if (_addressDictionary == nil) {
_addressDictionary = [NSMutableDictionary dictionary];
}
return _addressDictionary;
}
- (dispatch_semaphore_t)semaphore{
if (_getAutoZoneSemaphore == NULL) {
_getAutoZoneSemaphore = dispatch_semaphore_create(0);
}
return _getAutoZoneSemaphore;
}
- (ZYJQNDnsManager *)httpDns{
if (_httpDns == nil) {
ZYJQNResolver *systemDnsresolver = [ZYJQNResolver systemResolver];
ZYJQNDnspodFree *dnspodFree = [[ZYJQNDnspodFree alloc] init];
ZYJQNDnsManager *httpDns = [[ZYJQNDnsManager alloc] init:@[systemDnsresolver, dnspodFree]
networkInfo:nil];
_httpDns = httpDns;
}
return _httpDns;
}
@end
//MARK: -- DNS 事务
@implementation ZYJQNTransactionManager(Dns)
#define kZYJQNLoadLocalDnstransactionName @"ZYJQNLoadLocalDnstransaction"
#define kZYJQNDnsCheckAndPrefetchtransactionName @"ZYJQNDnsCheckAndPrefetchtransactionName"
- (void)addDnsLocalLoadTransaction{
if ([kZYJQNDnsPrefetcher isDnsOpen] == NO) {
return;
}
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
ZYJQNTransaction *transaction = [ZYJQNTransaction transaction:kZYJQNLoadLocalDnstransactionName after:0 action:^{
[kZYJQNDnsPrefetcher recoverCache];
[kZYJQNDnsPrefetcher localFetch];
}];
[[ZYJQNTransactionManager shared] addTransaction:transaction];
});
}
- (BOOL)addDnsCheckAndPrefetchTransaction:(ZYJQNZone *)currentZone token:(NSString *)token{
if (!token) {
return NO;
}
if ([kZYJQNDnsPrefetcher isDnsOpen] == NO) {
return NO;
}
BOOL ret = NO;
@synchronized (kZYJQNDnsPrefetcher) {
ZYJQNTransactionManager *transactionManager = [ZYJQNTransactionManager shared];
if (![transactionManager existtransactionsForName:token]) {
ZYJQNTransaction *transaction = [ZYJQNTransaction transaction:token after:0 action:^{
[kZYJQNDnsPrefetcher checkAndPrefetchDnsIfNeed:currentZone token:token];
}];
[transactionManager addTransaction:transaction];
ret = YES;
}
}
return ret;
}
- (void)setDnsCheckWhetherCachedValidTransactionAction{
if ([kZYJQNDnsPrefetcher isDnsOpen] == NO) {
return;
}
@synchronized (kZYJQNDnsPrefetcher) {
ZYJQNTransactionManager *transactionManager = [ZYJQNTransactionManager shared];
ZYJQNTransaction *transaction = [transactionManager transactionsForName:kZYJQNDnsCheckAndPrefetchtransactionName].firstObject;
if (!transaction) {
ZYJQNTransaction *transaction = [ZYJQNTransaction timeTransaction:kZYJQNDnsCheckAndPrefetchtransactionName
after:10
interval:120
action:^{
[kZYJQNDnsPrefetcher checkWhetherCachedDnsValid];
}];
[transactionManager addTransaction:transaction];
} else {
[transactionManager performTransaction:transaction];
}
}
}
@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
//
//
// ZYJQNPipeline.h
// ZYJQiniuSDK
//
// Created by BaiLong on 2017/7/25.
// Copyright © 2017年 Qiniu. All rights reserved.
//
#ifndef ZYJQNPipeline_h
#define ZYJQNPipeline_h
@class ZYJQNHttpResponseInfo;
@interface ZYJQNPipelineConfig : NSObject
/**
* 上报打点域名
*/
@property (copy, nonatomic, readonly) NSString *host;
/**
* 超时时间 单位 秒
*/
@property (assign) UInt32 timeoutInterval;
- (instancetype)initWithHost:(NSString *)host;
- (instancetype)init;
@end
/**
* 上传完成后的回调函数
*
* @param info 上下文信息,包括状态码,错误值
*/
typedef void (^ZYJQNPipelineCompletionHandler)(ZYJQNHttpResponseInfo *info);
@interface ZYJQNPipeline : NSObject
- (instancetype)init:(ZYJQNPipelineConfig *)config;
- (void)pumpRepo:(NSString *)repo
event:(NSDictionary *)data
token:(NSString *)token
handler:(ZYJQNPipelineCompletionHandler)handler;
- (void)pumpRepo:(NSString *)repo
events:(NSArray<NSDictionary *> *)data
token:(NSString *)token
handler:(ZYJQNPipelineCompletionHandler)handler;
@end
#endif /* ZYJQNPipeline_h */
//
//
// ZYJQNPipeline.m
// ZYJQiniuSDK
//
// Created by BaiLong on 2017/7/25.
// Copyright © 2017年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNSessionManager.h"
#import "ZYJQNPipeline.h"
@implementation ZYJQNPipelineConfig
- (instancetype)init {
return [self initWithHost:@"https://pipeline.qiniu.com"];
}
- (instancetype)initWithHost:(NSString*)host {
if (self = [super init]) {
_host = host;
_timeoutInterval = 10;
}
return self;
}
@end
@interface ZYJQNPipeline ()
@property (nonatomic) ZYJQNSessionManager *httpManager;
@property (nonatomic) ZYJQNPipelineConfig* config;
+ (NSDateFormatter*)dateFormatter;
@end
static NSString* buildString(NSObject* obj) {
NSString* v;
if ([obj isKindOfClass:[NSNumber class]]) {
NSNumber* num = (NSNumber*)obj;
if (num == (void*)kCFBooleanFalse) {
v = @"false";
} else if (num == (void*)kCFBooleanTrue) {
v = @"true";
} else if (!strcmp(num.objCType, @encode(BOOL))) {
if ([num intValue] == 0) {
v = @"false";
} else {
v = @"true";
}
} else {
v = num.stringValue;
}
} else if ([obj isKindOfClass:[NSString class]]) {
v = (NSString*)obj;
v = [v stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
v = [v stringByReplacingOccurrencesOfString:@"\t" withString:@"\\t"];
} else if ([obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[NSSet class]]) {
v = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:obj options:kNilOptions error:nil] encoding:NSUTF8StringEncoding];
} else if ([obj isKindOfClass:[NSDate class]]) {
v = [[ZYJQNPipeline dateFormatter] stringFromDate:(NSDate*)obj];
} else {
v = [obj description];
}
return v;
}
static void formatPoint(NSDictionary* event, NSMutableString* buffer) {
[event enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSObject* obj, BOOL* stop) {
if (obj == nil || [obj isEqual:[NSNull null]]) {
return;
}
[buffer appendString:key];
[buffer appendString:@"="];
[buffer appendString:buildString(obj)];
[buffer appendString:@"\t"];
}];
NSRange range = NSMakeRange(buffer.length - 1, 1);
[buffer replaceCharactersInRange:range withString:@"\n"];
}
static NSMutableString* formatPoints(NSArray<NSDictionary*>* events) {
NSMutableString* str = [NSMutableString new];
[events enumerateObjectsUsingBlock:^(NSDictionary* _Nonnull obj, NSUInteger idx, BOOL* _Nonnull stop) {
formatPoint(obj, str);
}];
return str;
}
@implementation ZYJQNPipeline
- (instancetype)init:(ZYJQNPipelineConfig*)config {
if (self = [super init]) {
if (config == nil) {
config = [ZYJQNPipelineConfig new];
}
_config = config;
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
_httpManager = [[ZYJQNSessionManager alloc] initWithProxy:nil timeout:config.timeoutInterval urlConverter:nil];
#endif
}
return self;
}
- (void)pumpRepo:(NSString*)repo
event:(NSDictionary*)data
token:(NSString*)token
handler:(ZYJQNPipelineCompletionHandler)handler {
NSMutableString* str = [NSMutableString new];
formatPoint(data, str);
[self pumpRepo:repo string:str token:token handler:handler];
}
- (void)pumpRepo:(NSString*)repo
events:(NSArray<NSDictionary*>*)data
token:(NSString*)token
handler:(ZYJQNPipelineCompletionHandler)handler {
NSMutableString* str = formatPoints(data);
[self pumpRepo:repo string:str token:token handler:handler];
}
- (NSString*)url:(NSString*)repo {
return [NSString stringWithFormat:@"%@/v2/repos/%@/data", _config.host, repo];
}
- (void)pumpRepo:(NSString*)repo
string:(NSString*)str
token:(NSString*)token
handler:(ZYJQNPipelineCompletionHandler)handler {
NSDictionary* headers = @{ @"Authorization" : token,
@"Content-Type" : @"text/plain" };
[_httpManager post:[self url:repo] withData:[str dataUsingEncoding:NSUTF8StringEncoding] withParams:nil withHeaders:headers withIdentifier:nil withCompleteBlock:^(ZYJQNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody) {
handler(httpResponseInfo);
} withProgressBlock:nil withCancelBlock:nil withAccess:nil];
}
+ (NSDateFormatter*)dateFormatter {
static NSDateFormatter* formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSDateFormatter new];
[formatter setLocale:[NSLocale currentLocale]];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"];
[formatter setTimeZone:[NSTimeZone defaultTimeZone]];
});
return formatter;
}
@end
//
//
// ZYJQNRecord.h
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* A 记录
*/
extern const int kZYJQNTypeA;
/**
* AAAA 记录
*/
extern const int kZYJQNTypeAAAA;
/**
* Cname 记录
*/
extern const int kZYJQNTypeCname;
/**
* Txt 记录
*/
extern const int kZYJQNTypeTXT;
typedef NS_ENUM(NSUInteger, ZYJQNRecordSource) {
ZYJQNRecordSourceUnknown,
ZYJQNRecordSourceDnspodFree,
ZYJQNRecordSourceDnspodEnterprise,
ZYJQNRecordSourceSystem,
};
@interface ZYJQNRecord : NSObject
@property (nonatomic, strong, readonly) NSString *value;
@property (nonatomic, readonly) int ttl;
@property (nonatomic, readonly) int type;
@property (nonatomic, readonly) long long timeStamp;
@property (nonatomic, readonly) ZYJQNRecordSource source;
- (instancetype)init:(NSString *)value
ttl:(int)ttl
type:(int)type
source:(ZYJQNRecordSource)source;
- (BOOL)expired:(long long)time;
@end
//
//
// ZYJQNRecord.m
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNRecord.h"
const int kZYJQNTypeA = 1;
const int kZYJQNTypeAAAA = 28;
const int kZYJQNTypeCname = 5;
const int kZYJQNTypeTXT = 16;
@implementation ZYJQNRecord
- (instancetype)init:(NSString *)value
ttl:(int)ttl
type:(int)type
source:(ZYJQNRecordSource)source {
if (self = [super init]) {
_value = value;
_type = type;
_ttl = ttl;
_source = source;
_timeStamp = [[NSDate date] timeIntervalSince1970];
}
return self;
}
- (BOOL)expired:(long long)time {
return time > _timeStamp + _ttl;
}
@end
//
//
// ZYJQNRecorderDelegate.h
// ZYJQiniuSDK
//
// Created by bailong on 14/10/5.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* 为持久化上传记录,根据上传的key以及文件名 生成持久化的记录key
*
* @param uploadKey 上传的key
* @param filePath 文件名
*
* @return 根据uploadKey, filepath 算出的记录key
*/
typedef NSString * (^ZYJQNRecorderKeyGenerator)(NSString *uploadKey, NSString *filePath);
/**
* 持久化记录接口,可以实现将记录持久化到文件,数据库等
*/
@protocol ZYJQNRecorderDelegate <NSObject>
/**
* 保存记录
*
* @param key 持久化记录的key
* @param value 持久化记录上传状态信息
*
* @return 错误信息,成功为nil
*/
- (NSError *)set:(NSString *)key
data:(NSData *)value;
/**
* 取出保存的持久化上传状态信息
*
* @param key 持久化记录key
*
* @return 上传中间状态信息
*/
- (NSData *)get:(NSString *)key;
/**
* 删除持久化记录,一般在上传成功后自动调用
*
* @param key 持久化记录key
*
* @return 错误信息,成功为nil
*/
- (NSError *)del:(NSString *)key;
/**
* 缓存文件名称
*/
- (NSString *)getFileName;
@end
//
//
// ZYJQNRefresher.h
// ZYJHappyDNS
//
// Created by bailong on 16/7/20.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYJQNRefresher : NSObject
@end
//
//
// ZYJQNRefresher.m
// ZYJHappyDNS
//
// Created by bailong on 16/7/20.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNRefresher.h"
@implementation ZYJQNRefresher
@end
//
//
// ZYJQNResolv.h
// ZYJHappyDNS
//
// Created by bailong on 16/5/28.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#ifndef ZYJQNResolv_h
#define ZYJQNResolv_h
extern BOOL isV6(NSString *address);
extern int setup_dns_server(void *res, NSString *dns_server, NSUInteger timeout);
#endif /* ZYJQNResolv_h */
//
//
// ZYJQNResolvUtil.m
// ZYJHappyDNS
//
// Created by bailong on 16/5/28.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
#include <arpa/inet.h>
#include <resolv.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#import "ZYJQNIP.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#import <MobileCoreServices/MobileCoreServices.h>
#import <UIKit/UIKit.h>
#endif
BOOL isV6(NSString *address) {
return strchr(address.UTF8String, ':') != NULL;
}
int setup_dns_server(void *_res_state, NSString *dns_server, NSUInteger timeout) {
res_state res = (res_state)_res_state;
int r = res_ninit(res);
if (r != 0) {
return r;
}
res->retrans = (int)timeout;
res->retry = 1;
if (dns_server == nil) {
return 0;
}
res->options |= RES_IGNTC;
union res_sockaddr_union server = {0};
struct addrinfo hints = {0}, *ai = NULL;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int ret = getaddrinfo(dns_server.UTF8String, "53", &hints, &ai);
if (ret != 0) {
return ret;
}
int family = ai->ai_family;
if (family == AF_INET6) {
((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53);
server.sin6 = *((struct sockaddr_in6 *)ai->ai_addr);
} else {
server.sin = *((struct sockaddr_in *)ai->ai_addr);
}
if (![ZYJQNIP isIpV6FullySupported] && family == AF_INET) {
if ([ZYJQNIP isV6]) {
freeaddrinfo(ai);
ai = NULL;
bzero(&hints, 0);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
char buf[64] = {0};
ZYJQN_nat64(buf, sizeof(buf), (uint32_t)server.sin.sin_addr.s_addr);
int ret = getaddrinfo(buf, "53", &hints, &ai);
if (ret != 0) {
return -1;
}
((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53);
server.sin6 = *((struct sockaddr_in6 *)ai->ai_addr);
}
}
freeaddrinfo(ai);
res_setservers(res, &server, 1);
return 0;
}
//
//
// ZYJQNResolver.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 ZYJQNResolver : NSObject <ZYJQNResolverDelegate>
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error;
// @deprecated typo
- (instancetype)initWithAddres:(NSString *)address DEPRECATED_ATTRIBUTE;
- (instancetype)initWithAddress:(NSString *)address;
- (instancetype)initWithAddress:(NSString *)address
timeout:(NSUInteger)time;
+ (instancetype)systemResolver;
+ (NSString *)systemDnsServer;
@end
//
//
// ZYJQNResolver.m
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#include <arpa/inet.h>
#include <resolv.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#import "ZYJQNDomain.h"
#import "ZYJQNIP.h"
#import "ZYJQNRecord.h"
#import "ZYJQNResolver.h"
#import "ZYJQNResolvUtil.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#import <MobileCoreServices/MobileCoreServices.h>
#import <UIKit/UIKit.h>
#endif
@interface ZYJQNResolver ()
@property (nonatomic, readonly, strong) NSString *address;
@property (nonatomic, readonly) NSUInteger timeout;
@end
static NSArray *query_ip_v4(res_state res, const char *host) {
u_char answer[2000];
int len = res_nquery(res, host, ns_c_in, ns_t_a, answer, sizeof(answer));
ns_msg handle;
ns_initparse(answer, len, &handle);
int count = ns_msg_count(handle, ns_s_an);
if (count <= 0) {
res_ndestroy(res);
return nil;
}
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count];
char buf[32];
char cnameBuf[NS_MAXDNAME];
memset(cnameBuf, 0, sizeof(cnameBuf));
for (int i = 0; i < count; i++) {
ns_rr rr;
if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) {
res_ndestroy(res);
return nil;
}
int t = ns_rr_type(rr);
int ttl = ns_rr_ttl(rr);
NSString *val;
if (t == ns_t_a) {
const char *p = inet_ntop(AF_INET, ns_rr_rdata(rr), buf, sizeof(buf));
val = [NSString stringWithUTF8String:p];
} else if (t == ns_t_cname) {
int x = ns_name_uncompress(answer, &(answer[len]), ns_rr_rdata(rr), cnameBuf, sizeof(cnameBuf));
if (x <= 0) {
continue;
}
val = [NSString stringWithUTF8String:cnameBuf];
memset(cnameBuf, 0, sizeof(cnameBuf));
} else {
continue;
}
ZYJQNRecord *record = [[ZYJQNRecord alloc] init:val ttl:ttl type:t source:ZYJQNRecordSourceSystem];
[array addObject:record];
}
res_ndestroy(res);
return array;
}
@implementation ZYJQNResolver
- (instancetype)initWithAddres:(NSString *)address {
return [self initWithAddress:address];
}
- (instancetype)initWithAddress:(NSString *)address {
return [self initWithAddress:address timeout:ZYJQN_DNS_DEFAULT_TIMEOUT];
}
- (instancetype)initWithAddress:(NSString *)address
timeout:(NSUInteger)time {
if (self = [super init]) {
_address = address;
_timeout = time;
}
return self;
}
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
struct __res_state res;
int r = setup_dns_server(&res, _address, _timeout);
if (r != 0) {
if (error != nil) {
*error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:kZYJQNDomainSeverError userInfo:nil];
}
return nil;
}
NSArray *ret = query_ip_v4(&res, [domain.domain cStringUsingEncoding:NSUTF8StringEncoding]);
if (ret != nil && ret.count != 0) {
return ret;
}
if (error != nil) {
*error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:NSURLErrorDNSLookupFailed userInfo:nil];
}
return nil;
}
+ (instancetype)systemResolver {
return [[ZYJQNResolver alloc] initWithAddress:nil];
}
+ (NSString *)systemDnsServer {
struct __res_state res;
int r = res_ninit(&res);
if (r != 0) {
return nil;
}
union res_sockaddr_union server[MAXNS] = {0};
r = res_getservers(&res, server, MAXNS);
res_ndestroy(&res);
if (r <= 0) {
return nil;
}
int family = server[0].sin.sin_family;
char buf[64] = {0};
const void *addr;
if (family == AF_INET6) {
addr = &server[0].sin6.sin6_addr;
} else {
addr = &server[0].sin.sin_addr;
}
const char *p = inet_ntop(family, addr, buf, sizeof(buf));
if (p == NULL) {
return nil;
}
return [NSString stringWithUTF8String:p];
}
@end
//
//
// ZYJQNResolverDelegate.h
// ZYJHappyDNS
//
// Created by bailong on 15/6/23.
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
//
#import <Foundation/Foundation.h>
extern const int kZYJQNDomainHijackingCode;
extern const int kZYJQNDomainNotOwnCode;
extern const int kZYJQNDomainSeverError;
#define ZYJQN_DNS_DEFAULT_TIMEOUT 20 //seconds
@class ZYJQNDomain;
@class ZYJQNNetworkInfo;
@protocol ZYJQNResolverDelegate <NSObject>
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError **)error;
@end
//
//
// ZYJQNResponseInfo.h
// ZYJQiniuSDK
//
// Created by bailong on 14/10/2.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
@class ZYJQNHttpResponseInfo;
/**
* 中途取消的状态码
*/
extern const int kZYJQNRequestCancelled;
/**
* 网络错误状态码
*/
extern const int kZYJQNNetworkError;
/**
* 错误参数状态码
*/
extern const int kZYJQNInvalidArgument;
/**
* 0 字节文件或数据
*/
extern const int kZYJQNZeroDataSize;
/**
* 错误token状态码
*/
extern const int kZYJQNInvalidToken;
/**
* 读取文件错误状态码
*/
extern const int kZYJQNFileError;
/**
* 上传完成后返回的状态信息
*/
@interface ZYJQNResponseInfo : NSObject
/**
* 状态码
*/
@property (readonly) int statusCode;
/**
* 七牛服务器生成的请求ID,用来跟踪请求信息,如果使用过程中出现问题,请反馈此ID
*/
@property (nonatomic, copy, readonly) NSString *reqId;
/**
* 七牛日志上报返回的X_Log_Client_Id
*/
@property (nonatomic, copy, readonly) NSString *xClientId;
/**
* 七牛服务器内部跟踪记录
*/
@property (nonatomic, copy, readonly) NSString *xlog;
/**
* cdn服务器内部跟踪记录
*/
@property (nonatomic, copy, readonly) NSString *xvia;
/**
* 错误信息,出错时请反馈此记录
*/
@property (nonatomic, copy, readonly) NSError *error;
/**
* 服务器域名
*/
@property (nonatomic, copy, readonly) NSString *host;
/**
* 请求消耗的时间,单位 秒
*/
@property (nonatomic, readonly) double duration;
/**
* 客户端id
*/
@property (nonatomic, readonly) NSString *id;
/**
* 时间戳
*/
@property (readonly) UInt64 timeStamp;
/**
* 是否取消
*/
@property (nonatomic, readonly, getter=isCancelled) BOOL canceled;
/**
* 成功的请求
*/
@property (nonatomic, readonly, getter=isOK) BOOL ok;
/**
* 是否网络错误
*/
@property (nonatomic, readonly, getter=isConnectionBroken) BOOL broken;
/**
* 是否为 七牛响应
*/
@property (nonatomic, readonly, getter=isNotQiniu) BOOL notQiniu;
/**
* 工厂函数,内部使用
*
* @param duration 请求完成时间,单位秒
*
* @return 取消的实例
*/
+ (instancetype)cancelWithDuration:(double)duration;
/**
* 工厂函数,内部使用
*
* @param desc 错误参数描述
* @param duration 请求完成时间,单位秒
*
* @return 错误参数实例
*/
+ (instancetype)responseInfoWithInvalidArgument:(NSString *)desc duration:(double)duration;
/**
* 工厂函数,内部使用
*
* @param desc 错误token描述
* @param duration 请求完成时间,单位秒
*
* @return 错误token实例
*/
+ (instancetype)responseInfoWithInvalidToken:(NSString *)desc duration:(double)duration;
/**
* 工厂函数,内部使用
*
* @param error 错误信息
* @param duration 请求完成时间,单位秒
*
* @return 文件错误实例
*/
+ (instancetype)responseInfoWithFileError:(NSError *)error duration:(double)duration;
/**
* 工厂函数,内部使用
*
* @param path 文件路径
* @param duration 请求完成时间,单位秒
*
* @return 文件错误实例
*/
+ (instancetype)responseInfoOfZeroData:(NSString *)path duration:(double)duration;
/**
* 工厂函数,内部使用
*
* @param httpResponseInfo 最后一次http请求的信息
* @param duration 请求完成时间,单位秒
*
* @return 实例
*/
+ (instancetype)responseInfoWithHttpResponseInfo:(ZYJQNHttpResponseInfo *)httpResponseInfo duration:(double)duration;
@end
//
//
// ZYJQNResponseInfo.m
// ZYJQiniuSDK
//
// Created by bailong on 14/10/2.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import "ZYJQNResponseInfo.h"
#import "ZYJQNHttpResponseInfo.h"
#import "ZYJQNUserAgent.h"
#import "ZYJQNVersion.h"
#import "ZYJQNUploadInfoReporter.h"
const int kZYJQNZeroDataSize = -6;
const int kZYJQNInvalidToken = -5;
const int kZYJQNFileError = -4;
const int kZYJQNInvalidArgument = -3;
const int kZYJQNRequestCancelled = -2;
const int kZYJQNNetworkError = -1;
/**
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Constants/index.html#//apple_ref/doc/constant_group/URL_Loading_System_Error_Codes
NSURLErrorUnknown = -1,
NSURLErrorCancelled = -999,
NSURLErrorBadURL = -1000,
NSURLErrorTimedOut = -1001,
NSURLErrorUnsupportedURL = -1002,
NSURLErrorCannotFindHost = -1003,
NSURLErrorCannotConnectToHost = -1004,
NSURLErrorDataLengthExceedsMaximum = -1103,
NSURLErrorNetworkConnectionLost = -1005,
NSURLErrorDNSLookupFailed = -1006,
NSURLErrorHTTPTooManyRedirects = -1007,
NSURLErrorResourceUnavailable = -1008,
NSURLErrorNotConnectedToInternet = -1009,
NSURLErrorRedirectToNonExistentLocation = -1010,
NSURLErrorBadServerResponse = -1011,
NSURLErrorUserCancelledAuthentication = -1012,
NSURLErrorUserAuthenticationRequired = -1013,
NSURLErrorZeroByteResource = -1014,
NSURLErrorCannotDecodeRawData = -1015,
NSURLErrorCannotDecodeContentData = -1016,
NSURLErrorCannotParseResponse = -1017,
NSURLErrorInternationalRoamingOff = -1018,
NSURLErrorCallIsActive = -1019,
NSURLErrorDataNotAllowed = -1020,
NSURLErrorRequestBodyStreamExhausted = -1021,
NSURLErrorFileDoesNotExist = -1100,
NSURLErrorFileIsDirectory = -1101,
NSURLErrorNoPermissionsToReadFile = -1102,
NSURLErrorSecureConnectionFailed = -1200,
NSURLErrorServerCertificateHasBadDate = -1201,
NSURLErrorServerCertificateUntrusted = -1202,
NSURLErrorServerCertificateHasUnknownRoot = -1203,
NSURLErrorServerCertificateNotYetValid = -1204,
NSURLErrorClientCertificateRejected = -1205,
NSURLErrorClientCertificateRequired = -1206,
NSURLErrorCannotLoadFromNetwork = -2000,
NSURLErrorCannotCreateFile = -3000,
NSURLErrorCannotOpenFile = -3001,
NSURLErrorCannotCloseFile = -3002,
NSURLErrorCannotWriteToFile = -3003,
NSURLErrorCannotRemoveFile = -3004,
NSURLErrorCannotMoveFile = -3005,
NSURLErrorDownloadDecodingFailedMidStream = -3006,
NSURLErrorDownloadDecodingFailedToComplete = -3007
*/
static NSString *domain = @"qiniu.com";
@interface ZYJQNResponseInfo ()
@end
@implementation ZYJQNResponseInfo
+ (instancetype)cancelWithDuration:(double)duration {
return [[ZYJQNResponseInfo alloc] initWithStatus:kZYJQNRequestCancelled errorDescription:@"cancelled by user" duration:duration];
}
+ (instancetype)responseInfoWithInvalidArgument:(NSString *)text duration:(double)duration {
return [[ZYJQNResponseInfo alloc] initWithStatus:kZYJQNInvalidArgument errorDescription:text duration:duration];
}
+ (instancetype)responseInfoWithInvalidToken:(NSString *)text duration:(double)duration {
return [[ZYJQNResponseInfo alloc] initWithStatus:kZYJQNInvalidToken errorDescription:text duration:duration];
}
+ (instancetype)responseInfoWithFileError:(NSError *)error duration:(double)duration {
return [[ZYJQNResponseInfo alloc] initWithStatus:kZYJQNFileError error:error host:nil duration:duration];
}
+ (instancetype)responseInfoOfZeroData:(NSString *)path duration:(double)duration {
NSString *desc;
if (path == nil) {
desc = @"data size is 0";
} else {
desc = [[NSString alloc] initWithFormat:@"file %@ size is 0", path];
}
return [[ZYJQNResponseInfo alloc] initWithStatus:kZYJQNZeroDataSize errorDescription:desc duration:duration];
}
+ (instancetype)responseInfoWithHttpResponseInfo:(ZYJQNHttpResponseInfo *)httpResponseInfo duration:(double)duration {
if (httpResponseInfo.hasHttpResponse) {
return [[ZYJQNResponseInfo alloc] initWithStatusCode:(int)httpResponseInfo.statusCode reqId:httpResponseInfo.reqId xlog:httpResponseInfo.xlog xvia:httpResponseInfo.xvia host:httpResponseInfo.host error:httpResponseInfo.error duration:duration];
} else {
return [[ZYJQNResponseInfo alloc] initWithNetError:httpResponseInfo.error host:httpResponseInfo.host duration:duration];
}
}
- (instancetype)initWithStatus:(int)status
errorDescription:(NSString *)text
duration:(double)duration {
NSError *error = [[NSError alloc] initWithDomain:domain code:status userInfo:@{ @"error" : text }];
return [self initWithStatus:status error:error host:nil duration:duration];
}
- (instancetype)initWithStatus:(int)status
error:(NSError *)error
host:(NSString *)host
duration:(double)duration {
if (self = [super init]) {
_statusCode = status;
_error = error;
_host = host;
_duration = duration;
_id = [ZYJQNUserAgent sharedInstance].id;
_timeStamp = [[NSDate date] timeIntervalSince1970];
_xClientId = Reporter.X_Log_Client_Id;
}
return self;
}
- (instancetype)initWithNetError:(NSError *)error
host:(NSString *)host
duration:(double)duration {
int code = kZYJQNNetworkError;
if (error != nil) {
code = (int)error.code;
}
return [[ZYJQNResponseInfo alloc] initWithStatus:code error:error host:host duration:duration];
}
- (instancetype)initWithStatusCode:(int)statusCode
reqId:(NSString *)reqId
xlog:(NSString *)xlog
xvia:(NSString *)xvia
host:(NSString *)host
error:(NSError *)error
duration:(double)duration {
if (self = [super init]) {
_statusCode = statusCode;
_reqId = reqId;
_xlog = xlog;
_xvia = xvia;
_host = host;
_error = error;
_duration = duration;
_id = [ZYJQNUserAgent sharedInstance].id;
_timeStamp = [[NSDate date] timeIntervalSince1970];
_xClientId = Reporter.X_Log_Client_Id;
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@= id: %@, ver: %@, status: %d, requestId: %@, xClientId: %@, xlog: %@, xvia: %@, host: %@ duration: %.3f s time: %llu error: %@>", NSStringFromClass([self class]), _id, kQiniuVersion, _statusCode, _reqId, _xClientId, _xlog, _xvia, _host, _duration, _timeStamp, _error];
}
- (BOOL)isCancelled {
return _statusCode == kZYJQNRequestCancelled || _statusCode == -999;
}
- (BOOL)isNotQiniu {
// reqId is nill means the server is not qiniu
return (_statusCode >= 200 && _statusCode < 500) && _reqId == nil;
}
- (BOOL)isOK {
return _statusCode == 200 && _error == nil && _reqId != nil;
}
- (BOOL)isConnectionBroken {
return _statusCode == kZYJQNNetworkError || (_statusCode < -1000 && _statusCode != -1003);
}
@end
//
//
// ZYJQNResumeUpload.h
// ZYJQiniuSDK
//
// Created by bailong on 14/10/1.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import "ZYJQNBaseUpload.h"
#import <Foundation/Foundation.h>
#import "ZYJQNFileDelegate.h"
@interface ZYJQNResumeUpload : ZYJQNBaseUpload
- (instancetype)initWithFile:(id<ZYJQNFileDelegate>)file
withKey:(NSString *)key
withToken:(ZYJQNUpToken *)token
withIdentifier:(NSString *)identifier
withCompletionHandler:(ZYJQNUpCompletionHandler)block
withOption:(ZYJQNUploadOption *)option
withRecorder:(id<ZYJQNRecorderDelegate>)recorder
withRecorderKey:(NSString *)recorderKey
withSessionManager:(ZYJQNSessionManager *)sessionManager
withConfiguration:(ZYJQNConfiguration *)config;
- (void)run;
@end
//
//
// ZYJQNResumeUpload.m
// ZYJQiniuSDK
//
// Created by bailong on 14/10/1.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import "ZYJQNResumeUpload.h"
@interface ZYJQNResumeUpload ()
@property (nonatomic, copy) NSString *recorderKey;
@property (nonatomic, strong) NSDictionary *headers;
@property (nonatomic, strong) NSMutableArray *contexts;
@property (nonatomic, strong) id<ZYJQNRecorderDelegate> recorder;
@property (nonatomic, strong) id<ZYJQNFileDelegate> file;
@property (nonatomic, copy) NSString *recordHost; // upload host in last recorder file
@property (nonatomic, assign) UInt32 chunkCrc;
@property (nonatomic, assign) float previousPercent;
@property (nonatomic, assign) int64_t modifyTime;
@end
@implementation ZYJQNResumeUpload
- (instancetype)initWithFile:(id<ZYJQNFileDelegate>)file
withKey:(NSString *)key
withToken:(ZYJQNUpToken *)token
withIdentifier:(NSString *)identifier
withCompletionHandler:(ZYJQNUpCompletionHandler)block
withOption:(ZYJQNUploadOption *)option
withRecorder:(id<ZYJQNRecorderDelegate>)recorder
withRecorderKey:(NSString *)recorderKey
withSessionManager:(ZYJQNSessionManager *)sessionManager
withConfiguration:(ZYJQNConfiguration *)config;
{
if (self = [super init]) {
self.file = file;
self.size = (UInt32)[file size];
self.key = key;
NSString *tokenUp = [NSString stringWithFormat:@"UpToken %@", token.token];
self.option = option != nil ? option : [ZYJQNUploadOption defaultOptions];
self.complete = block;
self.headers = @{@"Authorization" : tokenUp, @"Content-Type" : @"application/octet-stream"};
self.recorder = recorder;
self.sessionManager = sessionManager;
self.modifyTime = [file modifyTime];
self.recorderKey = recorderKey;
self.contexts = [[NSMutableArray alloc] initWithCapacity:(self.size + kZYJQNBlockSize - 1) / kZYJQNBlockSize];
self.config = config;
self.currentZoneType = ZYJQNZoneInfoTypeMain;
self.token = token;
self.previousPercent = 0;
self.access = token.access;
self.identifier = identifier;
[Collector update:ZYJCK_blockApiVersion value:@1 identifier:self.identifier];
}
return self;
}
- (void)record:(UInt32)offset host:(NSString *)host {
NSString *key = self.recorderKey;
if (offset == 0 || self.recorder == nil || key == nil || [key isEqualToString:@""]) {
return;
}
NSNumber *n_size = @(self.size);
NSNumber *n_offset = @(offset);
NSNumber *n_time = [NSNumber numberWithLongLong:self.modifyTime];
NSMutableDictionary *rec = [NSMutableDictionary dictionaryWithObjectsAndKeys:n_size, @"size", n_offset, @"offset", n_time, @"modify_time", host, @"host", self.contexts, @"contexts", nil];
NSError *error;
NSData *data = [NSJSONSerialization dataWithJSONObject:rec options:NSJSONWritingPrettyPrinted error:&error];
if (error != nil) {
NSLog(@"up record json error %@ %@", key, error);
return;
}
error = [self.recorder set:key data:data];
if (error != nil) {
NSLog(@"up record set error %@ %@", key, error);
}
}
- (void)removeRecord {
if (self.recorder == nil) {
return;
}
self.recordHost = nil;
[self.contexts removeAllObjects];
[self.recorder del:self.recorderKey];
}
- (UInt32)recoveryFromRecord {
NSString *key = self.recorderKey;
if (self.recorder == nil || key == nil || [key isEqualToString:@""]) {
return 0;
}
NSData *data = [self.recorder get:key];
if (data == nil) {
return 0;
}
NSError *error;
NSDictionary *info = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
if (error != nil) {
NSLog(@"recovery error %@ %@", key, error);
[self.recorder del:self.key];
return 0;
}
NSNumber *n_offset = info[@"offset"];
NSNumber *n_size = info[@"size"];
NSNumber *time = info[@"modify_time"];
NSArray *contexts = info[@"contexts"];
if (n_offset == nil || n_size == nil || time == nil || contexts == nil) {
return 0;
}
UInt32 offset = [n_offset unsignedIntValue];
UInt32 size = [n_size unsignedIntValue];
if (offset > size || size != self.size) {
return 0;
}
UInt64 t = [time unsignedLongLongValue];
if (t != self.modifyTime) {
NSLog(@"modify time changed %llu, %llu", t, self.modifyTime);
return 0;
}
self.recordHost = info[@"host"];
self.contexts = [[NSMutableArray alloc] initWithArray:contexts copyItems:true];
return offset;
}
- (void)nextTask:(UInt32)offset needDelay:(BOOL)needDelay retriedTimes:(int)retried host:(NSString *)host {
if (needDelay) {
ZYJQNAsyncRunAfter(self.config.retryInterval, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self nextTask:offset retriedTimes:retried host:host];
});
} else {
[self nextTask:offset retriedTimes:retried host:host];
}
}
- (void)nextTask:(UInt32)offset retriedTimes:(int)retried host:(NSString *)host {
if (self.option.cancellationSignal()) {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector userCancel:self.identifier];
self.complete(info, self.key, nil);
return;
}
if (offset == self.size) {
ZYJQNCompleteBlock completionHandler = ^(ZYJQNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody) {
[self collectHttpResponseInfo:httpResponseInfo fileOffset:offset];
if (httpResponseInfo.isOK) {
[self removeRecord];
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:offset needDelay:YES retriedTimes:retried + 1 host:host];
} else {
if (self.config.allowBackupHost) {
NSString *nextHost = nil;
UInt32 nextOffset = 0;
if (self.recordHost) {
self.previousPercent = 0;
[self removeRecord];
self.currentZoneType = ZYJQNZoneInfoTypeMain;
nextHost = [self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil];
nextOffset = 0;
} else {
nextHost = [self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:host];
nextOffset = offset;
}
if (nextHost) {
[self nextTask:nextOffset needDelay:YES retriedTimes:0 host:nextHost];
} else {
ZYJQNZonesInfo *zonesInfo = [self.config.zone getZonesInfoWithToken:self.token];
if (self.currentZoneType == ZYJQNZoneInfoTypeMain && zonesInfo.hasBackupZone) {
self.currentZoneType = ZYJQNZoneInfoTypeBackup;
self.previousPercent = 0;
[self removeRecord];
[self nextTask:0 needDelay:YES retriedTimes:0 host:[self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil]];
} 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 makeFile:host complete:completionHandler];
return;
}
UInt32 chunkSize = [self calcPutSize:offset];
ZYJQNInternalProgressBlock progressBlock = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
float percent = (float)(offset + totalBytesWritten) / (float)self.size;
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 completionHandler = ^(ZYJQNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody) {
[self collectHttpResponseInfo:httpResponseInfo fileOffset:offset];
NSString *ctx = respBody[@"ctx"];
NSNumber *crc = respBody[@"crc32"];
if (httpResponseInfo.isOK && ctx && crc && [crc unsignedLongValue] == self.chunkCrc) {
self.contexts[offset / kZYJQNBlockSize] = ctx;
[self record:offset + chunkSize host:host];
[self nextTask:offset + chunkSize needDelay:NO retriedTimes:retried host:host];
} else if (httpResponseInfo.couldRetry) {
if (retried < self.config.retryMax) {
[self nextTask:offset needDelay:YES retriedTimes:retried + 1 host:host];
} else {
if (self.config.allowBackupHost) {
NSString *nextHost = nil;
UInt32 nextOffset = 0;
if (self.recordHost) {
self.previousPercent = 0;
[self removeRecord];
self.currentZoneType = ZYJQNZoneInfoTypeMain;
nextHost = [self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil];
nextOffset = 0;
} else {
nextHost = [self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:host];
nextOffset = offset;
}
if (nextHost) {
[self nextTask:nextOffset needDelay:YES retriedTimes:0 host:nextHost];
} else {
ZYJQNZonesInfo *zonesInfo = [self.config.zone getZonesInfoWithToken:self.token];
if (self.currentZoneType == ZYJQNZoneInfoTypeMain && zonesInfo.hasBackupZone) {
self.currentZoneType = ZYJQNZoneInfoTypeBackup;
self.previousPercent = 0;
[self removeRecord];
[self nextTask:0 needDelay:YES retriedTimes:0 host:[self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil]];
} 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 {
if (httpResponseInfo.statusCode == 701) {
[self nextTask:(offset / kZYJQNBlockSize) * kZYJQNBlockSize needDelay:YES retriedTimes:0 host:host];
} else {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
self.complete(info, self.key, respBody);
}
}
};
if (offset % kZYJQNBlockSize == 0) {
UInt32 blockSize = [self calcBlockSize:offset];
[self makeBlock:host offset:offset blockSize:blockSize chunkSize:chunkSize progress:progressBlock complete:completionHandler];
return;
}
NSString *context = self.contexts[offset / kZYJQNBlockSize];
[self putChunk:host offset:offset size:chunkSize context:context progress:progressBlock complete:completionHandler];
}
- (UInt32)calcPutSize:(UInt32)offset {
UInt32 left = self.size - offset;
return left < self.config.chunkSize ? left : self.config.chunkSize;
}
- (UInt32)calcBlockSize:(UInt32)offset {
UInt32 left = self.size - offset;
return left < kZYJQNBlockSize ? left : kZYJQNBlockSize;
}
- (void)makeBlock:(NSString *)uphost
offset:(UInt32)offset
blockSize:(UInt32)blockSize
chunkSize:(UInt32)chunkSize
progress:(ZYJQNInternalProgressBlock)progressBlock
complete:(ZYJQNCompleteBlock)complete {
self.requestType = ZYJQNRequestType_mkblk;
NSError *error;
NSData *data = [self.file read:offset size:chunkSize error:&error];
if (error) {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithLocalIOError:error identifier:self.identifier];
self.complete(info, self.key, nil);
return;
}
NSString *url = [[NSString alloc] initWithFormat:@"%@/mkblk/%u", uphost, (unsigned int)blockSize];
self.chunkCrc = [ZYJQNCrc32 data:data];
[self post:url withData:data withCompleteBlock:complete withProgressBlock:progressBlock];
}
- (void)putChunk:(NSString *)uphost
offset:(UInt32)offset
size:(UInt32)size
context:(NSString *)context
progress:(ZYJQNInternalProgressBlock)progressBlock
complete:(ZYJQNCompleteBlock)complete {
self.requestType = ZYJQNRequestType_bput;
NSError *error;
NSData *data = [self.file read:offset size:size error:&error];
if (error) {
[self collectUploadQualityInfo];
ZYJQNResponseInfo *info = [Collector completeWithLocalIOError:error identifier:self.identifier];
self.complete(info, self.key, nil);
return;
}
UInt32 chunkOffset = offset % kZYJQNBlockSize;
NSString *url = [[NSString alloc] initWithFormat:@"%@/bput/%@/%u", uphost, context, (unsigned int)chunkOffset];
self.chunkCrc = [ZYJQNCrc32 data:data];
[self post:url withData:data withCompleteBlock:complete withProgressBlock:progressBlock];
}
- (void)makeFile:(NSString *)uphost
complete:(ZYJQNCompleteBlock)complete {
self.requestType = ZYJQNRequestType_mkfile;
NSString *mime = [[NSString alloc] initWithFormat:@"/mimeType/%@", [ZYJQNUrlSafeBase64 encodeString:self.option.mimeType]];
__block NSString *url = [[NSString alloc] initWithFormat:@"%@/mkfile/%u%@", uphost, (unsigned int)self.size, mime];
if (self.key != nil) {
NSString *keyStr = [[NSString alloc] initWithFormat:@"/key/%@", [ZYJQNUrlSafeBase64 encodeString:self.key]];
url = [NSString stringWithFormat:@"%@%@", url, keyStr];
}
[self.option.params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
url = [NSString stringWithFormat:@"%@/%@/%@", url, key, [ZYJQNUrlSafeBase64 encodeString:obj]];
}];
//添加路径
NSString *fname = [[NSString alloc] initWithFormat:@"/fname/%@", [ZYJQNUrlSafeBase64 encodeString:[self fileBaseName]]];
url = [NSString stringWithFormat:@"%@%@", url, fname];
NSMutableData *postData = [NSMutableData data];
NSString *bodyStr = [self.contexts componentsJoinedByString:@","];
[postData appendData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]];
[self post:url withData:postData withCompleteBlock:complete withProgressBlock:nil];
}
#pragma mark - 处理文件路径
- (NSString *)fileBaseName {
return [[self.file path] lastPathComponent];
}
- (void)post:(NSString *)url
withData:(NSData *)data
withCompleteBlock:(ZYJQNCompleteBlock)completeBlock
withProgressBlock:(ZYJQNInternalProgressBlock)progressBlock {
[self.sessionManager post:url withData:data withParams:nil withHeaders:self.headers withIdentifier:self.identifier withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:self.option.cancellationSignal withAccess:self.access];
}
- (void)run {
@autoreleasepool {
UInt32 offset = [self recoveryFromRecord];
[Collector update:ZYJCK_recoveredFrom value:@(offset) identifier:self.identifier];
if (offset > 0) {
[self nextTask:offset needDelay:NO retriedTimes:0 host:self.recordHost];
} else {
[self nextTask:offset needDelay:NO retriedTimes:0 host:[self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil]];
}
}
}
@end
#import <Foundation/Foundation.h>
#import "ZYJQNConfiguration.h"
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
@class ZYJQNHttpResponseInfo;
typedef void (^ZYJQNInternalProgressBlock)(long long totalBytesWritten, long long totalBytesExpectedToWrite);
typedef void (^ZYJQNCompleteBlock)(ZYJQNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody);
typedef BOOL (^ZYJQNCancelBlock)(void);
@interface ZYJQNSessionStatistics : NSObject
@property (nonatomic, copy) NSString *remoteIp;
@property (nonatomic, assign) int64_t port;
@property (nonatomic, assign) int64_t totalElapsedTime;
@property (nonatomic, assign) int64_t dnsElapsedTime;
@property (nonatomic, assign) int64_t connectElapsedTime;
@property (nonatomic, assign) int64_t tlsConnectElapsedTime;
@property (nonatomic, assign) int64_t requestElapsedTime;
@property (nonatomic, assign) int64_t waitElapsedTime;
@property (nonatomic, assign) int64_t responseElapsedTime;
@property (nonatomic, assign) int64_t bytesSent;
@property (nonatomic, assign) int64_t bytesTotal;
@property (nonatomic, assign, getter=isProxyConnection) BOOL proxyConnection;
@end
@interface ZYJQNSessionManager : NSObject
- (instancetype)initWithProxy:(NSDictionary *)proxyDict
timeout:(UInt32)timeout
urlConverter:(ZYJQNUrlConvert)converter;
- (void)multipartPost:(NSString *)url
withData:(NSData *)data
withParams:(NSDictionary *)params
withFileName:(NSString *)key
withMimeType:(NSString *)mime
withIdentifier:(NSString *)identifier
withCompleteBlock:(ZYJQNCompleteBlock)completeBlock
withProgressBlock:(ZYJQNInternalProgressBlock)progressBlock
withCancelBlock:(ZYJQNCancelBlock)cancelBlock
withAccess:(NSString *)access;
- (void)post:(NSString *)url
withData:(NSData *)data
withParams:(NSDictionary *)params
withHeaders:(NSDictionary *)headers
withIdentifier:(NSString *)identifier
withCompleteBlock:(ZYJQNCompleteBlock)completeBlock
withProgressBlock:(ZYJQNInternalProgressBlock)progressBlock
withCancelBlock:(ZYJQNCancelBlock)cancelBlock
withAccess:(NSString *)access;
- (void)get:(NSString *)url
withHeaders:(NSDictionary *)headers
withCompleteBlock:(ZYJQNCompleteBlock)completeBlock;
- (void)invalidateSessionWithIdentifier:(NSString *)identifier;
@end
#endif
//
//
// ZYJQNHttpManager.m
// ZYJQiniuSDK
//
// Created by bailong on 14/10/1.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import "ZYJQNAsyncRun.h"
#import "ZYJQNConfiguration.h"
#import "ZYJQNHttpResponseInfo.h"
#import "ZYJQNSessionManager.h"
#import "ZYJQNUserAgent.h"
#import "ZYJQNSystemTool.h"
#import "ZYJQNUploadInfoCollector.h"
#import "NSURLRequest+ZYJQNRequest.h"
#import "ZYJQNURLProtocol.h"
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
@implementation ZYJQNSessionStatistics
- (instancetype)init
{
self = [super init];
if (self) {
_port = ZYJQN_IntNotSet;
_totalElapsedTime = ZYJQN_IntNotSet;
_dnsElapsedTime = ZYJQN_IntNotSet;
_connectElapsedTime = ZYJQN_IntNotSet;
_connectElapsedTime = ZYJQN_IntNotSet;
_tlsConnectElapsedTime = ZYJQN_IntNotSet;
_requestElapsedTime = ZYJQN_IntNotSet;
_waitElapsedTime = ZYJQN_IntNotSet;
_responseElapsedTime = ZYJQN_IntNotSet;
_bytesSent = ZYJQN_IntNotSet;
_bytesTotal = ZYJQN_IntNotSet;
}
return self;
}
@end
typedef void (^ZYJQNSessionComplete)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error, ZYJQNSessionStatistics *sessionStatistics);
@interface ZYJQNSessionDelegateHandler : NSObject <NSURLSessionDataDelegate>
@property (nonatomic, copy) ZYJQNInternalProgressBlock progressBlock;
@property (nonatomic, copy) ZYJQNCancelBlock cancelBlock;
@property (nonatomic, copy) ZYJQNSessionComplete completeBlock;
@property (nonatomic, strong) NSData *responseData;
@property (nonatomic, strong) ZYJQNSessionStatistics *sessionStatistics;
@end
@implementation ZYJQNSessionDelegateHandler
- (instancetype)init
{
self = [super init];
if (self) {
_sessionStatistics = [[ZYJQNSessionStatistics alloc] init];
}
return self;
}
#pragma mark - NSURLSessionDataDelegate
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
_responseData = data;
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error {
// bytes_sent & bytes_total
_sessionStatistics.bytesSent = task.countOfBytesSent;
_sessionStatistics.bytesTotal = task.countOfBytesExpectedToSend;
self.completeBlock(_responseData, task.response, error, _sessionStatistics);
[session finishTasksAndInvalidate];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(ios(10.0)) {
if (metrics) {
if (metrics.transactionMetrics.count > 0) {
NSURLSessionTaskTransactionMetrics *transactionMetrics = metrics.transactionMetrics[0];
_sessionStatistics = [[ZYJQNSessionStatistics alloc] init];
// remote_ip & port
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
if (@available(iOS 13.0, *)) {
_sessionStatistics.remoteIp = transactionMetrics.remoteAddress;
_sessionStatistics.port = [transactionMetrics.remotePort unsignedShortValue];
}
#endif
// time
_sessionStatistics.totalElapsedTime = metrics.taskInterval.duration * 1000;
_sessionStatistics.dnsElapsedTime = [self getTimeintervalWithStartDate:transactionMetrics.domainLookupStartDate endDate:transactionMetrics.domainLookupEndDate];
_sessionStatistics.connectElapsedTime =
[self getTimeintervalWithStartDate:transactionMetrics.connectStartDate endDate:transactionMetrics.connectEndDate];
_sessionStatistics.tlsConnectElapsedTime = [self getTimeintervalWithStartDate:transactionMetrics.secureConnectionStartDate endDate:transactionMetrics.secureConnectionEndDate];
_sessionStatistics.requestElapsedTime = [self getTimeintervalWithStartDate:transactionMetrics.requestStartDate endDate:transactionMetrics.requestEndDate];
_sessionStatistics.waitElapsedTime = [self getTimeintervalWithStartDate:transactionMetrics.requestEndDate endDate:transactionMetrics.responseStartDate];
_sessionStatistics.responseElapsedTime = [self getTimeintervalWithStartDate:transactionMetrics.responseStartDate endDate:transactionMetrics.responseEndDate];
// proxy
_sessionStatistics.proxyConnection = transactionMetrics.isProxyConnection;
}
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
if (_progressBlock) {
_progressBlock(totalBytesSent, totalBytesExpectedToSend);
}
if (_cancelBlock && _cancelBlock()) {
[task cancel];
}
}
- (uint64_t)getTimeintervalWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate {
if (!startDate || !endDate) return 0;
NSTimeInterval interval = [endDate timeIntervalSinceDate:startDate];
return interval * 1000;
}
@end
@interface ZYJQNSessionManager ()
@property UInt32 timeout;
@property (nonatomic, strong) ZYJQNUrlConvert converter;
@property (nonatomic, strong) NSDictionary *proxyDict;
@property (nonatomic, strong) NSOperationQueue *delegateQueue;
@property (nonatomic, strong) NSMutableArray *sessionArray;
@property (nonatomic, strong) NSLock *lock;
@end
@implementation ZYJQNSessionManager
- (instancetype)initWithProxy:(NSDictionary *)proxyDict
timeout:(UInt32)timeout
urlConverter:(ZYJQNUrlConvert)converter {
if (self = [super init]) {
_delegateQueue = [[NSOperationQueue alloc] init];
_timeout = timeout;
_converter = converter;
_sessionArray = [NSMutableArray array];
[ZYJQNURLProtocol registerProtocol];
_lock = [[NSLock alloc] init];
}
return self;
}
- (instancetype)init {
return [self initWithProxy:nil timeout:60 urlConverter:nil];
}
- (void)sendRequest:(NSMutableURLRequest *)request
withIdentifier:(NSString *)identifier
withCompleteBlock:(ZYJQNCompleteBlock)completeBlock
withProgressBlock:(ZYJQNInternalProgressBlock)progressBlock
withCancelBlock:(ZYJQNCancelBlock)cancelBlock
withAccess:(NSString *)access {
NSString *domain = request.URL.host;
NSString *u = request.URL.absoluteString;
NSURL *url = request.URL;
if (_converter != nil) {
url = [[NSURL alloc] initWithString:_converter(u)];
request.URL = url;
domain = url.host;
}
request.ZYJQN_domain = request.URL.host;
[request setTimeoutInterval:_timeout];
[request setValue:[[ZYJQNUserAgent sharedInstance] getUserAgent:access] forHTTPHeaderField:@"User-Agent"];
[request setValue:nil forHTTPHeaderField:@"Accept-Language"];
ZYJQNSessionDelegateHandler *delegate = [[ZYJQNSessionDelegateHandler alloc] init];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ZYJQN_sessionConfiguration];
configuration.connectionProxyDictionary = _proxyDict ? _proxyDict : nil;
__block NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:_delegateQueue];
[_sessionArray addObject:@{@"identifier":identifier,@"session":session}];
delegate.cancelBlock = cancelBlock;
delegate.progressBlock = progressBlock ? progressBlock : ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
};
delegate.completeBlock = ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error, ZYJQNSessionStatistics *sessionStatistics) {
[self finishSession:session];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
ZYJQNHttpResponseInfo *info = [ZYJQNHttpResponseInfo buildResponseInfoHost:domain response:httpResponse body:data error:error sessionStatistics:sessionStatistics];
completeBlock(info, [info getResponseBody]);
};
NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:request];
[uploadTask resume];
}
- (void)multipartPost:(NSString *)url
withData:(NSData *)data
withParams:(NSDictionary *)params
withFileName:(NSString *)key
withMimeType:(NSString *)mime
withIdentifier:(NSString *)identifier
withCompleteBlock:(ZYJQNCompleteBlock)completeBlock
withProgressBlock:(ZYJQNInternalProgressBlock)progressBlock
withCancelBlock:(ZYJQNCancelBlock)cancelBlock
withAccess:(NSString *)access {
NSURL *URL = [[NSURL alloc] initWithString:url];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
request.HTTPMethod = @"POST";
NSString *boundary = @"werghnvt54wef654rjuhgb56trtg34tweuyrgf";
request.allHTTPHeaderFields = @{
@"Content-Type" : [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]
};
NSMutableData *postData = [[NSMutableData alloc] init];
for (NSString *paramsKey in params) {
NSString *pair = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n", boundary, paramsKey];
[postData appendData:[pair dataUsingEncoding:NSUTF8StringEncoding]];
id value = [params objectForKey:paramsKey];
if ([value isKindOfClass:[NSString class]]) {
[postData appendData:[value dataUsingEncoding:NSUTF8StringEncoding]];
} else if ([value isKindOfClass:[NSData class]]) {
[postData appendData:value];
}
[postData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
}
NSString *filePair = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"; filename=\"%@\"\nContent-Type:%@\r\n\r\n", boundary, @"file", key, mime];
[postData appendData:[filePair dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:data];
[postData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = postData;
[request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)postData.length] forHTTPHeaderField:@"Content-Length"];
[self sendRequest:request withIdentifier:identifier withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:cancelBlock
withAccess:access];
}
- (void)post:(NSString *)url
withData:(NSData *)data
withParams:(NSDictionary *)params
withHeaders:(NSDictionary *)headers
withIdentifier:(NSString *)identifier
withCompleteBlock:(ZYJQNCompleteBlock)completeBlock
withProgressBlock:(ZYJQNInternalProgressBlock)progressBlock
withCancelBlock:(ZYJQNCancelBlock)cancelBlock
withAccess:(NSString *)access {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:url]];
if (headers) {
[request setAllHTTPHeaderFields:headers];
}
[request setHTTPMethod:@"POST"];
if (params) {
[request setValuesForKeysWithDictionary:params];
}
[request setHTTPBody:data];
identifier = !identifier ? [[NSUUID UUID] UUIDString] : identifier;
ZYJQNAsyncRun(^{
[self sendRequest:request
withIdentifier:identifier
withCompleteBlock:completeBlock
withProgressBlock:progressBlock
withCancelBlock:cancelBlock
withAccess:access];
});
}
- (void)get:(NSString *)url
withHeaders:(NSDictionary *)headers
withCompleteBlock:(ZYJQNCompleteBlock)completeBlock {
ZYJQNAsyncRun(^{
NSURL *URL = [NSURL URLWithString:url];
NSString *domain = URL.host;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
request.ZYJQN_domain = URL.host;
ZYJQNSessionDelegateHandler *delegate = [[ZYJQNSessionDelegateHandler alloc] init];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ZYJQN_sessionConfiguration];
__block NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:self.delegateQueue];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
delegate.cancelBlock = nil;
delegate.progressBlock = nil;
delegate.completeBlock = ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error, ZYJQNSessionStatistics *sessionStatistics) {
[self finishSession:session];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
ZYJQNHttpResponseInfo *info = [ZYJQNHttpResponseInfo buildResponseInfoHost:domain response:httpResponse body:data error:error sessionStatistics:sessionStatistics];
completeBlock(info, [info getResponseBody]);
};
[dataTask resume];
});
}
- (void)finishSession:(NSURLSession *)session {
[_lock lock];
for (int i = 0; i < _sessionArray.count; i++) {
NSDictionary *sessionInfo = _sessionArray[i];
if (sessionInfo[@"session"] == session) {
[session finishTasksAndInvalidate];
[_sessionArray removeObject:sessionInfo];
break;
}
}
[_lock unlock];
}
- (void)invalidateSessionWithIdentifier:(NSString *)identifier {
[_lock lock];
for (int i = 0; i < _sessionArray.count; i++) {
NSDictionary *sessionInfo = _sessionArray[i];
if ([sessionInfo[@"identifier"] isEqualToString:identifier]) {
NSURLSession *session = sessionInfo[@"session"];
[session invalidateAndCancel];
[_sessionArray removeObject:sessionInfo];
break;
}
}
[_lock unlock];
}
@end
#endif
//
//
// ZYJQNSystem.h
// ZYJQiniuSDK
//
// Created by bailong on 15/10/13.
// Copyright © 2015年 Qiniu. All rights reserved.
//
#ifndef ZYJQNSystem_h
#define ZYJQNSystem_h
BOOL hasNSURLSession(void);
BOOL hasAts(void);
BOOL allowsArbitraryLoads(void);
BOOL isIpV6FullySupported(void);
#endif /* ZYJQNSystem_h */
//
//
// ZYJQNSystem.m
// ZYJQiniuSDK
//
// Created by bailong on 15/10/13.
// Copyright © 2015年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#import <MobileCoreServices/MobileCoreServices.h>
#import <UIKit/UIKit.h>
#else
#import <CoreServices/CoreServices.h>
#endif
BOOL hasNSURLSession() {
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED)
float sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (sysVersion < 7.0) {
return NO;
}
#else
NSOperatingSystemVersion sysVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
if (sysVersion.majorVersion < 10) {
return NO;
} else if (sysVersion.majorVersion == 10) {
return sysVersion.minorVersion >= 9;
}
#endif
return YES;
}
BOOL hasAts() {
#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 allowsArbitraryLoads() {
if (!hasAts()) {
return YES;
}
// for unit test
NSDictionary* d = [[NSBundle mainBundle] infoDictionary];
if (d == nil || d.count == 0) {
return YES;
}
NSDictionary* sec = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSAppTransportSecurity"];
if (sec == nil) {
return NO;
}
NSNumber* ats = [sec objectForKey:@"NSAllowsArbitraryLoads"];
if (ats == nil) {
return NO;
}
return ats.boolValue;
}
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;
}
//
//
// ZYJQNSystemTool.h
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2020/4/2.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYJQNSystemTool : NSObject
// 获取当前进程ID
+ (int64_t)getCurrentProcessID;
// 获取当前线程ID
+ (int64_t)getCurrentThreadID;
@end
//
//
// ZYJQNSystemTool.m
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2020/4/2.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNSystemTool.h"
#include <pthread.h>
@implementation ZYJQNSystemTool
+ (int64_t)getCurrentProcessID {
return [[NSProcessInfo processInfo] processIdentifier];
}
+ (int64_t)getCurrentThreadID {
__uint64_t threadId = 0;
if (pthread_threadid_np(0, &threadId)) {
threadId = pthread_mach_thread_np(pthread_self());
}
return threadId;
}
@end
//
//
// ZYJQNTransactionManager.h
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/1.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZYJQNTransaction : NSObject
/// 事务名称
@property(nonatomic, copy, readonly)NSString *name;
// 事务延迟执行时间 单位:秒
@property(nonatomic, assign, readonly)NSInteger after;
/// 事务内容
@property(nonatomic, copy, readonly)void(^action)(void);
/// MARK: -- 构造方法
/// 普通事务,事务体仅仅执行一次
/// @param name 事务名称
/// @param after 事务延后时间 单位:秒
/// @param action 事务体
+ (instancetype)transaction:(NSString *)name
after:(NSInteger)after
action:(void(^)(void))action;
/// 定时事务
/// @param name 事务名称
/// @param after 事务延后时间 单位:秒
/// @param interval 事务执行间隔 单位:秒
/// @param action 事务体
+ (instancetype)timeTransaction:(NSString *)name
after:(NSInteger)after
interval:(NSInteger)interval
action:(void(^)(void))action;
@end
#define kZYJQNTransactionManager [ZYJQNTransactionManager shared]
@interface ZYJQNTransactionManager : NSObject
/// 单例构造方法
+ (instancetype)shared;
/// 根据name查找事务
- (NSArray <ZYJQNTransaction *> *)transactionsForName:(NSString *)name;
/// 是否存在某个名称的事务
- (BOOL)existtransactionsForName:(NSString *)name;
/// 添加一个事务
- (void)addTransaction:(ZYJQNTransaction *)transaction;
/// 移除一个事务
- (void)removeTransaction:(ZYJQNTransaction *)transaction;
/// 在下一次循环执行事务, 该事务如果未被添加到事务列表,会自动添加
- (void)performTransaction:(ZYJQNTransaction *)transaction;
/// 销毁资源 清空事务链表 销毁常驻线程
- (void)destroyResource;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNTransactionManager.m
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/1.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNTransactionManager.h"
//MARK: -- 事务对象
typedef NS_ENUM(NSInteger, ZYJQNTransactionType){
ZYJQNTransactionTypeNormal, // 普通类型事务,事务体仅会执行一次
ZYJQNTransactionTypeTime, // 定时事务,事务体会定时执行
};
@interface ZYJQNTransaction()
// 事务类型
@property(nonatomic, assign)ZYJQNTransactionType type;
// 定时任务执行时间间隔
@property(nonatomic, assign)NSInteger interval;
// 事务延后时间 单位:秒
@property(nonatomic, assign)NSInteger after;
// 事务执行时间 与事务管理者定时器时间相关联
@property(nonatomic, assign)long long actionTime;
// 事务名称
@property(nonatomic, copy)NSString *name;
// 事务执行体
@property(nonatomic, copy)void(^action)(void);
// 下一个需要处理的事务
@property(nonatomic, strong, nullable)ZYJQNTransaction *nextTransaction;
@end
@implementation ZYJQNTransaction
+ (instancetype)transaction:(NSString *)name
after:(NSInteger)after
action:(void (^)(void))action{
ZYJQNTransaction *transaction = [[ZYJQNTransaction alloc] init];
transaction.type = ZYJQNTransactionTypeNormal;
transaction.after = after;
transaction.name = name;
transaction.action = action;
return transaction;
}
+ (instancetype)timeTransaction:(NSString *)name
after:(NSInteger)after
interval:(NSInteger)interval
action:(void (^)(void))action{
ZYJQNTransaction *transaction = [[ZYJQNTransaction alloc] init];
transaction.type = ZYJQNTransactionTypeTime;
transaction.after = after;
transaction.name = name;
transaction.interval = interval;
transaction.action = action;
return transaction;
}
- (BOOL)shouldAction:(long long)time{
if (time < self.actionTime) {
return NO;
} else {
return YES;
}
}
- (BOOL)maybeCompleted:(long long)time{
if (time >= self.actionTime && self.type == ZYJQNTransactionTypeNormal) {
return YES;
} else {
return NO;
}
}
- (void)handleAction:(long long)time{
if (![self shouldAction:time]) {
return;
}
if (self.action) {
self.action();
}
if (self.type == ZYJQNTransactionTypeNormal) {
self.actionTime = 0;
} else if(self.type == ZYJQNTransactionTypeTime) {
self.actionTime = time + self.interval;
}
}
@end
//MARK: -- 事务链表
@interface ZYJQNTransactionList : NSObject
@property(nonatomic, strong)ZYJQNTransaction *header;
@end
@implementation ZYJQNTransactionList
- (BOOL)isEmpty{
if (self.header == nil) {
return YES;
} else {
return NO;
}
}
- (NSArray <ZYJQNTransaction *> *)transactionsForName:(NSString *)name{
NSMutableArray *transactions = [NSMutableArray array];
[self enumerate:^(ZYJQNTransaction *transaction, BOOL * _Nonnull stop) {
if ([transaction.name isEqualToString:name]) {
[transactions addObject:transaction];
}
}];
return [transactions copy];
}
- (void)enumerate:(void(^)(ZYJQNTransaction *transaction, BOOL * _Nonnull stop))handler {
if (!handler) {
return;
}
BOOL isStop = NO;
ZYJQNTransaction *transaction = self.header;
while (transaction && !isStop) {
handler(transaction, &isStop);
transaction = transaction.nextTransaction;
}
}
- (void)add:(ZYJQNTransaction *)transaction{
@synchronized (self) {
ZYJQNTransaction *transactionP = self.header;
while (transactionP.nextTransaction) {
transactionP = transactionP.nextTransaction;
}
if (transactionP) {
transactionP.nextTransaction = transaction;
} else {
self.header = transaction;
}
}
}
- (void)remove:(ZYJQNTransaction *)transaction{
@synchronized (self) {
ZYJQNTransaction *transactionP = self.header;
ZYJQNTransaction *transactionLast = nil;
while (transactionP) {
if (transactionP == transaction) {
if (transactionLast) {
transactionLast.nextTransaction = transactionP.nextTransaction;
} else {
self.header = transactionP.nextTransaction;
}
break;
}
transactionLast = transactionP;
transactionP = transactionP.nextTransaction;
}
}
}
- (BOOL)has:(ZYJQNTransaction *)transaction{
@synchronized (self) {
__block BOOL has = NO;
[self enumerate:^(ZYJQNTransaction *transactionP, BOOL * _Nonnull stop) {
if (transaction == transactionP) {
has = YES;
*stop = YES;
}
}];
return has;
}
}
- (void)removeAll{
@synchronized (self) {
self.header = nil;
}
}
@end
//MARK: -- 事务管理者
@interface ZYJQNTransactionManager()
// 事务处理线程
@property(nonatomic, strong)NSThread *thread;
// 事务链表
@property(nonatomic, strong)ZYJQNTransactionList *transactionList;
// 定时器执行次数
@property(nonatomic, assign)long long time;
// 事务定时器
@property(nonatomic, strong)NSTimer *timer;
@end
@implementation ZYJQNTransactionManager
+ (instancetype)shared{
static ZYJQNTransactionManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[ZYJQNTransactionManager alloc] init];
});
return manager;
}
- (instancetype)init{
if (self = [super init]) {
_time = 0;
_transactionList = [[ZYJQNTransactionList alloc] init];
}
return self;
}
- (NSArray <ZYJQNTransaction *> *)transactionsForName:(NSString *)name{
return [self.transactionList transactionsForName:name];
}
- (BOOL)existtransactionsForName:(NSString *)name{
NSArray *transactionList = [self transactionsForName:name];
if (transactionList && transactionList.count > 0) {
return YES;
} else {
return NO;
}
}
- (void)addTransaction:(ZYJQNTransaction *)transaction{
transaction.actionTime = self.time + transaction.after;
[self.transactionList add:transaction];
[self createThread];
}
- (void)removeTransaction:(ZYJQNTransaction *)transaction{
BOOL canDestroyResource = NO;
[self.transactionList remove:transaction];
if ([self.transactionList isEmpty]) {
canDestroyResource = YES;
}
//
// if (canDestroyResource) {
// [self destroyResource];
// }
}
- (void)performTransaction:(ZYJQNTransaction *)transaction{
if (!transaction) {
return;
}
@synchronized (self) {
if (![self.transactionList has:transaction]) {
[self.transactionList add:transaction];
}
transaction.actionTime = self.time;
}
}
/// 销毁资源
- (void)destroyResource{
@synchronized (self) {
[self invalidateTimer];
[self.thread cancel];
self.thread = nil;
[self.transactionList removeAll];
}
}
//MARK: -- handle transaction action
- (void)handleAllTransaction{
[self.transactionList enumerate:^(ZYJQNTransaction *transaction, BOOL * _Nonnull stop) {
[self handleTransaction:transaction];
if ([transaction maybeCompleted:self.time]) {
[self removeTransaction:transaction];
}
}];
}
- (void)handleTransaction:(ZYJQNTransaction *)transaction{
[transaction handleAction:self.time];
}
//MARK: -- thread
- (void)createThread{
@synchronized (self) {
if (self.thread == nil) {
__weak typeof(self) weakSelf = self;
self.thread = [[NSThread alloc] initWithTarget:weakSelf
selector:@selector(threadHandler)
object:nil];
self.thread.name = @"com.qiniu.transaction";
[self.thread start];
}
}
}
- (void)threadHandler{
@autoreleasepool {
if (self.timer == nil) {
[self createTimer];
}
NSThread *thread = [NSThread currentThread];
while (thread && !thread.isCancelled) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}
}
//MARK: -- timer
- (void)createTimer{
__weak typeof(self) weakSelf = self;
NSTimer *timer = [NSTimer timerWithTimeInterval:1
target:weakSelf
selector:@selector(timerAction)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode];
[self timerAction];
_timer = timer;
}
- (void)invalidateTimer{
[self.timer invalidate];
self.timer = nil;
}
- (void)timerAction{
self.time += 1;
[self handleAllTransaction];
}
@end
//
//
// ZYJQNTxtResolver.h
// ZYJHappyDNS
//
// Created by bailong on 16/1/5.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNResolverDelegate.h"
#import <Foundation/Foundation.h>
@interface ZYJQNTxtResolver : NSObject <ZYJQNResolverDelegate>
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error;
/**
* 根据服务器地址进行初始化
*
* @param address DNS 服务器地址,nil 表示系统的
*/
- (instancetype)initWithAddress:(NSString *)address;
- (instancetype)initWithAddress:(NSString *)address timeout:(NSUInteger)time;
@end
//
//
// ZYJQNTxtResolver.m
// ZYJHappyDNS
//
// Created by bailong on 16/1/5.
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
//
#import "ZYJQNTxtResolver.h"
#include <arpa/inet.h>
#include <resolv.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#import "ZYJQNDomain.h"
#import "ZYJQNRecord.h"
#import "ZYJQNResolvUtil.h"
#import "ZYJQNResolver.h"
@interface ZYJQNTxtResolver ()
@property (nonatomic, readonly, strong) NSString *address;
@property (nonatomic, readonly) NSUInteger timeout;
@end
static NSArray *query_ip(res_state res, const char *host) {
u_char answer[1500];
int len = res_nquery(res, host, ns_c_in, ns_t_txt, answer, sizeof(answer));
ns_msg handle;
ns_initparse(answer, len, &handle);
int count = ns_msg_count(handle, ns_s_an);
if (count != 1) {
res_ndestroy(res);
return nil;
}
char txtbuf[256];
memset(txtbuf, 0, sizeof(txtbuf));
ns_rr rr;
if (ns_parserr(&handle, ns_s_an, 0, &rr) != 0) {
res_ndestroy(res);
return nil;
}
int t = ns_rr_type(rr);
int ttl = ns_rr_ttl(rr);
int rdlen = ns_rr_rdlen(rr);
if (rdlen <= 1 + 7) {
res_ndestroy(res);
return nil;
}
NSString *val;
if (t == ns_t_txt) {
memcpy(txtbuf, ns_rr_rdata(rr) + 1, rdlen - 1);
val = [NSString stringWithUTF8String:txtbuf];
} else {
res_ndestroy(res);
return nil;
}
NSArray *ipArray = [val 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:ZYJQNRecordSourceSystem];
[ret addObject:record];
}
res_ndestroy(res);
return ret;
}
@implementation ZYJQNTxtResolver
- (instancetype)initWithAddress:(NSString *)address {
return [self initWithAddress:address timeout:ZYJQN_DNS_DEFAULT_TIMEOUT];
}
- (instancetype)initWithAddress:(NSString *)address timeout:(NSUInteger)time {
if (self = [super init]) {
_address = address;
_timeout = time;
}
return self;
}
- (NSArray *)query:(ZYJQNDomain *)domain networkInfo:(ZYJQNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
struct __res_state res;
int r = setup_dns_server(&res, _address, _timeout);
if (r != 0) {
if (error != nil) {
*error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:kZYJQNDomainSeverError userInfo:nil];
}
return nil;
}
NSArray *ret = query_ip(&res, [domain.domain cStringUsingEncoding:NSUTF8StringEncoding]);
if (ret == nil && error != nil) {
*error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:NSURLErrorDNSLookupFailed userInfo:nil];
}
return ret;
}
@end
//
//
// ZYJQNURLProtocol.h
// AppTest
//
// Created by yangsen on 2020/4/7.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZYJQNURLProtocol : NSURLProtocol
+ (void)registerProtocol;
+ (void)unregisterProtocol;
@end
@interface NSURLSessionConfiguration(ZYJQNURLProtocol)
+ (NSURLSessionConfiguration *)ZYJQN_sessionConfiguration;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNURLProtocol.m
// AppTest
//
// Created by yangsen on 2020/4/7.
// Copyright © 2020 com.qiniu. All rights reserved.
//
#import "ZYJQNURLProtocol.h"
#import "ZYJQNCFHttpClient.h"
#import "NSURLRequest+ZYJQNRequest.h"
#import "ZYJQNDnsPrefetcher.h"
#import "NSObject+ZYJQNSwizzle.h"
#import <objc/runtime.h>
@interface ZYJQNRequestInfo : NSObject
@property(nonatomic, weak)NSURLSession *session;
@property(nonatomic, weak)NSURLSessionDataTask *task;
@end
@implementation ZYJQNRequestInfo
@end
@interface ZYJQNRequestInfoManager : NSObject
@property(nonatomic, strong)NSMutableDictionary <NSString *, ZYJQNRequestInfo *> *infos;
@end
@implementation ZYJQNRequestInfoManager
+ (instancetype)share{
static ZYJQNRequestInfoManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[ZYJQNRequestInfoManager alloc] init];
[manager setupData];
});
return manager;
}
- (void)setupData{
_infos = [NSMutableDictionary dictionary];
}
- (void)setRequestInfo:(ZYJQNRequestInfo *)info forRequest:(NSURLRequest *)request{
NSString *requestIdentifier = [request ZYJQN_identifier];
if (!requestIdentifier || !info) {
return;
}
@synchronized (self) {
[self.infos setObject:info forKey:requestIdentifier];
}
}
- (void)removeRequestInfoForRequest:(NSURLRequest *)request{
NSString *requestIdentifier = [request ZYJQN_identifier];
if (!requestIdentifier) {
return;
}
@synchronized (self) {
[self.infos removeObjectForKey:requestIdentifier];
}
}
- (ZYJQNRequestInfo *)getRequestInfoForRequest:(NSURLRequest *)request{
NSString *requestIdentifier = [request ZYJQN_identifier];
if (!requestIdentifier) {
return nil;
}
ZYJQNRequestInfo *info = nil;
@synchronized (self) {
info = self.infos[requestIdentifier];
}
return info;
}
@end
@interface NSURLRequest(ZYJQNHttps)
@property(nonatomic, readonly)NSURLSession *ZYJQN_session;
@property(nonatomic, readonly)NSURLSessionDataTask *ZYJQN_task;
@end
@implementation NSURLRequest(ZYJQNHttps)
- (NSURLSession *)ZYJQN_session{
return [[ZYJQNRequestInfoManager share] getRequestInfoForRequest:self].session;
}
- (NSURLSessionDataTask *)ZYJQN_task{
return [[ZYJQNRequestInfoManager share] getRequestInfoForRequest:self].task;
}
- (void)ZYJQN_setSession:(NSURLSession *)session task:(NSURLSessionDataTask *)task{
ZYJQNRequestInfo *info = [[ZYJQNRequestInfo alloc] init];
info.session = session;
info.task = task;
[[ZYJQNRequestInfoManager share] setRequestInfo:info forRequest:self];
}
- (void)ZYJQN_requestRemoveTask{
[[ZYJQNRequestInfoManager share] removeRequestInfoForRequest:self];
}
- (BOOL)ZYJQNHttps_shouldInit{
if ([self ZYJQN_isQiNiuRequest]
&& ([self.URL.absoluteString hasPrefix:@"http://"] || [self.URL.absoluteString hasPrefix:@"https://"])) {
return YES;
} else {
return NO;
}
}
@end
@interface NSURLSession(ZYJQNURLProtocol)
@end
@implementation NSURLSession(ZYJQNURLProtocol)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self ZYJQN_swizzleInstanceMethodsOfSelectorA:@selector(dataTaskWithRequest:)
selectorB:@selector(ZYJQN_dataTaskWithRequest:)];
});
}
- (NSURLSessionDataTask *)ZYJQN_dataTaskWithRequest:(NSURLRequest *)request{
NSURLSessionDataTask *task = [self ZYJQN_dataTaskWithRequest:request];
if ([request ZYJQN_isQiNiuRequest]) {
[request ZYJQN_setSession:self task:task];
}
return task;
}
@end
@interface ZYJQNURLProtocol()<ZYJQNCFHttpClientDelegate>
@property(nonatomic, strong)ZYJQNCFHttpClient *httpsClient;
@end
@implementation ZYJQNURLProtocol
#define kZYJQNRequestIdentifiers @"ZYJQNRequestIdentifiers"
+ (void)registerProtocol{
[NSURLProtocol registerClass:[ZYJQNURLProtocol class]];
}
+ (void)unregisterProtocol{
[NSURLProtocol unregisterClass:[ZYJQNURLProtocol class]];
}
//MARK: -- overload
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([NSURLProtocol propertyForKey:kZYJQNRequestIdentifiers inRequest:request]) {
return NO;
}
id <ZYJQNInetAddressDelegate> address = [kZYJQNDnsPrefetcher getInetAddressByHost:request.URL.host].firstObject;
if ([request ZYJQNHttps_shouldInit]
&& address.ipValue && address.ipValue.length > 0) {
return YES;
} else {
[request ZYJQN_requestRemoveTask];
return NO;
}
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
NSString *host = request.URL.host;
NSString *ip = [kZYJQNDnsPrefetcher getInetAddressByHost:host].firstObject.ipValue;
if (!ip || ip.length == 0) {
return request;
}
NSString *urlString = request.URL.absoluteString;
urlString = [urlString stringByReplacingOccurrencesOfString:host withString:ip];
NSMutableURLRequest *requestNew = [request mutableCopy];
requestNew.URL = [NSURL URLWithString:urlString];
return [requestNew copy];
}
- (void)startLoading {
[self loadingRequest:self.request];
}
- (void)stopLoading {
[self.httpsClient stopLoading];
self.httpsClient = nil;
}
- (void)loadingRequest:(NSURLRequest *)request{
self.httpsClient = [ZYJQNCFHttpClient client:request];
self.httpsClient.delegate = self;
[NSURLProtocol setProperty:@(YES)
forKey:kZYJQNRequestIdentifiers
inRequest:self.httpsClient.request];
[self.httpsClient startLoading];
}
//MARK: -- delegate
- (void)didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
id <NSURLSessionTaskDelegate> sessionDelegate = (id <NSURLSessionTaskDelegate>)self.request.ZYJQN_session.delegate;
if ([sessionDelegate respondsToSelector:@selector(URLSession:
task:
didSendBodyData:
totalBytesSent:
totalBytesExpectedToSend:)]) {
[sessionDelegate URLSession:self.request.ZYJQN_session
task:self.request.ZYJQN_task
didSendBodyData:bytesSent
totalBytesSent:totalBytesSent
totalBytesExpectedToSend:totalBytesExpectedToSend];
}
}
- (void)didFinish {
[self.client URLProtocolDidFinishLoading:self];
[self.request ZYJQN_requestRemoveTask];
}
- (void)didLoadData:(nonnull NSData *)data {
[self.client URLProtocol:self didLoadData:data];
}
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain {
NSMutableArray *policies = [NSMutableArray array];
if (domain) {
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
} else {
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
}
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
SecTrustResultType result = kSecTrustResultInvalid;
OSStatus status = SecTrustEvaluate(serverTrust, &result);
if (status != errSecSuccess) {
return NO;
}
if (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed) {
return YES;
} else {
return NO;
}
}
- (void)onError:(nonnull NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
- (void)onReceiveResponse:(nonnull NSURLResponse *)response {
[self.client URLProtocol:self
didReceiveResponse:response
cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (void)redirectedToRequest:(nonnull NSURLRequest *)request redirectResponse:(nonnull NSURLResponse *)redirectResponse {
if ([self.client respondsToSelector:@selector(URLProtocol:wasRedirectedToRequest:redirectResponse:)]) {
[self.client URLProtocol:self wasRedirectedToRequest:request redirectResponse:redirectResponse];
[self.client URLProtocolDidFinishLoading:self];
} else {
[self.httpsClient stopLoading];
[self loadingRequest:request];
}
}
@end
@implementation NSURLSessionConfiguration(ZYJQNURLProtocol)
+ (NSURLSessionConfiguration *)ZYJQN_sessionConfiguration{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.protocolClasses = @[[ZYJQNURLProtocol class]];
return config;
}
@end
//
//
// ZYJQNUpToken.h
// ZYJQiniuSDK
//
// Created by bailong on 15/6/7.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYJQNUpToken : NSObject
+ (instancetype)parse:(NSString *)token;
@property (copy, nonatomic, readonly) NSString *access;
@property (copy, nonatomic, readonly) NSString *bucket;
@property (copy, nonatomic, readonly) NSString *token;
@property (readonly) BOOL hasReturnUrl;
- (NSString *)index;
@end
//
//
// ZYJQNUpToken.m
// ZYJQiniuSDK
//
// Created by bailong on 15/6/7.
// Copyright (c) 2015年 Qiniu. All rights reserved.
//
#import "ZYJQNUrlSafeBase64.h"
#import "ZYJQNUpToken.h"
@interface ZYJQNUpToken ()
- (instancetype)init:(NSDictionary *)policy token:(NSString *)token;
@end
@implementation ZYJQNUpToken
- (instancetype)init:(NSDictionary *)policy token:(NSString *)token {
if (self = [super init]) {
_token = token;
_access = [self getAccess];
_bucket = [self getBucket:policy];
_hasReturnUrl = (policy[@"returnUrl"] != nil);
}
return self;
}
- (NSString *)getAccess {
NSRange range = [_token rangeOfString:@":" options:NSCaseInsensitiveSearch];
return [_token substringToIndex:range.location];
}
- (NSString *)getBucket:(NSDictionary *)info {
NSString *scope = [info objectForKey:@"scope"];
if (!scope || [scope isKindOfClass:[NSNull class]]) {
return @"";
}
NSRange range = [scope rangeOfString:@":"];
if (range.location == NSNotFound) {
return scope;
}
return [scope substringToIndex:range.location];
}
+ (instancetype)parse:(NSString *)token {
if (token == nil) {
return nil;
}
NSArray *array = [token componentsSeparatedByString:@":"];
if (array == nil || array.count != 3) {
return nil;
}
NSData *data = [ZYJQNUrlSafeBase64 decodeString:array[2]];
if (!data) {
return nil;
}
NSError *tmp = nil;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&tmp];
if (tmp != nil || dict[@"scope"] == nil || dict[@"deadline"] == nil) {
return nil;
}
return [[ZYJQNUpToken alloc] init:dict token:token];
}
- (NSString *)index {
return [NSString stringWithFormat:@"%@:%@", _access, _bucket];
}
@end
//
//
// ZYJQNUploadInfoCollector.h
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2020/4/15.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#define Collector [ZYJQNUploadInfoCollector sharedInstance]
@class ZYJQNHttpResponseInfo;
@class ZYJQNResponseInfo;
// request types
typedef enum : NSUInteger {
ZYJQNRequestType_form,
ZYJQNRequestType_mkblk,
ZYJQNRequestType_bput,
ZYJQNRequestType_mkfile,
ZYJQNRequestType_put,
ZYJQNRequestType_initParts,
ZYJQNRequestType_uploadParts,
ZYJQNRequestType_completeParts,
ZYJQNRequestType_ucQuery,
ZYJQNRequestType_httpdnsQuery
} ZYJQNRequestType;
typedef NSString ZYJQNCollectKey;
// update key
extern ZYJQNCollectKey *const ZYJCK_bucket;
extern ZYJQNCollectKey *const ZYJCK_key;
extern ZYJQNCollectKey *const ZYJCK_targetRegionId;
extern ZYJQNCollectKey *const ZYJCK_currentRegionId;
extern ZYJQNCollectKey *const ZYJCK_result;
extern ZYJQNCollectKey *const ZYJCK_recoveredFrom;
extern ZYJQNCollectKey *const ZYJCK_fileSize;
extern ZYJQNCollectKey *const ZYJCK_blockApiVersion;
// append key
extern ZYJQNCollectKey *const ZYJCK_blockBytesSent;
extern ZYJQNCollectKey *const ZYJCK_totalBytesSent;
// Upload Result Type
extern NSString *const ZYJupload_ok; // 上传成功
extern NSString *const ZYJzero_size_file; // ⽂件⼤小错误
extern NSString *const ZYJinvalid_file; // 文件内容错误
extern NSString *const ZYJinvalid_args; // 调用参数出错
extern NSString *const ZYJlocal_io_error; // 本地 I/O 错误
/// Network Error Type
extern NSString *const ZYJunknown_error; // 未知错误
extern NSString *const ZYJnetwork_error; // 未知网络错误
extern NSString *const ZYJnetwork_timeout; // 超时错误
extern NSString *const ZYJunknown_host; // DNS 解析错误
extern NSString *const ZYJcannot_connect_to_host; // 连接服务器器错误
extern NSString *const ZYJtransmission_error; // 传输错误
extern NSString *const ZYJproxy_error; // 使用了 HTTP Proxy 且 Proxy 出错
extern NSString *const ZYJssl_error; // SSL 加密错误
extern NSString *const ZYJresponse_error; // 收到响应,但状态码非 200
extern NSString *const ZYJparse_error; // 解析响应错误
extern NSString *const ZYJmalicious_response; // 用户劫持错误
extern NSString *const ZYJuser_canceled; // 用户主动取消
extern NSString *const ZYJbad_request; // API 失败是由于客户端的参数错误导致,⽆法依靠重试来解决的(例如 4xx 错误, upload token 错误,⽬标 bucket 不存在,⽂件已经存在,区域不正确,额度不够 等)
extern NSString *const ZYJprotocol_error; // 协议错误
extern int64_t ZYJQN_IntNotSet;
// 用于统计上传质量 和生成ZYJQNResponseInfo实例
@interface ZYJQNUploadInfoCollector : NSObject
- (id)init __attribute__((unavailable("Use sharedInstance: instead.")));
+ (instancetype)sharedInstance;
/**
* 注册上传统计实例
*
* @param identifier 此次上传的唯一标识
* @param token 上传token
*
*/
- (void)registerWithIdentifier:(NSString *)identifier token:(NSString *)token;
/**
* 更新ZYJQNCollectKey对应的上传信息
*
* @param key 需要更新的ZYJQNCollectKey
* @param identifier 此次上传的唯一标识
*
*/
- (void)update:(ZYJQNCollectKey *)key value:(id)value identifier:(NSString *)identifier;
/**
* 拼接ZYJQNCollectKey对应的上传信息 一般用于拼接数字类型常量
*
* @param key 需要拼接的ZYJQNCollectKey
* @param identifier 此次上传的唯一标识
*
*/
- (void)append:(ZYJQNCollectKey *)key value:(id)value identifier:(NSString *)identifier;
/**
* 记录此次上传中单次http请求结果
*
* @param upType 请求类型
* @param httpResponseInfo 请求返回信息
* @param fileOffset data偏移量(非分片上传请求时该值为0)
* @param targetRegionId 目标区域id
* @param currentRegionId 当前区域id
* @param identifier 此次上传的唯一标识
*
*/
- (void)addRequestWithType:(ZYJQNRequestType)upType httpResponseInfo:(ZYJQNHttpResponseInfo *)httpResponseInfo fileOffset:(int64_t)fileOffset targetRegionId:(NSString *)targetRegionId currentRegionId:(NSString *)currentRegionId identifier:(NSString *)identifier;
/**
* 根据http请求结果返回ZYJQNResponseInfo
*
* @param lastHttpResponseInfo 最后一个请求的返回信息
* @param identifier 此次上传的唯一标识
*
* @return ZYJQNResponseInfo 返回信息
*/
- (ZYJQNResponseInfo *)completeWithHttpResponseInfo:(ZYJQNHttpResponseInfo *)lastHttpResponseInfo identifier:(NSString *)identifier;
/**
* 参数问题导致上传结束并返回ZYJQNResponseInfo
*
* @param text 描述
* @param identifier 此次上传的唯一标识
*
* @return ZYJQNResponseInfo 返回信息
*/
- (ZYJQNResponseInfo *)completeWithInvalidArgument:(NSString *)text identifier:(NSString *)identifier;
/**
* token无效导致上传结束并返回ZYJQNResponseInfo
*
* @param text 描述
* @param identifier 此次上传的唯一标识
*
* @return ZYJQNResponseInfo 返回信息
*/
- (ZYJQNResponseInfo *)completeWithInvalidToken:(NSString *)text identifier:(NSString *)identifier;
/**
* 文件内容出错导致上传结束并返回ZYJQNResponseInfo
*
* @param error 报错信息
* @param identifier 此次上传的唯一标识
*
* @return ZYJQNResponseInfo 返回信息
*/
- (ZYJQNResponseInfo *)completeWithFileError:(NSError *)error identifier:(NSString *)identifier;
/**
* 本地 I/O 出错导致上传结束并返回ZYJQNResponseInfo
*
* @param error 报错信息
* @param identifier 此次上传的唯一标识
*
* @return ZYJQNResponseInfo 返回信息
*/
- (ZYJQNResponseInfo *)completeWithLocalIOError:(NSError *)error identifier:(NSString *)identifier;
/**
* zero data问题导致上传结束并返回ZYJQNResponseInfo
*
* @param path 文件路径
* @param identifier 此次上传的唯一标识
*
* @return ZYJQNResponseInfo 返回信息
*/
- (ZYJQNResponseInfo *)completeWithZeroData:(NSString *)path identifier:(NSString *)identifier;
/**
* 用户取消导致上传结束并返回ZYJQNResponseInfo
*
* @param identifier 此次上传的唯一标识
*
* @return ZYJQNResponseInfo 返回信息
*/
- (ZYJQNResponseInfo *)userCancel:(NSString *)identifier;
@end
//
//
// ZYJQNUploadInfoCollector.m
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2020/4/15.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNUploadInfoCollector.h"
#import "ZYJQNUploadInfoReporter.h"
#import "ZYJQNHttpResponseInfo.h"
#import "ZYJQNResponseInfo.h"
ZYJQNCollectKey *const ZYJCK_bucket = @"bucket";
ZYJQNCollectKey *const ZYJCK_key = @"key";
ZYJQNCollectKey *const ZYJCK_targetRegionId = @"targetRegionId";
ZYJQNCollectKey *const ZYJCK_currentRegionId = @"currentRegionId";
ZYJQNCollectKey *const ZYJCK_result = @"result";
ZYJQNCollectKey *const ZYJCK_blockBytesSent = @"blockBytesSent";
ZYJQNCollectKey *const ZYJCK_recoveredFrom = @"recoveredFrom";
ZYJQNCollectKey *const ZYJCK_totalBytesSent = @"totalBytesSent";
ZYJQNCollectKey *const ZYJCK_fileSize = @"fileSize";
ZYJQNCollectKey *const ZYJCK_blockApiVersion = @"blockApiVersion";
int64_t ZYJQN_IntNotSet = -11111111;
// Upload Result Type
NSString *const ZYJupload_ok = @"ok";
NSString *const ZYJzero_size_file = @"ZYJzero_size_file";
NSString *const ZYJinvalid_file = @"ZYJinvalid_file";
NSString *const ZYJinvalid_args = @"ZYJinvalid_args";
NSString *const ZYJlocal_io_error = @"ZYJlocal_io_error";
// Network Error Type
NSString *const ZYJunknown_error = @"ZYJunknown_error";
NSString *const ZYJnetwork_error = @"ZYJnetwork_error";
NSString *const ZYJnetwork_timeout = @"timeout";
NSString *const ZYJunknown_host = @"ZYJunknown_host";
NSString *const ZYJcannot_connect_to_host = @"ZYJcannot_connect_to_host";
NSString *const ZYJtransmission_error = @"ZYJtransmission_error";
NSString *const ZYJproxy_error = @"ZYJproxy_error";
NSString *const ZYJssl_error = @"ZYJssl_error";
NSString *const ZYJresponse_error = @"ZYJresponse_error";
NSString *const ZYJparse_error = @"ZYJparse_error";
NSString *const ZYJmalicious_response = @"ZYJmalicious_response";
NSString *const ZYJuser_canceled = @"ZYJuser_canceled";
NSString *const ZYJbad_request = @"ZYJbad_request";
NSString *const ZYJprotocol_error = @"ZYJprotocol_error";
static NSString *const ZYJrequestTypes[] = {@"form", @"mkblk", @"bput", @"mkfile", @"put", @"init_parts", @"upload_part", @"complete_part", @"uc_query", @"httpdns_query"};
@interface ZYJQNCollectItem : NSObject
@property (nonatomic, copy) NSString *identifier;
@property (nonatomic, copy) NSString *bucket;
@property (nonatomic, copy) NSString *key;
@property (nonatomic, copy) NSString *token;
@property (nonatomic, copy) NSString *targetRegionId;
@property (nonatomic, copy) NSString *currentRegionId;
@property (nonatomic, copy) NSString *result;
@property (nonatomic, assign) int64_t uploadStartTime;
@property (nonatomic, assign) int64_t uploadEndTime;
@property (nonatomic, assign) int64_t totalBytesSent;
@property (nonatomic, assign) int64_t fileSize;
@property (nonatomic, assign) int64_t recoveredFrom;
@property (nonatomic, assign) int64_t blockApiVersion;
@property (nonatomic, assign) int64_t blockBytesSent;
@property (nonatomic, strong) NSMutableArray<ZYJQNHttpResponseInfo *> *httpRequestList;
@end
@implementation ZYJQNCollectItem
- (instancetype)initWithIdentifier:(NSString *)identifier token:(NSString *)token
{
self = [super init];
if (self) {
_identifier = identifier;
_token = token;
_uploadStartTime = ZYJQN_IntNotSet;
_uploadEndTime = ZYJQN_IntNotSet;
_fileSize = ZYJQN_IntNotSet;
_recoveredFrom = ZYJQN_IntNotSet;
_blockApiVersion = ZYJQN_IntNotSet;
_totalBytesSent = 0;
_blockBytesSent = 0;
_httpRequestList = [NSMutableArray array];
}
return self;
}
@end
@interface ZYJQNUploadInfoCollector ()
@property (nonatomic, strong) NSArray<ZYJQNCollectKey *> *updateKeysList;
@property (nonatomic, strong) NSArray <ZYJQNCollectKey *>*appendKeysList;
@property (nonatomic, strong) NSMutableArray<ZYJQNCollectItem *> *collectItemList;
@property (nonatomic, strong) dispatch_queue_t collectQueue;
@end
@implementation ZYJQNUploadInfoCollector
+ (instancetype)sharedInstance {
static ZYJQNUploadInfoCollector *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
sharedInstance.collectItemList = [NSMutableArray array];
sharedInstance.collectQueue = dispatch_queue_create("com.qiniu.collector", DISPATCH_QUEUE_SERIAL);
sharedInstance.updateKeysList = @[
ZYJCK_bucket,
ZYJCK_key,
ZYJCK_targetRegionId,
ZYJCK_currentRegionId,
ZYJCK_result,
ZYJCK_recoveredFrom,
ZYJCK_fileSize,
ZYJCK_blockApiVersion];
sharedInstance.appendKeysList = @[
ZYJCK_blockBytesSent,
ZYJCK_totalBytesSent];
});
return sharedInstance;
}
- (void)registerWithIdentifier:(NSString *)identifier token:(NSString *)token {
if (!identifier || !token) return;
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *item = [[ZYJQNCollectItem alloc] initWithIdentifier:identifier token:token];
item.uploadStartTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970] * 1000;
[self.collectItemList addObject:item];
});
}
- (void)update:(ZYJQNCollectKey *)key value:(id)value identifier:(NSString *)identifier {
if (!identifier || !key || ![self.updateKeysList containsObject:key]) return;
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
if (currentItem) {
[currentItem setValue:value forKey:key];
}
});
}
- (void)append:(ZYJQNCollectKey *)key value:(id)value identifier:(NSString *)identifier {
if (!identifier || !key || ![self.appendKeysList containsObject:key]) return;
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
if (currentItem) {
// append NSNumber value
NSNumber *formalValue = [currentItem valueForKey:key];
NSNumber *appendValue = (NSNumber *)value;
int64_t newValue = formalValue.longValue + appendValue.longValue;
[currentItem setValue:@(newValue) forKey:key];
}
});
}
- (void)addRequestWithType:(ZYJQNRequestType)upType httpResponseInfo:(ZYJQNHttpResponseInfo *)httpResponseInfo fileOffset:(int64_t)fileOffset targetRegionId:(NSString *)targetRegionId currentRegionId:(NSString *)currentRegionId identifier:(NSString *)identifier {
if (!identifier || !httpResponseInfo) return;
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
if (currentItem) {
[currentItem.httpRequestList addObject:httpResponseInfo];
if ([ZYJQNReportConfig sharedInstance].isReportEnable) {
// 分块上传bytesSent字段有误差 这里分开处理
int64_t bytesSent;
if (upType == ZYJQNRequestType_mkblk || upType == ZYJQNRequestType_bput) {
if (httpResponseInfo.hasHttpResponse) {
bytesSent = httpResponseInfo.bytesTotal;
} else {
bytesSent = 0;
}
} else {
bytesSent = httpResponseInfo.bytesSent;
}
ZYJQNReportRequestItem *item = [ZYJQNReportRequestItem buildWithUpType:ZYJrequestTypes[upType]
TargetBucket:currentItem.bucket
targetKey:currentItem.key
fileOffset:fileOffset
targetRegionId:targetRegionId
currentRegionId:currentRegionId
prefetchedIpCount:ZYJQN_IntNotSet
pid:httpResponseInfo.pid
tid:httpResponseInfo.tid
statusCode:httpResponseInfo.statusCode
reqId:httpResponseInfo.reqId
host:httpResponseInfo.host
remoteIp:httpResponseInfo.remoteIp
port:httpResponseInfo.port totalElapsedTime:httpResponseInfo.totalElapsedTime dnsElapsedTime:httpResponseInfo.dnsElapsedTime connectElapsedTime:httpResponseInfo.connectElapsedTime tlsConnectElapsedTime:httpResponseInfo.tlsConnectElapsedTime requestElapsedTime:httpResponseInfo.requestElapsedTime waitElapsedTime:httpResponseInfo.waitElapsedTime responseElapsedTime:httpResponseInfo.responseElapsedTime bytesSent:bytesSent bytesTotal:httpResponseInfo.bytesTotal errorType:httpResponseInfo.errorType errorDescription:httpResponseInfo.errorDescription networkType:httpResponseInfo.networkType signalStrength:httpResponseInfo.signalStrength];
[Reporter report:[item toJson] token:currentItem.token];
}
}
});
}
- (ZYJQNResponseInfo *)completeWithHttpResponseInfo:(ZYJQNHttpResponseInfo *)lastHttpResponseInfo identifier:(NSString *)identifier {
__block ZYJQNResponseInfo *info;
dispatch_semaphore_t signal = dispatch_semaphore_create(0);
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
if (lastHttpResponseInfo.isOK) {
currentItem.result = ZYJupload_ok;
} else {
currentItem.result = lastHttpResponseInfo.errorType;
}
currentItem.uploadEndTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970] * 1000;
info = [ZYJQNResponseInfo responseInfoWithHttpResponseInfo:lastHttpResponseInfo duration:(currentItem.uploadEndTime - currentItem.uploadStartTime) / 1000.0];
dispatch_semaphore_signal(signal);
if ([ZYJQNReportConfig sharedInstance].isReportEnable) [self reportResult:currentItem];
[self.collectItemList removeObject:currentItem];
});
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
return info;
}
- (ZYJQNResponseInfo *)completeWithInvalidArgument:(NSString *)text identifier:(NSString *)identifier {
__block ZYJQNResponseInfo *info;
dispatch_semaphore_t signal = dispatch_semaphore_create(0);
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
currentItem.result = ZYJinvalid_args;
currentItem.uploadEndTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970] * 1000;
info = [ZYJQNResponseInfo responseInfoWithInvalidArgument:text duration:(currentItem.uploadEndTime - currentItem.uploadStartTime) / 1000.0];
dispatch_semaphore_signal(signal);
if ([ZYJQNReportConfig sharedInstance].isReportEnable) [self reportResult:currentItem];
[self.collectItemList removeObject:currentItem];
});
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
return info;
}
- (ZYJQNResponseInfo *)completeWithInvalidToken:(NSString *)text identifier:(NSString *)identifier {
__block ZYJQNResponseInfo *info;
dispatch_semaphore_t signal = dispatch_semaphore_create(0);
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
currentItem.result = ZYJinvalid_args;
currentItem.uploadEndTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970] * 1000;
info = [ZYJQNResponseInfo responseInfoWithInvalidToken:text duration:(currentItem.uploadEndTime - currentItem.uploadStartTime) / 1000.0];
dispatch_semaphore_signal(signal);
if ([ZYJQNReportConfig sharedInstance].isReportEnable) [self reportResult:currentItem];
[self.collectItemList removeObject:currentItem];
});
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
return info;
}
- (ZYJQNResponseInfo *)completeWithFileError:(NSError *)error identifier:(NSString *)identifier {
__block ZYJQNResponseInfo *info;
dispatch_semaphore_t signal = dispatch_semaphore_create(0);
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
currentItem.result = ZYJinvalid_file;
currentItem.uploadEndTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970] * 1000;
info = [ZYJQNResponseInfo responseInfoWithFileError:error duration:(currentItem.uploadEndTime - currentItem.uploadStartTime) / 1000.0];
dispatch_semaphore_signal(signal);
if ([ZYJQNReportConfig sharedInstance].isReportEnable) [self reportResult:currentItem];
[self.collectItemList removeObject:currentItem];
});
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
return info;
}
- (ZYJQNResponseInfo *)completeWithLocalIOError:(NSError *)error identifier:(NSString *)identifier {
__block ZYJQNResponseInfo *info;
dispatch_semaphore_t signal = dispatch_semaphore_create(0);
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
currentItem.result = ZYJlocal_io_error;
currentItem.uploadEndTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970] * 1000;
info = [ZYJQNResponseInfo responseInfoWithFileError:error duration:(currentItem.uploadEndTime - currentItem.uploadStartTime) / 1000.0];
dispatch_semaphore_signal(signal);
if ([ZYJQNReportConfig sharedInstance].isReportEnable) [self reportResult:currentItem];
[self.collectItemList removeObject:currentItem];
});
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
return info;
}
- (ZYJQNResponseInfo *)completeWithZeroData:(NSString *)path identifier:(NSString *)identifier {
__block ZYJQNResponseInfo *info;
dispatch_semaphore_t signal = dispatch_semaphore_create(0);
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
currentItem.result = ZYJzero_size_file;
currentItem.uploadEndTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970] * 1000;
info = [ZYJQNResponseInfo responseInfoOfZeroData:path duration:(currentItem.uploadEndTime - currentItem.uploadStartTime) / 1000.0];
dispatch_semaphore_signal(signal);
if ([ZYJQNReportConfig sharedInstance].isReportEnable) [self reportResult:currentItem];
[self.collectItemList removeObject:currentItem];
});
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
return info;
}
- (ZYJQNResponseInfo *)userCancel:(NSString *)identifier {
__block ZYJQNResponseInfo *info;
dispatch_semaphore_t signal = dispatch_semaphore_create(0);
dispatch_async(_collectQueue, ^{
ZYJQNCollectItem *currentItem = [self getCurrentItemWithIdentifier:identifier];
currentItem.result = ZYJuser_canceled;
currentItem.uploadEndTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970] * 1000;
info = [ZYJQNResponseInfo cancelWithDuration:(currentItem.uploadEndTime - currentItem.uploadStartTime) / 1000.0];
dispatch_semaphore_signal(signal);
if ([ZYJQNReportConfig sharedInstance].isReportEnable) [self reportResult:currentItem];
[self.collectItemList removeObject:currentItem];
});
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
return info;
}
- (void)reportResult:(ZYJQNCollectItem *)currentItem {
int64_t regionsCount = !currentItem.targetRegionId || !currentItem.currentRegionId || [currentItem.targetRegionId isEqualToString:currentItem.currentRegionId] ? 1 : 2;
int64_t totalElapsedTime = currentItem.uploadEndTime - currentItem.uploadStartTime;
if (currentItem.blockApiVersion != ZYJQN_IntNotSet) {
ZYJQNReportBlockItem *item = [ZYJQNReportBlockItem buildWithTargetRegionId:currentItem.targetRegionId currentRegionId:currentItem.currentRegionId totalElapsedTime:totalElapsedTime bytesSent:currentItem.blockBytesSent recoveredFrom:currentItem.recoveredFrom fileSize:currentItem.fileSize pid:ZYJQN_IntNotSet tid:ZYJQN_IntNotSet upApiVersion:currentItem.blockApiVersion];
[Reporter report:[item toJson] token:currentItem.token];
}
ZYJQNReportQualityItem *item = [ZYJQNReportQualityItem buildWithResult:currentItem.result totalElapsedTime:totalElapsedTime requestsCount:currentItem.httpRequestList.count regionsCount:regionsCount bytesSent:currentItem.totalBytesSent];
[Reporter report:[item toJson] token:currentItem.token];
}
- (ZYJQNCollectItem *)getCurrentItemWithIdentifier:(NSString *)identifier {
ZYJQNCollectItem *item = nil;
for (NSInteger i = 0; i < self.collectItemList.count; i++) {
ZYJQNCollectItem *currentItem = self.collectItemList[i];
if ([currentItem.identifier isEqualToString:identifier]) {
item = currentItem;
break;
}
}
return item;
}
@end
//
//
// ZYJQNUploadInfoReporter.h
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2019/6/24.
// Copyright © 2019 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#import <UIKit/UIKit.h>
#endif
@class ZYJQNResponseInfo;
// base item
@interface ZYJQNReportBaseItem : NSObject
- (NSString *)toJson; // get json with report item
@end
// request type item - 用于统计单个请求的打点信息
@interface ZYJQNReportRequestItem : ZYJQNReportBaseItem
+ (instancetype)buildWithUpType:(NSString *)up_type
TargetBucket:(NSString *)target_bucket
targetKey:(NSString *)target_key
fileOffset:(int64_t)file_offset
targetRegionId:(NSString *)target_region_id
currentRegionId:(NSString *)current_region_id
prefetchedIpCount:(int64_t)prefetched_ip_count
pid:(int64_t)pid
tid:(int64_t)tid
statusCode:(int64_t)status_code
reqId:(NSString *)req_id
host:(NSString *)host
remoteIp:(NSString *)remote_ip
port:(int64_t)port
totalElapsedTime:(int64_t)total_elapsed_time
dnsElapsedTime:(int64_t)dns_elapsed_time
connectElapsedTime:(int64_t)connect_elapsed_time
tlsConnectElapsedTime:(int64_t)tls_connect_elapsed_time
requestElapsedTime:(int64_t)request_elapsed_time
waitElapsedTime:(int64_t)wait_elapsed_time
responseElapsedTime:(int64_t)response_elapsed_time
bytesSent:(int64_t)bytes_sent
bytesTotal:(int64_t)bytes_total
errorType:(NSString *)error_type
errorDescription:(NSString *)error_description
networkType:(NSString *)network_type
signalStrength:(int64_t)signal_strength;
@end
// block type item - 用于统计分片上传整体质量信息
@interface ZYJQNReportBlockItem : ZYJQNReportBaseItem
+ (instancetype)buildWithTargetRegionId:(NSString *)target_region_id
currentRegionId:(NSString *)current_region_id
totalElapsedTime:(int64_t)total_elapsed_time
bytesSent:(int64_t)bytes_sent
recoveredFrom:(int64_t)recovered_from
fileSize:(int64_t)file_size
pid:(int64_t)pid
tid:(int64_t)tid
upApiVersion:(int64_t)up_api_version;
@end
// quality type item - 用于统计上传结果
@interface ZYJQNReportQualityItem : ZYJQNReportBaseItem
+ (instancetype)buildWithResult:(NSString *)result
totalElapsedTime:(int64_t)total_elapsed_time
requestsCount:(int64_t)requests_count
regionsCount:(int64_t)regions_count
bytesSent:(int64_t)bytes_sent;
@end
@interface ZYJQNReportConfig : NSObject
- (id)init __attribute__((unavailable("Use sharedInstance: instead.")));
+ (instancetype)sharedInstance;
/**
* 是否开启sdk上传信息搜集 默认为YES
*/
@property (nonatomic, assign, getter=isReportEnable) BOOL reportEnable;
/**
* 每次上传最小时间间隔 单位:分钟 默认为10分钟
*/
@property (nonatomic, assign) uint32_t interval;
/**
* 记录文件大于 uploadThreshold 后才可能触发上传,单位:字节 默认为4 * 1024
*/
@property (nonatomic, assign) uint64_t uploadThreshold;
/**
* 记录文件最大值 要大于 uploadThreshold 单位:字节 默认为2 * 1024 * 1024
*/
@property (nonatomic, assign) uint64_t maxRecordFileSize;
/**
* 记录文件所在文件夹目录 默认为:.../沙盒/Library/Caches/com.qiniu.report
*/
@property (nonatomic, copy) NSString *recordDirectory;
/**
* 信息上报服务器地址
*/
@property (nonatomic, copy, readonly) NSString *serverURL;
/**
* 信息上报请求超时时间 单位:秒 默认为10秒
*/
@property (nonatomic, assign, readonly) NSTimeInterval timeoutInterval;
@end
#define Reporter [ZYJQNUploadInfoReporter sharedInstance]
@interface ZYJQNUploadInfoReporter : NSObject
@property (nonatomic, copy, readonly) NSString *X_Log_Client_Id;
- (id)init __attribute__((unavailable("Use sharedInstance: instead.")));
+ (instancetype)sharedInstance;
/**
* 上报统计信息
*
* @param jsonString 需要记录的json字符串
* @param token 上传凭证
*
*/
- (void)report:(NSString *)jsonString token:(NSString *)token;
/**
* 清空统计信息
*/
- (void)clean;
@end
//
//
// ZYJQNUploadInfoReporter.m
// ZYJQiniuSDK
//
// Created by WorkSpace_Sun on 2019/6/24.
// Copyright © 2019 Qiniu. All rights reserved.
//
#import "ZYJQNUploadInfoReporter.h"
#import "ZYJQNUploadInfoCollector.h"
#import "ZYJQNResponseInfo.h"
#import "ZYJQNFile.h"
#import "ZYJQNUpToken.h"
#import "ZYJQNUserAgent.h"
#import "ZYJQNAsyncRun.h"
#import "ZYJQNSystemTool.h"
#import "ZYJQNVersion.h"
#import <objc/runtime.h>
@interface ZYJQNReportBaseItem ()
// 打点类型 request、block、quality
@property (nonatomic, copy) NSString *log_type;
// 客户端时间戳
@property (nonatomic, assign) int64_t up_time;
@end
@implementation ZYJQNReportBaseItem
- (instancetype)init
{
self = [super init];
if (self) {
self.up_time = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970];
}
return self;
}
- (NSString *)toJson {
NSMutableDictionary *itemDic = [NSMutableDictionary dictionary];
// self class property
unsigned int selfPropertyCount = 0;
objc_property_t *selfProperties = class_copyPropertyList([self class], &selfPropertyCount);
for (unsigned int i = 0; i < selfPropertyCount; i ++) {
objc_property_t property = selfProperties[i];
const char *name = property_getName(property);
unsigned int attrCount = 0;
objc_property_attribute_t * attrs = property_copyAttributeList(property, &attrCount);
for (unsigned int j = 0; j < attrCount; j ++) {
objc_property_attribute_t attr = attrs[j];
const char *attrName = attr.name;
if (0 == strcmp(attrName, "T")) {
const char *value = attr.value;
if (0 == strcmp(value, "@\"NSString\"")) {
NSString *key = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
NSString *ivarValue = [self valueForKey:key];
if (ivarValue) [itemDic setValue:ivarValue forKey:key];
} else {
// 默认其他属性的基本类型是int
NSString *key = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
NSNumber *ivarValue = [self valueForKey:key];
if (ivarValue && ![ivarValue isEqualToNumber:@(ZYJQN_IntNotSet)]) [itemDic setValue:ivarValue forKey:key];
}
}
}
free(attrs);
}
free(selfProperties);
// super class property
unsigned int superPropertyCount = 0;
objc_property_t *superProperties = class_copyPropertyList([self superclass], &superPropertyCount);
for (unsigned int i = 0; i < superPropertyCount; i ++) {
objc_property_t property = superProperties[i];
const char *name = property_getName(property);
unsigned int attrCount = 0;
objc_property_attribute_t * attrs = property_copyAttributeList(property, &attrCount);
for (unsigned int j = 0; j < attrCount; j ++) {
objc_property_attribute_t attr = attrs[j];
const char *attrName = attr.name;
if (0 == strcmp(attrName, "T")) {
const char *value = attr.value;
if (0 == strcmp(value, "@\"NSString\"")) {
NSString *key = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
NSString *ivarValue = [self valueForKey:key];
if (ivarValue) [itemDic setValue:ivarValue forKey:key];
} else {
// 默认其他属性的基本类型是int
NSString *key = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
NSNumber *ivarValue = [self valueForKey:key];
if (ivarValue) [itemDic setValue:ivarValue forKey:key];
}
}
}
free(attrs);
}
free(superProperties);
NSError *error;
NSData *itemData = [NSJSONSerialization dataWithJSONObject:itemDic options:kNilOptions error:&error];
if (error) return nil;
NSString *itemJson = [[NSString alloc] initWithData:itemData encoding:NSUTF8StringEncoding];
return itemJson;
}
@end
@interface ZYJQNReportRequestItem ()
// API 请求类型,可选值有 "form","mkblk","bput","mkfile","put","init_parts","upload_part","complete_part","uc_query","httpdns_query"
@property (nonatomic, copy) NSString *up_type;
// 记录⽬标 Bucket 名称
@property (nonatomic, copy) NSString *target_bucket;
// 记录⽬标 Key 名称
@property (nonatomic, copy) NSString *target_key;
// 本次分片上传的偏移量,单位为字节
@property (nonatomic, assign) int64_t file_offset;
// ⽬标上传的区域 ID,可选值为 "z0","z1","z2","as0","na0" 等
@property (nonatomic, copy) NSString *target_region_id;
// 当前上传的区域 ID,可选值为 "z0","z1","z2","as0","na0" 等
@property (nonatomic, copy) NSString *current_region_id;
// 该域名通过预取 DNS 得到的 IP 地址数量(目前是0)
@property (nonatomic, assign) int64_t prefetched_ip_count;
// 当前进程 ID
@property (nonatomic, assign) int64_t pid;
// 当前线程 ID
@property (nonatomic, assign) int64_t tid;
// 当前平台的操作系统名称
@property (nonatomic, copy) NSString *os_name;
// 当前平台的操作系统版本号
@property (nonatomic, copy) NSString *os_version;
// 当前 SDK 名称,默认Object-C
@property (nonatomic, copy) NSString *sdk_name;
// 当前 SDK 版本号
@property (nonatomic, copy) NSString *sdk_version;
// 记录响应状态码
@property (nonatomic, assign) int64_t status_code;
// 记录响应中存储的 ReqId
@property (nonatomic, copy) NSString *req_id;
// 记录主机域名(不含解析,不含端⼝)
@property (nonatomic, copy) NSString *host;
// 记录成功建⽴连接的服务器 IP 地址
@property (nonatomic, copy) NSString *remote_ip;
// 记录主机端口号
@property (nonatomic, assign) int64_t port;
// 记录从发送请求到收到响应之间的单调时间差,单位为毫秒
@property (nonatomic, assign) int64_t total_elapsed_time;
// 记录⼀次请求中 DNS 查询的耗时,单位为毫秒,如果当前请求不需要进⾏ DNS 查询,则填写 0
@property (nonatomic, assign) int64_t dns_elapsed_time;
// 记录一次请求中建立⽹络连接的耗时,单位为毫秒,如果当前请求不不需要进行⽹络连接,则填写 0
@property (nonatomic, assign) int64_t connect_elapsed_time;
// 记录一次请求中建立安全⽹络连接的耗时,单位为毫秒(该耗时被 connect_elapsed_time 包含,因此总是⼩小于或等于 connect_elapsed_time,如果当前请求不需要进行安全连接,则填写 0)
@property (nonatomic, assign) int64_t tls_connect_elapsed_time;
// 记录⼀次请求中发送请求的耗时,单位为毫秒
@property (nonatomic, assign) int64_t request_elapsed_time;
// 记录⼀次请求中从发送请求完毕到收到响应前的耗时,单位为毫秒
@property (nonatomic, assign) int64_t wait_elapsed_time;
// 记录⼀次请求中读取响应的耗时,单位为毫秒
@property (nonatomic, assign) int64_t response_elapsed_time;
// 本次成功发送请求的请求体大小,单位为字节
@property (nonatomic, assign) int64_t bytes_sent;
// 预期发送请求的请求体大小,单位为字节
@property (nonatomic, assign) int64_t bytes_total;
// 错误类型
@property (nonatomic, copy) NSString *error_type;
// 对于服务器器成功响应,且响应体中包含 error 字段的,则给出 error 字段的内容。否则对于其他错误,则可以⾃自定义错误描述 信息
@property (nonatomic, copy) NSString *error_description;
// 请求结束时的⽹网络类型,可选值有 "wifi", "2g", "3g", "4g" 等。如果当前⽹网络不不可⽤用,则给出 "none"
@property (nonatomic, copy) NSString *network_type;
// 请求结束时的信号强度
@property (nonatomic, assign) int64_t signal_strength;
@end
@implementation ZYJQNReportRequestItem
- (instancetype)init
{
self = [super init];
if (self) {
self.log_type = @"request";
}
return self;
}
+ (instancetype)buildWithUpType:(NSString *)up_type
TargetBucket:(NSString *)target_bucket
targetKey:(NSString *)target_key
fileOffset:(int64_t)file_offset
targetRegionId:(NSString *)target_region_id
currentRegionId:(NSString *)current_region_id
prefetchedIpCount:(int64_t)prefetched_ip_count
pid:(int64_t)pid
tid:(int64_t)tid
statusCode:(int64_t)status_code
reqId:(NSString *)req_id
host:(NSString *)host
remoteIp:(NSString *)remote_ip
port:(int64_t)port
totalElapsedTime:(int64_t)total_elapsed_time
dnsElapsedTime:(int64_t)dns_elapsed_time
connectElapsedTime:(int64_t)connect_elapsed_time
tlsConnectElapsedTime:(int64_t)tls_connect_elapsed_time
requestElapsedTime:(int64_t)request_elapsed_time
waitElapsedTime:(int64_t)wait_elapsed_time
responseElapsedTime:(int64_t)response_elapsed_time
bytesSent:(int64_t)bytes_sent
bytesTotal:(int64_t)bytes_total
errorType:(NSString *)error_type
errorDescription:(NSString *)error_description
networkType:(NSString *)network_type
signalStrength:(int64_t)signal_strength {
ZYJQNReportRequestItem *item = [[ZYJQNReportRequestItem alloc] init];
item.up_type = up_type;
item.target_bucket = target_bucket;
item.target_key = target_key;
item.file_offset = file_offset;
item.target_region_id = target_region_id;
item.current_region_id = current_region_id;
item.prefetched_ip_count = prefetched_ip_count;
item.pid = pid;
item.tid = tid;
item.status_code = status_code;
item.req_id = req_id;
item.host = host;
item.remote_ip = remote_ip;
item.port = port;
item.total_elapsed_time = total_elapsed_time;
item.dns_elapsed_time = dns_elapsed_time;
item.connect_elapsed_time = connect_elapsed_time;
item.tls_connect_elapsed_time = tls_connect_elapsed_time;
item.request_elapsed_time = request_elapsed_time;
item.wait_elapsed_time = wait_elapsed_time;
item.response_elapsed_time = response_elapsed_time;
item.bytes_sent = bytes_sent;
item.bytes_total = bytes_total;
item.error_type = error_type;
item.error_description = error_description;
item.network_type = network_type;
item.signal_strength = signal_strength;
#if __IPHONE_OS_VERSION_MIN_REQUIRED
item.os_name = [[UIDevice currentDevice] model];
item.os_version = [[UIDevice currentDevice] systemVersion];
#else
item.os_name = @"Mac OS X";
item.os_version = [[NSProcessInfo processInfo] operatingSystemVersionString];
#endif
item.sdk_name = @"Object-C";
item.sdk_version = kQiniuVersion;
return item;
}
@end
// block type item - 用于统计分片上传整体质量信息
@interface ZYJQNReportBlockItem ()
// ⽬标上传的区域 ID,可选值为 "z0","z1","z2","as0","na0"
@property (nonatomic, copy) NSString *target_region_id;
// 当前上传的区域 ID,可选值为 "z0","z1","z2","as0","na0"
@property (nonatomic, copy) NSString *current_region_id;
// 记录对于当前上传的区域,从发送第一个请求到收到最后一个响应 之间的单调时间差,单位为毫秒
@property (nonatomic, assign) int64_t total_elapsed_time;
// 成功上传⾄服务器的分块尺寸总和,单位为字节
@property (nonatomic, assign) int64_t bytes_sent;
// 上次失败时已上传的文件尺⼨(也就是上传恢复点),单位为字节
@property (nonatomic, assign) int64_t recovered_from;
// 要上传的文件总尺寸,单位为字节
@property (nonatomic, assign) int64_t file_size;
// 当前进程 ID
@property (nonatomic, assign) int64_t pid;
// 当前线程 ID
@property (nonatomic, assign) int64_t tid;
// 分⽚上传 API 版本,可选值为 1 和 2
@property (nonatomic, assign) int64_t up_api_version;
@end
@implementation ZYJQNReportBlockItem
- (instancetype)init
{
self = [super init];
if (self) {
self.log_type = @"block";
}
return self;
}
+ (instancetype)buildWithTargetRegionId:(NSString *)target_region_id
currentRegionId:(NSString *)current_region_id
totalElapsedTime:(int64_t)total_elapsed_time
bytesSent:(int64_t)bytes_sent
recoveredFrom:(int64_t)recovered_from
fileSize:(int64_t)file_size
pid:(int64_t)pid
tid:(int64_t)tid
upApiVersion:(int64_t)up_api_version {
ZYJQNReportBlockItem *item = [[ZYJQNReportBlockItem alloc] init];
item.target_region_id = target_region_id;
item.current_region_id = current_region_id;
item.total_elapsed_time = total_elapsed_time;
item.bytes_sent = bytes_sent;
item.recovered_from = recovered_from;
item.file_size = file_size;
item.pid = pid;
item.tid = tid;
item.up_api_version = up_api_version;
return item;
}
@end
// quality type item - 用于统计上传结果
@interface ZYJQNReportQualityItem ()
// 记录上传结果
@property (nonatomic, copy) NSString *result;
// 记录对于当前上传的⽂文件,从发送第⼀个请求到收到最后⼀个响应之间的单调时间差,单位为毫秒
@property (nonatomic, assign) int64_t total_elapsed_time;
// 为了完成本次上传所发出的 HTTP 请求总数(含 UC Query 和 HTTPDNS Query)
@property (nonatomic, assign) int64_t requests_count;
// 为了完成本次上传所使用的区域数量
@property (nonatomic, assign) int64_t regions_count;
// 为了完成本次上传所发出的 HTTP 请求体尺寸总量(含 UC Query 和 HTTPDNS Query)
@property (nonatomic, assign) int64_t bytes_sent;
@end
@implementation ZYJQNReportQualityItem
- (instancetype)init
{
self = [super init];
if (self) {
self.log_type = @"quality";
}
return self;
}
+ (instancetype)buildWithResult:(NSString *)result
totalElapsedTime:(int64_t)total_elapsed_time
requestsCount:(int64_t)requests_count
regionsCount:(int64_t)regions_count
bytesSent:(int64_t)bytes_sent {
ZYJQNReportQualityItem *item = [[ZYJQNReportQualityItem alloc] init];
item.result = result;
item.total_elapsed_time = total_elapsed_time;
item.requests_count = requests_count;
item.regions_count = regions_count;
item.bytes_sent = bytes_sent;
return item;
}
@end
@implementation ZYJQNReportConfig
+ (instancetype)sharedInstance {
static ZYJQNReportConfig *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
_reportEnable = YES;
_interval = 10;
_serverURL = @"https://uplog.qbox.me/log/4";
_recordDirectory = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"com.qiniu.report"];
_maxRecordFileSize = 2 * 1024 * 1024;
_uploadThreshold = 4 * 1024;
_timeoutInterval = 10;
}
return self;
}
@end
static const NSString *recorderFileName = @"recorder";
static const NSString *reportTypeValueList[] = {@"form", @"mkblk", @"bput", @"mkfile", @"block"};
@interface ZYJQNUploadInfoReporter ()
@property (nonatomic, strong) ZYJQNReportConfig *config;
@property (nonatomic, assign) NSTimeInterval lastReportTime;
@property (nonatomic, strong) NSFileManager *fileManager;
@property (nonatomic, strong) NSString *recorderFilePath;
@property (nonatomic, strong) dispatch_queue_t recordQueue;
@property (nonatomic, strong) dispatch_semaphore_t semaphore;
@property (nonatomic, copy, readwrite) NSString *X_Log_Client_Id;
@end
@implementation ZYJQNUploadInfoReporter
+ (instancetype)sharedInstance {
static ZYJQNUploadInfoReporter *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
_config = [ZYJQNReportConfig sharedInstance];
_lastReportTime = 0;
_recorderFilePath = [NSString stringWithFormat:@"%@/%@", _config.recordDirectory, recorderFileName];
_fileManager = [NSFileManager defaultManager];
_recordQueue = dispatch_queue_create("com.qiniu.reporter", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)clean {
if ([_fileManager fileExistsAtPath:_recorderFilePath]) {
NSError *error = nil;
[_fileManager removeItemAtPath:_recorderFilePath error:&error];
if (error) {
ZYJQNAsyncRunInMain(^{
NSLog(@"remove recorder file failed: %@", error);
});
return;
}
}
}
- (BOOL)checkReportAvailable {
if (!_config.isReportEnable) return NO;
if (!(_config.maxRecordFileSize > _config.uploadThreshold)) {
ZYJQNAsyncRunInMain(^{
NSLog(@"maxRecordFileSize must be larger than uploadThreshold");
});
return NO;
}
return YES;
}
- (void)report:(NSString *)jsonString token:(NSString *)token {
if (![self checkReportAvailable] || !jsonString) return;
// 串行队列处理文件读写
dispatch_async(_recordQueue, ^{
[self innerReport:jsonString token:token];
});
}
- (void)innerReport:(NSString *)jsonString token:(NSString *)token {
// 检查recorder文件夹是否存在
NSError *error = nil;
if (![_fileManager fileExistsAtPath:_config.recordDirectory]) {
[_fileManager createDirectoryAtPath:_config.recordDirectory withIntermediateDirectories:YES attributes:nil error:&error];
if (error) {
ZYJQNAsyncRunInMain(^{
NSLog(@"create record directory failed, please check record directory: %@", error.localizedDescription);
});
return;
}
}
// 拼接换行符
NSString *finalRecordInfo = [jsonString stringByAppendingString:@"\n"];
if (![_fileManager fileExistsAtPath:_recorderFilePath]) {
// 如果recordFile不存在,创建文件并写入首行,首次不上传
[finalRecordInfo writeToFile:_recorderFilePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
} else {
// recordFile存在,拼接文件内容、上传到服务器
ZYJQNFile *file = [[ZYJQNFile alloc] init:_recorderFilePath error:&error];
if (error) {
ZYJQNAsyncRunInMain(^{
NSLog(@"create ZYJQNFile with path failed: %@", error.localizedDescription);
});
return;
}
// 判断recorder文件大小是否超过maxRecordFileSize
if (file.size < _config.maxRecordFileSize) {
// 上传信息写入recorder文件
NSFileHandle *fileHandler = [NSFileHandle fileHandleForUpdatingAtPath:_recorderFilePath];
[fileHandler seekToEndOfFile];
[fileHandler writeData:[finalRecordInfo dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandler closeFile];
}
// 判断是否满足上传条件:文件大于上报临界值 && (首次上传 || 距上次上传时间大于_config.interval)
NSTimeInterval currentTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970];
if (file.size > _config.uploadThreshold && (_lastReportTime == 0 || currentTime - _lastReportTime > _config.interval * 60)) {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:_config.serverURL]];
[request setValue:[NSString stringWithFormat:@"UpToken %@", token] forHTTPHeaderField:@"Authorization"];
[request setValue:[[ZYJQNUserAgent sharedInstance] getUserAgent:[ZYJQNUpToken parse:token].access] forHTTPHeaderField:@"User-Agent"];
if (self.X_Log_Client_Id) {
[request setValue:self.X_Log_Client_Id forHTTPHeaderField:@"X-Log-Client-Id"];
}
[request setHTTPMethod:@"POST"];
[request setTimeoutInterval:_config.timeoutInterval];
__block NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:[NSURL fileURLWithPath:_recorderFilePath] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode == 200) {
self.lastReportTime = [[NSDate dateWithTimeIntervalSinceNow:0] timeIntervalSince1970];
NSDictionary *respHeader = httpResponse.allHeaderFields;
if (!self.X_Log_Client_Id && [respHeader.allKeys containsObject:@"x-log-client-id"]) {
self.X_Log_Client_Id = respHeader[@"x-log-client-id"];
}
[self clean];
} else {
ZYJQNAsyncRunInMain(^{
NSLog(@"upload info report failed: %@", error.localizedDescription);
});
}
[session finishTasksAndInvalidate];
dispatch_semaphore_signal(self.semaphore);
}];
[uploadTask resume];
// 控制上传过程中,文件内容不被修改
_semaphore = dispatch_semaphore_create(0);
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
}
}
}
@end
//
//
// ZYJQNUploader.h
// ZYJQiniuSDK
//
// Created by bailong on 14-9-28.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNRecorderDelegate.h"
@class ZYJQNResponseInfo;
@class ZYJQNUploadOption;
@class ZYJQNConfiguration;
@class PHAsset;
@class PHAssetResource;
#if !TARGET_OS_MACCATALYST
@class ALAsset;
#endif
/**
* 上传完成后的回调函数
*
* @param info 上下文信息,包括状态码,错误值
* @param key 上传时指定的key,原样返回
* @param resp 上传成功会返回文件信息,失败为nil; 可以通过此值是否为nil 判断上传结果
*/
typedef void (^ZYJQNUpCompletionHandler)(ZYJQNResponseInfo *info, NSString *key, NSDictionary *resp);
/**
管理上传的类,可以生成一次,持续使用,不必反复创建。
*/
@interface ZYJQNUploadManager : NSObject
/**
* 默认构造方法,没有持久化记录
*
* @return 上传管理类实例
*/
- (instancetype)init;
/**
* 使用一个持久化的记录接口进行记录的构造方法
*
* @param recorder 持久化记录接口实现
*
* @return 上传管理类实例
*/
- (instancetype)initWithRecorder:(id<ZYJQNRecorderDelegate>)recorder;
/**
* 使用持久化记录接口以及持久化key生成函数的构造方法,默认情况下使用上传存储的key, 如果key为nil或者有特殊字符比如/,建议使用自己的生成函数
*
* @param recorder 持久化记录接口实现
* @param recorderKeyGenerator 持久化记录key生成函数
*
* @return 上传管理类实例
*/
- (instancetype)initWithRecorder:(id<ZYJQNRecorderDelegate>)recorder
recorderKeyGenerator:(ZYJQNRecorderKeyGenerator)recorderKeyGenerator;
/**
* 使用配置信息生成上传实例
*
* @param config 配置信息
*
* @return 上传管理类实例
*/
- (instancetype)initWithConfiguration:(ZYJQNConfiguration *)config;
/**
* 方便使用的单例方法
*
* @param config 配置信息
*
* @return 上传管理类实例
*/
+ (instancetype)sharedInstanceWithConfiguration:(ZYJQNConfiguration *)config;
/**
* 直接上传数据
*
* @param data 待上传的数据
* @param key 上传到云存储的key,为nil时表示是由七牛生成
* @param token 上传需要的token, 由服务器生成
* @param completionHandler 上传完成后的回调函数
* @param option 上传时传入的可选参数
*/
- (void)putData:(NSData *)data
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option;
/**
* 上传文件
*
* @param filePath 文件路径
* @param key 上传到云存储的key,为nil时表示是由七牛生成
* @param token 上传需要的token, 由服务器生成
* @param completionHandler 上传完成后的回调函数
* @param option 上传时传入的可选参数
*/
- (void)putFile:(NSString *)filePath
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option;
#if !TARGET_OS_MACCATALYST
/**
* 上传ALAsset文件
*
* @param asset ALAsset文件
* @param key 上传到云存储的key,为nil时表示是由七牛生成
* @param token 上传需要的token, 由服务器生成
* @param completionHandler 上传完成后的回调函数
* @param option 上传时传入的可选参数
*/
- (void)putALAsset:(ALAsset *)asset
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option API_UNAVAILABLE(macos, tvos);
#endif
/**
* 上传PHAsset文件(IOS8 andLater)
*
* @param asset PHAsset文件
* @param key 上传到云存储的key,为nil时表示是由七牛生成
* @param token 上传需要的token, 由服务器生成
* @param completionHandler 上传完成后的回调函数
* @param option 上传时传入的可选参数
*/
- (void)putPHAsset:(PHAsset *)asset
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option API_AVAILABLE(ios(9.1)) API_UNAVAILABLE(macos, tvos);
/**
* 上传PHAssetResource文件(IOS9.1 andLater)
*
* @param assetResource PHAssetResource文件
* @param key 上传到云存储的key,为nil时表示是由七牛生成
* @param token 上传需要的token, 由服务器生成
* @param completionHandler 上传完成后的回调函数
* @param option 上传时传入的可选参数
*/
- (void)putPHAssetResource:(PHAssetResource *)assetResource
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option API_AVAILABLE(ios(9)) API_UNAVAILABLE(macos, tvos);
@end
//
//
// ZYJQNUploader.h
// ZYJQiniuSDK
//
// Created by bailong on 14-9-28.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#import <MobileCoreServices/MobileCoreServices.h>
#import <UIKit/UIKit.h>
#if !TARGET_OS_MACCATALYST
#import <AssetsLibrary/AssetsLibrary.h>
#import "ZYJQNALAssetFile.h"
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
#import "ZYJQNPHAssetFile.h"
#import <Photos/Photos.h>
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
#import "ZYJQNPHAssetResource.h"
#endif
#else
#import <CoreServices/CoreServices.h>
#endif
#import "ZYJQNAsyncRun.h"
#import "ZYJQNConfiguration.h"
#import "ZYJQNCrc32.h"
#import "ZYJQNFile.h"
#import "ZYJQNFormUpload.h"
#import "ZYJQNResponseInfo.h"
#import "ZYJQNResumeUpload.h"
#import "ZYJQNSessionManager.h"
#import "ZYJQNUpToken.h"
#import "ZYJQNUploadManager.h"
#import "ZYJQNUploadOption+Private.h"
#import "ZYJQNConcurrentResumeUpload.h"
#import "ZYJQNUploadInfoCollector.h"
#import "ZYJQNDnsPrefetcher.h"
#import "ZYJQNZone.h"
@interface ZYJQNUploadManager ()
@property (nonatomic) ZYJQNSessionManager *sessionManager;
@property (nonatomic) ZYJQNConfiguration *config;
@end
@implementation ZYJQNUploadManager
- (instancetype)init {
return [self initWithConfiguration:nil];
}
- (instancetype)initWithRecorder:(id<ZYJQNRecorderDelegate>)recorder {
return [self initWithRecorder:recorder recorderKeyGenerator:nil];
}
- (instancetype)initWithRecorder:(id<ZYJQNRecorderDelegate>)recorder
recorderKeyGenerator:(ZYJQNRecorderKeyGenerator)recorderKeyGenerator {
ZYJQNConfiguration *config = [ZYJQNConfiguration build:^(ZYJQNConfigurationBuilder *builder) {
builder.recorder = recorder;
builder.recorderKeyGen = recorderKeyGenerator;
}];
return [self initWithConfiguration:config];
}
- (instancetype)initWithConfiguration:(ZYJQNConfiguration *)config {
if (self = [super init]) {
if (config == nil) {
config = [ZYJQNConfiguration build:^(ZYJQNConfigurationBuilder *builder){
}];
}
_config = config;
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
_sessionManager = [[ZYJQNSessionManager alloc] initWithProxy:config.proxy timeout:config.timeoutInterval urlConverter:config.converter];
#endif
[[ZYJQNTransactionManager shared] addDnsLocalLoadTransaction];
}
return self;
}
+ (instancetype)sharedInstanceWithConfiguration:(ZYJQNConfiguration *)config {
static ZYJQNUploadManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] initWithConfiguration:config];
});
return sharedInstance;
}
+ (BOOL)checkAndNotifyError:(NSString *)key
token:(NSString *)token
input:(NSObject *)input
identifier:(NSString *)identifier
complete:(ZYJQNUpCompletionHandler)completionHandler {
NSString *desc = nil;
if (completionHandler == nil) {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:@"no completionHandler"
userInfo:nil];
return YES;
}
if (input == nil) {
desc = @"no input data";
} else if (token == nil || [token isEqual:[NSNull null]] || [token isEqualToString:@""]) {
desc = @"no token";
}
if (desc != nil) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithInvalidArgument:desc identifier:identifier];
completionHandler(info, key, nil);
});
return YES;
}
return NO;
}
- (void)putData:(NSData *)data
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option {
NSString *identifier = [[NSUUID UUID] UUIDString];
[Collector registerWithIdentifier:identifier token:token];
[self putData:data fileName:nil key:key token:token identifier:identifier complete:completionHandler option:option];
}
- (void)putData:(NSData *)data
fileName:(NSString *)fileName
key:(NSString *)key
token:(NSString *)token
identifier:(NSString *)identifier
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option {
if ([ZYJQNUploadManager checkAndNotifyError:key token:token input:data identifier:identifier complete:completionHandler]) {
return;
}
[[ZYJQNTransactionManager shared] addDnsCheckAndPrefetchTransaction:self.config.zone
token:token];
ZYJQNUpToken *t = [ZYJQNUpToken parse:token];
if (t == nil) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithInvalidToken:@"invalid token" identifier:identifier];
completionHandler(info, key, nil);
});
return;
} else {
[Collector update:ZYJCK_bucket value:t.bucket identifier:identifier];
[Collector update:ZYJCK_key value:key identifier:identifier];
}
[_config.zone preQuery:t on:^(int code, ZYJQNHttpResponseInfo *httpResponseInfo) {
[Collector addRequestWithType:ZYJQNRequestType_ucQuery httpResponseInfo:httpResponseInfo fileOffset:ZYJQN_IntNotSet targetRegionId:nil currentRegionId:nil identifier:identifier];
if (code != 0) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:identifier];
completionHandler(info, key, nil);
});
return;
}
if ([data length] == 0) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithZeroData:nil identifier:identifier];
completionHandler(info, key, nil);
});
return;
}
ZYJQNUpCompletionHandler complete = ^(ZYJQNResponseInfo *info, NSString *key, NSDictionary *resp) {
ZYJQNAsyncRunInMain(^{
completionHandler(info, key, resp);
});
};
ZYJQNFormUpload *up = [[ZYJQNFormUpload alloc]
initWithData:data
withKey:key
withFileName:fileName
withToken:t
withIdentifier:(NSString *)identifier
withCompletionHandler:complete
withOption:option
withSessionManager:self.sessionManager
withConfiguration:self.config];
ZYJQNAsyncRun(^{
[up put];
});
}];
}
- (void)putFileInternal:(id<ZYJQNFileDelegate>)file
key:(NSString *)key
token:(NSString *)token
identifier:(NSString *)identifier
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option {
@autoreleasepool {
ZYJQNUpToken *t = [ZYJQNUpToken parse:token];
if (t == nil) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithInvalidToken:@"invalid token" identifier:identifier];
completionHandler(info, key, nil);
});
return;
} else {
[Collector update:ZYJCK_bucket value:t.bucket identifier:identifier];
[Collector update:ZYJCK_key value:key identifier:identifier];
}
[[ZYJQNTransactionManager shared] addDnsCheckAndPrefetchTransaction:self.config.zone
token:token];
[_config.zone preQuery:t on:^(int code, ZYJQNHttpResponseInfo *httpResponseInfo) {
[Collector addRequestWithType:ZYJQNRequestType_ucQuery httpResponseInfo:httpResponseInfo fileOffset:ZYJQN_IntNotSet targetRegionId:nil currentRegionId:nil identifier:identifier];
if (code != 0) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:identifier];
completionHandler(info, key, nil);
});
return;
}
ZYJQNUpCompletionHandler complete = ^(ZYJQNResponseInfo *info, NSString *key, NSDictionary *resp) {
[file close];
ZYJQNAsyncRunInMain(^{
completionHandler(info, key, resp);
});
};
if ([file size] <= self.config.putThreshold) {
NSError *error;
NSData *data = [file readAllWithError:&error];
if (error) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithLocalIOError:error identifier:identifier];
completionHandler(info, key, nil);
});
return;
}
NSString *fileName = [[file path] lastPathComponent];
[self putData:data fileName:fileName key:key token:token identifier:identifier complete:completionHandler option:option];
return;
}
NSString *recorderKey = key;
if (self.config.recorder != nil && self.config.recorderKeyGen != nil) {
recorderKey = self.config.recorderKeyGen(key, [file path]);
}
NSLog(@"recorder %@", self.config.recorder);
if (self.config.useConcurrentResumeUpload) {
ZYJQNConcurrentResumeUpload *up = [[ZYJQNConcurrentResumeUpload alloc]
initWithFile:file
withKey:key
withToken:t
withIdentifier:identifier
withRecorder:self.config.recorder
withRecorderKey:recorderKey
withSessionManager:self.sessionManager
withCompletionHandler:completionHandler
withOption:option
withConfiguration:self.config];
ZYJQNAsyncRun(^{
[up run];
});
} else {
ZYJQNResumeUpload *up = [[ZYJQNResumeUpload alloc]
initWithFile:file
withKey:key
withToken:t
withIdentifier:identifier
withCompletionHandler:complete
withOption:option
withRecorder:self.config.recorder
withRecorderKey:recorderKey
withSessionManager:self.sessionManager
withConfiguration:self.config];
ZYJQNAsyncRun(^{
[up run];
});
}
}];
}
}
- (void)putFile:(NSString *)filePath
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option {
NSString *identifier = [[NSUUID UUID] UUIDString];
[Collector registerWithIdentifier:identifier token:token];
if ([ZYJQNUploadManager checkAndNotifyError:key token:token input:filePath identifier:identifier complete:completionHandler]) {
return;
}
@autoreleasepool {
NSError *error = nil;
__block ZYJQNFile *file = [[ZYJQNFile alloc] init:filePath error:&error];
if (error) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithFileError:error identifier:identifier];
completionHandler(info, key, nil);
});
return;
}
[self putFileInternal:file key:key token:token identifier:identifier complete:completionHandler option:option];
}
}
#if !TARGET_OS_MACCATALYST
- (void)putALAsset:(ALAsset *)asset
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option {
#if __IPHONE_OS_VERSION_MIN_REQUIRED
NSString *identifier = [[NSUUID UUID] UUIDString];
[Collector registerWithIdentifier:identifier token:token];
if ([ZYJQNUploadManager checkAndNotifyError:key token:token input:asset identifier:identifier complete:completionHandler]) {
return;
}
@autoreleasepool {
NSError *error = nil;
__block ZYJQNALAssetFile *file = [[ZYJQNALAssetFile alloc] init:asset error:&error];
if (error) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithFileError:error identifier:identifier];
completionHandler(info, key, nil);
});
return;
}
[self putFileInternal:file key:key token:token identifier:identifier complete:completionHandler option:option];
}
#endif
}
#endif
- (void)putPHAsset:(PHAsset *)asset
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option {
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100)
NSString *identifier = [[NSUUID UUID] UUIDString];
[Collector registerWithIdentifier:identifier token:token];
if ([ZYJQNUploadManager checkAndNotifyError:key token:token input:asset identifier:identifier complete:completionHandler]) {
return;
}
@autoreleasepool {
NSError *error = nil;
__block ZYJQNPHAssetFile *file = [[ZYJQNPHAssetFile alloc] init:asset error:&error];
if (error) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithFileError:error identifier:identifier];
completionHandler(info, key, nil);
});
return;
}
[self putFileInternal:file key:key token:token identifier:identifier complete:completionHandler option:option];
}
#endif
}
- (void)putPHAssetResource:(PHAssetResource *)assetResource
key:(NSString *)key
token:(NSString *)token
complete:(ZYJQNUpCompletionHandler)completionHandler
option:(ZYJQNUploadOption *)option {
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000)
NSString *identifier = [[NSUUID UUID] UUIDString];
[Collector registerWithIdentifier:identifier token:token];
if ([ZYJQNUploadManager checkAndNotifyError:key token:token input:assetResource identifier:identifier complete:completionHandler]) {
return;
}
@autoreleasepool {
NSError *error = nil;
__block ZYJQNPHAssetResource *file = [[ZYJQNPHAssetResource alloc] init:assetResource error:&error];
if (error) {
ZYJQNAsyncRunInMain(^{
ZYJQNResponseInfo *info = [Collector completeWithFileError:error identifier:identifier];
completionHandler(info, key, nil);
});
return;
}
[self putFileInternal:file key:key token:token identifier:identifier complete:completionHandler option:option];
}
#endif
}
@end
//
//
// ZYJQNUploadOption+Private.h
// ZYJQiniuSDK
//
// Created by bailong on 14/10/5.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import "ZYJQNUploadOption.h"
@interface ZYJQNUploadOption (Private)
@property (nonatomic, getter=priv_isCancelled, readonly) BOOL cancelled;
@end
//
//
// ZYJQNUploadOption.h
// ZYJQiniuSDK
//
// Created by bailong on 14/10/4.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* 上传进度回调函数
*
* @param key 上传时指定的存储key
* @param percent 进度百分比
*/
typedef void (^ZYJQNUpProgressHandler)(NSString *key, float percent);
/**
* 上传中途取消函数
*
* @return 如果想取消,返回True, 否则返回No
*/
typedef BOOL (^ZYJQNUpCancellationSignal)(void);
/**
* 可选参数集合,此类初始化后sdk上传使用时 不会对此进行改变;如果参数没有变化以及没有使用依赖,可以重复使用。
*/
@interface ZYJQNUploadOption : NSObject
/**
* 用于服务器上传回调通知的自定义参数,参数的key必须以x: 开头
*/
@property (copy, nonatomic, readonly) NSDictionary *params;
/**
* 指定文件的mime类型
*/
@property (copy, nonatomic, readonly) NSString *mimeType;
/**
* 是否进行crc校验
*/
@property (readonly) BOOL checkCrc;
/**
* 进度回调函数
*/
@property (copy, readonly) ZYJQNUpProgressHandler progressHandler;
/**
* 中途取消函数
*/
@property (copy, readonly) ZYJQNUpCancellationSignal cancellationSignal;
/**
* 可选参数的初始化方法
*
* @param mimeType mime类型
* @param progress 进度函数
* @param params 自定义服务器回调参数
* @param check 是否进行crc检查
* @param cancellation 中途取消函数
*
* @return 可选参数类实例
*/
- (instancetype)initWithMime:(NSString *)mimeType
progressHandler:(ZYJQNUpProgressHandler)progress
params:(NSDictionary *)params
checkCrc:(BOOL)check
cancellationSignal:(ZYJQNUpCancellationSignal)cancellation;
- (instancetype)initWithProgessHandler:(ZYJQNUpProgressHandler)progress DEPRECATED_ATTRIBUTE;
- (instancetype)initWithProgressHandler:(ZYJQNUpProgressHandler)progress;
/**
* 内部使用,默认的参数实例
*
* @return 可选参数类实例
*/
+ (instancetype)defaultOptions;
@end
//
//
// ZYJQNUploadOption.m
// ZYJQiniuSDK
//
// Created by bailong on 14/10/4.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import "ZYJQNUploadOption+Private.h"
#import "ZYJQNUploadManager.h"
static NSString *mime(NSString *mimeType) {
if (mimeType == nil || [mimeType isEqualToString:@""]) {
return @"application/octet-stream";
}
return mimeType;
}
@implementation ZYJQNUploadOption
+ (NSDictionary *)filteParam:(NSDictionary *)params {
NSMutableDictionary *ret = [NSMutableDictionary dictionary];
if (params == nil) {
return ret;
}
[params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
if ([key hasPrefix:@"x:"] && ![obj isEqualToString:@""]) {
ret[key] = obj;
}
}];
return ret;
}
- (instancetype)initWithProgessHandler:(ZYJQNUpProgressHandler)progress {
return [self initWithMime:nil progressHandler:progress params:nil checkCrc:NO cancellationSignal:nil];
}
- (instancetype)initWithProgressHandler:(ZYJQNUpProgressHandler)progress {
return [self initWithMime:nil progressHandler:progress params:nil checkCrc:NO cancellationSignal:nil];
}
- (instancetype)initWithMime:(NSString *)mimeType
progressHandler:(ZYJQNUpProgressHandler)progress
params:(NSDictionary *)params
checkCrc:(BOOL)check
cancellationSignal:(ZYJQNUpCancellationSignal)cancel {
if (self = [super init]) {
_mimeType = mime(mimeType);
_progressHandler = progress != nil ? progress : ^(NSString *key, float percent) {
};
_params = [ZYJQNUploadOption filteParam:params];
_checkCrc = check;
_cancellationSignal = cancel != nil ? cancel : ^BOOL() {
return NO;
};
}
return self;
}
+ (instancetype)defaultOptions {
return [[ZYJQNUploadOption alloc] initWithMime:nil progressHandler:nil params:nil checkCrc:NO cancellationSignal:nil];
}
@end
//
//
// ZYJQiniuSDK
//
// Created by bailong on 14-9-28.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* url safe base64 编码类, 对/ 做了处理
*/
@interface ZYJQNUrlSafeBase64 : NSObject
/**
* 字符串编码
*
* @param source 字符串
*
* @return base64 字符串
*/
+ (NSString *)encodeString:(NSString *)source;
/**
* 二进制数据编码
*
* @param source 二进制数据
*
* @return base64字符串
*/
+ (NSString *)encodeData:(NSData *)source;
/**
* 字符串解码
*
* @param data 字符串
*
* @return 数据
*/
+ (NSData *)decodeString:(NSString *)data;
@end
//
//
// ZYJQiniuSDK
//
// Created by bailong on 14-9-28.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNUrlSafeBase64.h"
#import "ZYJQN_GTM_Base64.h"
@implementation ZYJQNUrlSafeBase64
+ (NSString *)encodeString:(NSString *)sourceString {
NSData *data = [NSData dataWithBytes:[sourceString UTF8String] length:[sourceString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
return [self encodeData:data];
}
+ (NSString *)encodeData:(NSData *)data {
return [ZYJQN_GTM_Base64 stringByWebSafeEncodingData:data padded:YES];
}
+ (NSData *)decodeString:(NSString *)data {
return [ZYJQN_GTM_Base64 webSafeDecodeString:data];
}
@end
//
//
// ZYJQNUserAgent.h
// ZYJQiniuSDK
//
// Created by bailong on 14-9-29.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* UserAgent
*
*/
@interface ZYJQNUserAgent : NSObject
/**
* 用户id
*/
@property (copy, nonatomic, readonly) NSString *id;
/**
* UserAgent 字串
*/
- (NSString *)description;
/**
* UserAgent + AK 字串
*/
- (NSString *)getUserAgent:(NSString *)access;
/**
* 单例
*/
+ (instancetype)sharedInstance;
@end
//
//
// ZYJQNUserAgent.m
// ZYJQiniuSDK
//
// Created by bailong on 14-9-29.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#import <MobileCoreServices/MobileCoreServices.h>
#import <UIKit/UIKit.h>
#else
#import <CoreServices/CoreServices.h>
#endif
#import "ZYJQNUserAgent.h"
#import "ZYJQNVersion.h"
static NSString *ZYJQN_clientId(void) {
#if __IPHONE_OS_VERSION_MIN_REQUIRED
NSString *s = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
if (s == nil) {
s = @"simulator";
}
return s;
#else
long long now_timestamp = [[NSDate date] timeIntervalSince1970] * 1000;
int r = arc4random() % 1000;
return [NSString stringWithFormat:@"%lld%u", now_timestamp, r];
#endif
}
static NSString *ZYJQN_userAgent(NSString *id, NSString *ak) {
#if __IPHONE_OS_VERSION_MIN_REQUIRED
return [NSString stringWithFormat:@"QiniuObject-C/%@ (%@; iOS %@; %@; %@)", kQiniuVersion, [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], id, ak];
#else
return [NSString stringWithFormat:@"QiniuObject-C/%@ (Mac OS X %@; %@; %@)", kQiniuVersion, [[NSProcessInfo processInfo] operatingSystemVersionString], id, ak];
#endif
}
@interface ZYJQNUserAgent ()
@property (nonatomic) NSString *ua;
@end
@implementation ZYJQNUserAgent
- (NSString *)description {
return _ua;
}
- (instancetype)init {
if (self = [super init]) {
_id = ZYJQN_clientId();
}
return self;
}
/**
* UserAgent
*/
- (NSString *)getUserAgent:(NSString *)access {
NSString *ak;
if (access == nil || access.length == 0) {
ak = @"-";
} else {
ak = access;
}
return ZYJQN_userAgent(_id, ak);
}
/**
* 单例
*/
+ (instancetype)sharedInstance {
static ZYJQNUserAgent *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
@end
//
//
// ZYJQNUtils.h
// ZYJQiniuSDK_Mac
//
// Created by yangsen on 2020/3/27.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZYJQNUtils : NSObject
/// 获取当前时间戳 单位:ms
+ (NSTimeInterval)currentTimestamp;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNUtils.m
// ZYJQiniuSDK_Mac
//
// Created by yangsen on 2020/3/27.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNUtils.h"
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>
@implementation ZYJQNUtils
+ (NSTimeInterval)currentTimestamp{
return [[NSDate date] timeIntervalSince1970] * 1000;
}
@end
//
//
// ZYJQNVersion.h
// ZYJQiniuSDK
//
// Created by bailong on 14-9-29.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* sdk 版本
*/
static NSString *const kQiniuVersion = @"7.4.3";
//
//
// ZYJQNZone.h
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/16.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNZoneInfo.h"
#import "ZYJQNHttpResponseInfo.h"
NS_ASSUME_NONNULL_BEGIN
@class ZYJQNUpToken, ZYJQNZonesInfo;
typedef void (^ZYJQNPrequeryReturn)(int code, ZYJQNHttpResponseInfo * _Nullable httpResponseInfo);
@interface ZYJQNZone : NSObject
- (NSString *)upHost:(ZYJQNZoneInfo *)zoneInfo
isHttps:(BOOL)isHttps
lastUpHost:(NSString *)lastUpHost;
/**
* 默认上传服务器地址列表
*/
- (void)preQuery:(ZYJQNUpToken * _Nullable)token
on:(ZYJQNPrequeryReturn)ret;
- (ZYJQNZonesInfo *)getZonesInfoWithToken:(ZYJQNUpToken * _Nullable)token;
- (NSString *)up:(ZYJQNUpToken * _Nullable)token
zoneInfoType:(ZYJQNZoneInfoType)zoneInfoType
isHttps:(BOOL)isHttps
frozenDomain:(NSString * _Nullable)frozenDomain;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNZone.m
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/16.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNZone.h"
#import "ZYJQNUpToken.h"
#import "ZYJQNZoneInfo.h"
@implementation ZYJQNZone
- (NSString *)upHost:(ZYJQNZoneInfo *)zoneInfo
isHttps:(BOOL)isHttps
lastUpHost:(NSString *)lastUpHost {
NSString *upHost = nil;
NSString *upDomain = nil;
// frozen domain
if (lastUpHost) {
NSString *upLastDomain = nil;
if (isHttps) {
upLastDomain = [lastUpHost substringFromIndex:8];
} else {
upLastDomain = [lastUpHost substringFromIndex:7];
}
[zoneInfo frozenDomain:upLastDomain];
}
//get backup domain
for (NSString *backupDomain in zoneInfo.upDomainsList) {
NSDate *frozenTill = zoneInfo.upDomainsDic[backupDomain];
NSDate *now = [NSDate date];
if ([frozenTill compare:now] == NSOrderedAscending) {
upDomain = backupDomain;
break;
}
}
if (upDomain) {
[zoneInfo.upDomainsDic setObject:[NSDate dateWithTimeIntervalSince1970:0] forKey:upDomain];
} else {
//reset all the up host frozen time
if (!lastUpHost) {
for (NSString *domain in zoneInfo.upDomainsList) {
[zoneInfo.upDomainsDic setObject:[NSDate dateWithTimeIntervalSince1970:0] forKey:domain];
}
if (zoneInfo.upDomainsList.count > 0) {
upDomain = zoneInfo.upDomainsList[0];
}
}
}
if (upDomain) {
if (isHttps) {
upHost = [NSString stringWithFormat:@"https://%@", upDomain];
} else {
upHost = [NSString stringWithFormat:@"http://%@", upDomain];
}
}
return upHost;
}
- (NSString *)up:(ZYJQNUpToken *)token
zoneInfoType:(ZYJQNZoneInfoType)zoneInfoType
isHttps:(BOOL)isHttps
frozenDomain:(NSString *)frozenDomain {
return nil;
}
- (ZYJQNZonesInfo *)getZonesInfoWithToken:(ZYJQNUpToken *)token {
return nil;
}
- (void)preQuery:(ZYJQNUpToken *)token
on:(ZYJQNPrequeryReturn)ret {
ret(0, nil);
}
@end
//
//
// ZYJQNZoneInfo.h
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/16.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, ZYJQNZoneInfoType) {
ZYJQNZoneInfoTypeMain,
ZYJQNZoneInfoTypeBackup,
};
typedef enum : NSUInteger {
ZYJQNZoneRegion_z0,
ZYJQNZoneRegion_z1,
ZYJQNZoneRegion_z2,
ZYJQNZoneRegion_as0,
ZYJQNZoneRegion_na0,
ZYJQNZoneRegion_unknown
} ZYJQNZoneRegion;
@interface ZYJQNZoneInfo : NSObject
@property (nonatomic, assign, readonly) ZYJQNZoneInfoType type;
@property (nonatomic, assign, readonly) long ttl;
@property (nonatomic, strong, readonly) NSArray<NSString *> *upDomainsList;
@property (nonatomic, strong, readonly) NSMutableDictionary *upDomainsDic;
- (instancetype)init:(long)ttl
upDomainsList:(NSMutableArray<NSString *> *)upDomainsList
upDomainsDic:(NSMutableDictionary *)upDomainsDic
zoneRegion:(ZYJQNZoneRegion)zoneRegion;
- (ZYJQNZoneInfo *)buildInfoFromJson:(NSDictionary *)resp;
- (void)frozenDomain:(NSString *)domain;
- (BOOL)isValid;
@end
@interface ZYJQNZonesInfo : NSObject
@property (nonatomic, strong) NSArray<ZYJQNZoneInfo *> *zonesInfo;
@property (nonatomic, assign, readonly) BOOL hasBackupZone;
+ (instancetype)buildZonesInfoWithResp:(NSDictionary *)resp;
- (instancetype)initWithZonesInfo:(NSArray<ZYJQNZoneInfo *> *)zonesInfo;
- (ZYJQNZoneInfo *)getZoneInfoWithType:(ZYJQNZoneInfoType)type;
- (NSString *)getZoneInfoRegionNameWithType:(ZYJQNZoneInfoType)type;
@end
NS_ASSUME_NONNULL_END
//
//
// ZYJQNZoneInfo.m
// ZYJQiniuSDK
//
// Created by yangsen on 2020/4/16.
// Copyright © 2020 Qiniu. All rights reserved.
//
#import "ZYJQNZoneInfo.h"
static NSString *const zoneNames[] = {@"z0", @"z1", @"z2", @"as0", @"na0", @"unknown"};
@interface ZYJQNZoneInfo()
@property (nonatomic, assign) ZYJQNZoneInfoType type;
@property (nonatomic, assign) ZYJQNZoneRegion zoneRegion;
@property (nonatomic, assign) long ttl;
@property (nonatomic, strong) NSDate *buildDate;
@property (nonatomic, strong) NSMutableArray<NSString *> *upDomainsList;
@property (nonatomic, strong) NSMutableDictionary *upDomainsDic;
@end
@implementation ZYJQNZoneInfo
- (instancetype)init:(long)ttl
upDomainsList:(NSMutableArray<NSString *> *)upDomainsList
upDomainsDic:(NSMutableDictionary *)upDomainsDic
zoneRegion:(ZYJQNZoneRegion)zoneRegion {
if (self = [super init]) {
_ttl = ttl;
_buildDate = [NSDate date];
_upDomainsList = upDomainsList;
_upDomainsDic = upDomainsDic;
_zoneRegion = zoneRegion;
_type = ZYJQNZoneInfoTypeMain;
}
return self;
}
- (ZYJQNZoneInfo *)buildInfoFromJson:(NSDictionary *)resp {
long ttl = [[resp objectForKey:@"ttl"] longValue];
NSDictionary *up = [resp objectForKey:@"up"];
NSDictionary *acc = [up objectForKey:@"acc"];
NSDictionary *src = [up objectForKey:@"src"];
NSDictionary *old_acc = [up objectForKey:@"old_acc"];
NSDictionary *old_src = [up objectForKey:@"old_src"];
NSArray *urlDicList = [[NSArray alloc] initWithObjects:acc, src, old_acc, old_src, nil];
NSMutableArray *domainList = [[NSMutableArray alloc] init];
NSMutableDictionary *domainDic = [[NSMutableDictionary alloc] init];
//main
for (int i = 0; i < urlDicList.count; i++) {
if ([[urlDicList[i] allKeys] containsObject:@"main"]) {
NSArray *mainDomainList = urlDicList[i][@"main"];
for (int i = 0; i < mainDomainList.count; i++) {
[domainList addObject:mainDomainList[i]];
[domainDic setObject:[NSDate dateWithTimeIntervalSince1970:0] forKey:mainDomainList[i]];
}
}
}
//backup
for (int i = 0; i < urlDicList.count; i++) {
if ([[urlDicList[i] allKeys] containsObject:@"backup"]) {
NSArray *mainDomainList = urlDicList[i][@"backup"];
for (int i = 0; i < mainDomainList.count; i++) {
[domainList addObject:mainDomainList[i]];
[domainDic setObject:[NSDate dateWithTimeIntervalSince1970:0] forKey:mainDomainList[i]];
}
}
}
// judge zone region via io
NSDictionary *io = [resp objectForKey:@"io"];
NSDictionary *io_src = [io objectForKey:@"src"];
NSArray *io_main = [io_src objectForKey:@"main"];
NSString *io_host = io_main.count > 0 ? io_main[0] : nil;
ZYJQNZoneRegion zoneRegion = ZYJQNZoneRegion_unknown;
if ([io_host isEqualToString:@"iovip.qbox.me"]) {
zoneRegion = ZYJQNZoneRegion_z0;
} else if ([io_host isEqualToString:@"iovip-z1.qbox.me"]) {
zoneRegion = ZYJQNZoneRegion_z1;
} else if ([io_host isEqualToString:@"iovip-z2.qbox.me"]) {
zoneRegion = ZYJQNZoneRegion_z2;
} else if ([io_host isEqualToString:@"iovip-na0.qbox.me"]) {
zoneRegion = ZYJQNZoneRegion_na0;
} else if ([io_host isEqualToString:@"iovip-as0.qbox.me"]) {
zoneRegion = ZYJQNZoneRegion_as0;
} else {
zoneRegion = ZYJQNZoneRegion_unknown;
}
return [[ZYJQNZoneInfo alloc] init:ttl upDomainsList:domainList upDomainsDic:domainDic zoneRegion:zoneRegion];
}
- (void)frozenDomain:(NSString *)domain {
NSTimeInterval secondsFor10min = 10 * 60;
NSDate *tomorrow = [NSDate dateWithTimeIntervalSinceNow:secondsFor10min];
[self.upDomainsDic setObject:tomorrow forKey:domain];
}
- (BOOL)isValid{
NSDate *currentDate = [NSDate date];
if (self.ttl > [currentDate timeIntervalSinceDate:self.buildDate]) {
return YES;
} else {
return NO;
}
}
@end
@interface ZYJQNZonesInfo()
@end
@implementation ZYJQNZonesInfo
- (instancetype)initWithZonesInfo:(NSArray<ZYJQNZoneInfo *> *)zonesInfo{
self = [super init];
if (self) {
_zonesInfo = zonesInfo;
}
return self;
}
+ (instancetype)buildZonesInfoWithResp:(NSDictionary *)resp {
NSMutableArray *zonesInfo = [NSMutableArray array];
NSArray *hosts = resp[@"hosts"];
for (NSInteger i = 0; i < hosts.count; i++) {
ZYJQNZoneInfo *zoneInfo = [[[ZYJQNZoneInfo alloc] init] buildInfoFromJson:hosts[i]];
zoneInfo.type = i == 0 ? ZYJQNZoneInfoTypeMain : ZYJQNZoneInfoTypeBackup;
[zonesInfo addObject:zoneInfo];
}
return [[[self class] alloc] initWithZonesInfo:zonesInfo];
}
- (ZYJQNZoneInfo *)getZoneInfoWithType:(ZYJQNZoneInfoType)type {
ZYJQNZoneInfo *zoneInfo = nil;
for (ZYJQNZoneInfo *info in _zonesInfo) {
if (info.type == type) {
zoneInfo = info;
break;
}
}
return zoneInfo;
}
- (NSString *)getZoneInfoRegionNameWithType:(ZYJQNZoneInfoType)type {
ZYJQNZoneInfo *zoneInfo = [self getZoneInfoWithType:type];
return zoneNames[zoneInfo.zoneRegion];
}
- (BOOL)hasBackupZone {
return _zonesInfo.count > 1;
}
@end
//
//
// GTMBase64.h
//
// Copyright 2006-2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
#import <Foundation/Foundation.h>
// GTMBase64
//
/// Helper for handling Base64 and WebSafeBase64 encodings
//
/// The webSafe methods use different character set and also the results aren't
/// always padded to a multiple of 4 characters. This is done so the resulting
/// data can be used in urls and url query arguments without needing any
/// encoding. You must use the webSafe* methods together, the data does not
/// interop with the RFC methods.
//
@interface ZYJQN_GTM_Base64 : NSObject
//
// Standard Base64 (RFC) handling
//
// encodeData:
//
/// Base64 encodes contents of the NSData object.
//
/// Returns:
/// A new autoreleased NSData with the encoded payload. nil for any error.
//
+ (NSData *)encodeData:(NSData *)data;
// decodeData:
//
/// Base64 decodes contents of the NSData object.
//
/// Returns:
/// A new autoreleased NSData with the decoded payload. nil for any error.
//
+ (NSData *)decodeData:(NSData *)data;
// encodeBytes:length:
//
/// Base64 encodes the data pointed at by |bytes|.
//
/// Returns:
/// A new autoreleased NSData with the encoded payload. nil for any error.
//
+ (NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length;
// decodeBytes:length:
//
/// Base64 decodes the data pointed at by |bytes|.
//
/// Returns:
/// A new autoreleased NSData with the encoded payload. nil for any error.
//
+ (NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length;
// stringByEncodingData:
//
/// Base64 encodes contents of the NSData object.
//
/// Returns:
/// A new autoreleased NSString with the encoded payload. nil for any error.
//
+ (NSString *)stringByEncodingData:(NSData *)data;
// stringByEncodingBytes:length:
//
/// Base64 encodes the data pointed at by |bytes|.
//
/// Returns:
/// A new autoreleased NSString with the encoded payload. nil for any error.
//
+ (NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length;
// decodeString:
//
/// Base64 decodes contents of the NSString.
//
/// Returns:
/// A new autoreleased NSData with the decoded payload. nil for any error.
//
+ (NSData *)decodeString:(NSString *)string;
//
// Modified Base64 encoding so the results can go onto urls.
//
// The changes are in the characters generated and also allows the result to
// not be padded to a multiple of 4.
// Must use the matching call to encode/decode, won't interop with the
// RFC versions.
//
// webSafeEncodeData:padded:
//
/// WebSafe Base64 encodes contents of the NSData object. If |padded| is YES
/// then padding characters are added so the result length is a multiple of 4.
//
/// Returns:
/// A new autoreleased NSData with the encoded payload. nil for any error.
//
+ (NSData *)webSafeEncodeData:(NSData *)data
padded:(BOOL)padded;
// webSafeDecodeData:
//
/// WebSafe Base64 decodes contents of the NSData object.
//
/// Returns:
/// A new autoreleased NSData with the decoded payload. nil for any error.
//
+ (NSData *)webSafeDecodeData:(NSData *)data;
// webSafeEncodeBytes:length:padded:
//
/// WebSafe Base64 encodes the data pointed at by |bytes|. If |padded| is YES
/// then padding characters are added so the result length is a multiple of 4.
//
/// Returns:
/// A new autoreleased NSData with the encoded payload. nil for any error.
//
+ (NSData *)webSafeEncodeBytes:(const void *)bytes
length:(NSUInteger)length
padded:(BOOL)padded;
// webSafeDecodeBytes:length:
//
/// WebSafe Base64 decodes the data pointed at by |bytes|.
//
/// Returns:
/// A new autoreleased NSData with the encoded payload. nil for any error.
//
+ (NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length;
// stringByWebSafeEncodingData:padded:
//
/// WebSafe Base64 encodes contents of the NSData object. If |padded| is YES
/// then padding characters are added so the result length is a multiple of 4.
//
/// Returns:
/// A new autoreleased NSString with the encoded payload. nil for any error.
//
+ (NSString *)stringByWebSafeEncodingData:(NSData *)data
padded:(BOOL)padded;
// stringByWebSafeEncodingBytes:length:padded:
//
/// WebSafe Base64 encodes the data pointed at by |bytes|. If |padded| is YES
/// then padding characters are added so the result length is a multiple of 4.
//
/// Returns:
/// A new autoreleased NSString with the encoded payload. nil for any error.
//
+ (NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
length:(NSUInteger)length
padded:(BOOL)padded;
// webSafeDecodeString:
//
/// WebSafe Base64 decodes contents of the NSString.
//
/// Returns:
/// A new autoreleased NSData with the decoded payload. nil for any error.
//
+ (NSData *)webSafeDecodeString:(NSString *)string;
@end
//
//
// GTMBase64.m
//
// Copyright 2006-2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
#import "ZYJQN_GTM_Base64.h"
static const char *kBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char *kWebSafeBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
static const char kBase64PaddingChar = '=';
static const char kBase64InvalidChar = 99;
static const char kBase64DecodeChars[] = {
// This array was generated by the following code:
// #include <sys/time.h>
// #include <stdlib.h>
// #include <string.h>
// main()
// {
// static const char Base64[] =
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// char *pos;
// int idx, i, j;
// printf(" ");
// for (i = 0; i < 255; i += 8) {
// for (j = i; j < i + 8; j++) {
// pos = strchr(Base64, j);
// if ((pos == NULL) || (j == 0))
// idx = 99;
// else
// idx = pos - Base64;
// if (idx == 99)
// printf(" %2d, ", idx);
// else
// printf(" %2d/*%c*/,", idx, j);
// }
// printf("\n ");
// }
// }
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 62 /*+*/, 99, 99, 99, 63 /*/ */,
52 /*0*/, 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/,
60 /*8*/, 61 /*9*/, 99, 99, 99, 99, 99, 99,
99, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, 5 /*F*/, 6 /*G*/,
7 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, 12 /*M*/, 13 /*N*/, 14 /*O*/,
15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/,
23 /*X*/, 24 /*Y*/, 25 /*Z*/, 99, 99, 99, 99, 99,
99, 26 /*a*/, 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/,
33 /*h*/, 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/,
41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, 48 /*w*/,
49 /*x*/, 50 /*y*/, 51 /*z*/, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99};
static const char kWebSafeBase64DecodeChars[] = {
// This array was generated by the following code:
// #include <sys/time.h>
// #include <stdlib.h>
// #include <string.h>
// main()
// {
// static const char Base64[] =
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
// char *pos;
// int idx, i, j;
// printf(" ");
// for (i = 0; i < 255; i += 8) {
// for (j = i; j < i + 8; j++) {
// pos = strchr(Base64, j);
// if ((pos == NULL) || (j == 0))
// idx = 99;
// else
// idx = pos - Base64;
// if (idx == 99)
// printf(" %2d, ", idx);
// else
// printf(" %2d/*%c*/,", idx, j);
// }
// printf("\n ");
// }
// }
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 62 /*-*/, 99, 99,
52 /*0*/, 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/,
60 /*8*/, 61 /*9*/, 99, 99, 99, 99, 99, 99,
99, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, 5 /*F*/, 6 /*G*/,
7 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, 12 /*M*/, 13 /*N*/, 14 /*O*/,
15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/,
23 /*X*/, 24 /*Y*/, 25 /*Z*/, 99, 99, 99, 99, 63 /*_*/,
99, 26 /*a*/, 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/,
33 /*h*/, 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/,
41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, 48 /*w*/,
49 /*x*/, 50 /*y*/, 51 /*z*/, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99};
// Tests a character to see if it's a whitespace character.
//
// Returns:
// YES if the character is a whitespace character.
// NO if the character is not a whitespace character.
//
BOOL ZYJQN_IsSpace(unsigned char c) {
// we use our own mapping here because we don't want anything w/ locale
// support.
static BOOL kSpaces[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 0-9
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 10-19
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20-29
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 30-39
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40-49
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50-59
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60-69
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 70-79
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-89
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90-99
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100-109
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 110-119
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120-129
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 130-139
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140-149
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 150-159
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160-169
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170-179
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180-189
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 190-199
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200-209
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 210-219
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220-229
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 230-239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240-249
0, 0, 0, 0, 0, 1, // 250-255
};
return kSpaces[c];
}
// Calculate how long the data will be once it's base64 encoded.
//
// Returns:
// The guessed encoded length for a source length
//
NSUInteger ZYJQN_CalcEncodedLength(NSUInteger srcLen, BOOL padded) {
NSUInteger intermediate_result = 8 * srcLen + 5;
NSUInteger len = intermediate_result / 6;
if (padded) {
len = ((len + 3) / 4) * 4;
}
return len;
}
// Tries to calculate how long the data will be once it's base64 decoded.
// Unlike the above, this is always an upperbound, since the source data
// could have spaces and might end with the padding characters on them.
//
// Returns:
// The guessed decoded length for a source length
//
NSUInteger ZYJQN_GuessDecodedLength(NSUInteger srcLen) {
return (srcLen + 3) / 4 * 3;
}
@interface ZYJQN_GTM_Base64 (PrivateMethods)
+ (NSData *)baseEncode:(const void *)bytes
length:(NSUInteger)length
charset:(const char *)charset
padded:(BOOL)padded;
+ (NSData *)baseDecode:(const void *)bytes
length:(NSUInteger)length
charset:(const char *)charset
requirePadding:(BOOL)requirePadding;
+ (NSUInteger)baseEncode:(const char *)srcBytes
srcLen:(NSUInteger)srcLen
destBytes:(char *)destBytes
destLen:(NSUInteger)destLen
charset:(const char *)charset
padded:(BOOL)padded;
+ (NSUInteger)baseDecode:(const char *)srcBytes
srcLen:(NSUInteger)srcLen
destBytes:(char *)destBytes
destLen:(NSUInteger)destLen
charset:(const char *)charset
requirePadding:(BOOL)requirePadding;
@end
@implementation ZYJQN_GTM_Base64
//
// Standard Base64 (RFC) handling
//
+ (NSData *)encodeData:(NSData *)data {
return [self baseEncode:[data bytes]
length:[data length]
charset:kBase64EncodeChars
padded:YES];
}
+ (NSData *)decodeData:(NSData *)data {
return [self baseDecode:[data bytes]
length:[data length]
charset:kBase64DecodeChars
requirePadding:YES];
}
+ (NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length {
return [self baseEncode:bytes
length:length
charset:kBase64EncodeChars
padded:YES];
}
+ (NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length {
return [self baseDecode:bytes
length:length
charset:kBase64DecodeChars
requirePadding:YES];
}
+ (NSString *)stringByEncodingData:(NSData *)data {
NSString *result = nil;
NSData *converted = [self baseEncode:[data bytes]
length:[data length]
charset:kBase64EncodeChars
padded:YES];
if (converted) {
result = [[NSString alloc] initWithData:converted
encoding:NSASCIIStringEncoding];
}
return result;
}
+ (NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length {
NSString *result = nil;
NSData *converted = [self baseEncode:bytes
length:length
charset:kBase64EncodeChars
padded:YES];
if (converted) {
result = [[NSString alloc] initWithData:converted
encoding:NSASCIIStringEncoding];
}
return result;
}
+ (NSData *)decodeString:(NSString *)string {
NSData *result = nil;
NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
if (data) {
result = [self baseDecode:[data bytes]
length:[data length]
charset:kBase64DecodeChars
requirePadding:YES];
}
return result;
}
//
// Modified Base64 encoding so the results can go onto urls.
//
// The changes are in the characters generated and also the result isn't
// padded to a multiple of 4.
// Must use the matching call to encode/decode, won't interop with the
// RFC versions.
//
+ (NSData *)webSafeEncodeData:(NSData *)data
padded:(BOOL)padded {
return [self baseEncode:[data bytes]
length:[data length]
charset:kWebSafeBase64EncodeChars
padded:padded];
}
+ (NSData *)webSafeDecodeData:(NSData *)data {
return [self baseDecode:[data bytes]
length:[data length]
charset:kWebSafeBase64DecodeChars
requirePadding:NO];
}
+ (NSData *)webSafeEncodeBytes:(const void *)bytes
length:(NSUInteger)length
padded:(BOOL)padded {
return [self baseEncode:bytes
length:length
charset:kWebSafeBase64EncodeChars
padded:padded];
}
+ (NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length {
return [self baseDecode:bytes
length:length
charset:kWebSafeBase64DecodeChars
requirePadding:NO];
}
+ (NSString *)stringByWebSafeEncodingData:(NSData *)data
padded:(BOOL)padded {
NSString *result = nil;
NSData *converted = [self baseEncode:[data bytes]
length:[data length]
charset:kWebSafeBase64EncodeChars
padded:padded];
if (converted) {
result = [[NSString alloc] initWithData:converted
encoding:NSASCIIStringEncoding];
}
return result;
}
+ (NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
length:(NSUInteger)length
padded:(BOOL)padded {
NSString *result = nil;
NSData *converted = [self baseEncode:bytes
length:length
charset:kWebSafeBase64EncodeChars
padded:padded];
if (converted) {
result = [[NSString alloc] initWithData:converted
encoding:NSASCIIStringEncoding];
}
return result;
}
+ (NSData *)webSafeDecodeString:(NSString *)string {
NSData *result = nil;
NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
if (data) {
result = [self baseDecode:[data bytes]
length:[data length]
charset:kWebSafeBase64DecodeChars
requirePadding:NO];
}
return result;
}
@end
@implementation ZYJQN_GTM_Base64 (PrivateMethods)
//
// baseEncode:length:charset:padded:
//
// Does the common lifting of creating the dest NSData. it creates & sizes the
// data for the results. |charset| is the characters to use for the encoding
// of the data. |padding| controls if the encoded data should be padded to a
// multiple of 4.
//
// Returns:
// an autorelease NSData with the encoded data, nil if any error.
//
+ (NSData *)baseEncode:(const void *)bytes
length:(NSUInteger)length
charset:(const char *)charset
padded:(BOOL)padded {
// how big could it be?
NSUInteger maxLength = ZYJQN_CalcEncodedLength(length, padded);
// make space
NSMutableData *result = [NSMutableData data];
[result setLength:maxLength];
// do it
NSUInteger finalLength = [self baseEncode:bytes
srcLen:length
destBytes:[result mutableBytes]
destLen:[result length]
charset:charset
padded:padded];
if (finalLength) {
// _GTMDevAssert(finalLength == maxLength, @"how did we calc the length wrong?");
} else {
// shouldn't happen, this means we ran out of space
result = nil;
}
return result;
}
//
// baseDecode:length:charset:requirePadding:
//
// Does the common lifting of creating the dest NSData. it creates & sizes the
// data for the results. |charset| is the characters to use for the decoding
// of the data.
//
// Returns:
// an autorelease NSData with the decoded data, nil if any error.
//
//
+ (NSData *)baseDecode:(const void *)bytes
length:(NSUInteger)length
charset:(const char *)charset
requirePadding:(BOOL)requirePadding {
// could try to calculate what it will end up as
NSUInteger maxLength = ZYJQN_GuessDecodedLength(length);
// make space
NSMutableData *result = [NSMutableData data];
[result setLength:maxLength];
// do it
NSUInteger finalLength = [self baseDecode:bytes
srcLen:length
destBytes:[result mutableBytes]
destLen:[result length]
charset:charset
requirePadding:requirePadding];
if (finalLength) {
if (finalLength != maxLength) {
// resize down to how big it was
[result setLength:finalLength];
}
} else {
// either an error in the args, or we ran out of space
result = nil;
}
return result;
}
//
// baseEncode:srcLen:destBytes:destLen:charset:padded:
//
// Encodes the buffer into the larger. returns the length of the encoded
// data, or zero for an error.
// |charset| is the characters to use for the encoding
// |padded| tells if the result should be padded to a multiple of 4.
//
// Returns:
// the length of the encoded data. zero if any error.
//
+ (NSUInteger)baseEncode:(const char *)srcBytes
srcLen:(NSUInteger)srcLen
destBytes:(char *)destBytes
destLen:(NSUInteger)destLen
charset:(const char *)charset
padded:(BOOL)padded {
if (!srcLen || !destLen || !srcBytes || !destBytes) {
return 0;
}
char *curDest = destBytes;
const unsigned char *curSrc = (const unsigned char *)(srcBytes);
// Three bytes of data encodes to four characters of cyphertext.
// So we can pump through three-byte chunks atomically.
while (srcLen > 2) {
// space?
// _GTMDevAssert(destLen >= 4, @"our calc for encoded length was wrong");
curDest[0] = charset[curSrc[0] >> 2];
curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
curDest[2] = charset[((curSrc[1] & 0x0f) << 2) + (curSrc[2] >> 6)];
curDest[3] = charset[curSrc[2] & 0x3f];
curDest += 4;
curSrc += 3;
srcLen -= 3;
destLen -= 4;
}
// now deal with the tail (<=2 bytes)
switch (srcLen) {
case 0:
// Nothing left; nothing more to do.
break;
case 1:
// One byte left: this encodes to two characters, and (optionally)
// two pad characters to round out the four-character cypherblock.
// _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
curDest[0] = charset[curSrc[0] >> 2];
curDest[1] = charset[(curSrc[0] & 0x03) << 4];
curDest += 2;
destLen -= 2;
if (padded) {
// _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
curDest[0] = kBase64PaddingChar;
curDest[1] = kBase64PaddingChar;
curDest += 2;
}
break;
case 2:
// Two bytes left: this encodes to three characters, and (optionally)
// one pad character to round out the four-character cypherblock.
// _GTMDevAssert(destLen >= 3, @"our calc for encoded length was wrong");
curDest[0] = charset[curSrc[0] >> 2];
curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
curDest[2] = charset[(curSrc[1] & 0x0f) << 2];
curDest += 3;
destLen -= 3;
if (padded) {
// _GTMDevAssert(destLen >= 1, @"our calc for encoded length was wrong");
curDest[0] = kBase64PaddingChar;
curDest += 1;
}
break;
}
// return the length
return (curDest - destBytes);
}
//
// baseDecode:srcLen:destBytes:destLen:charset:requirePadding:
//
// Decodes the buffer into the larger. returns the length of the decoded
// data, or zero for an error.
// |charset| is the character decoding buffer to use
//
// Returns:
// the length of the encoded data. zero if any error.
//
+ (NSUInteger)baseDecode:(const char *)srcBytes
srcLen:(NSUInteger)srcLen
destBytes:(char *)destBytes
destLen:(NSUInteger)destLen
charset:(const char *)charset
requirePadding:(BOOL)requirePadding {
if (!srcLen || !destLen || !srcBytes || !destBytes) {
return 0;
}
int decode;
NSUInteger destIndex = 0;
int state = 0;
char ch = 0;
while (srcLen-- && (ch = *srcBytes++) != 0) {
if (ZYJQN_IsSpace(ch)) // Skip whitespace
continue;
if (ch == kBase64PaddingChar)
break;
decode = charset[(unsigned int)ch];
if (decode == kBase64InvalidChar)
return 0;
// Four cyphertext characters decode to three bytes.
// Therefore we can be in one of four states.
switch (state) {
case 0:
// We're at the beginning of a four-character cyphertext block.
// This sets the high six bits of the first byte of the
// plaintext block.
// _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
destBytes[destIndex] = decode << 2;
state = 1;
break;
case 1:
// We're one character into a four-character cyphertext block.
// This sets the low two bits of the first plaintext byte,
// and the high four bits of the second plaintext byte.
// _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
destBytes[destIndex] |= decode >> 4;
destBytes[destIndex + 1] = (decode & 0x0f) << 4;
destIndex++;
state = 2;
break;
case 2:
// We're two characters into a four-character cyphertext block.
// This sets the low four bits of the second plaintext
// byte, and the high two bits of the third plaintext byte.
// However, if this is the end of data, and those two
// bits are zero, it could be that those two bits are
// leftovers from the encoding of data that had a length
// of two mod three.
// _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
destBytes[destIndex] |= decode >> 2;
destBytes[destIndex + 1] = (decode & 0x03) << 6;
destIndex++;
state = 3;
break;
case 3:
// We're at the last character of a four-character cyphertext block.
// This sets the low six bits of the third plaintext byte.
// _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
destBytes[destIndex] |= decode;
destIndex++;
state = 0;
break;
}
}
// We are done decoding Base-64 chars. Let's see if we ended
// on a byte boundary, and/or with erroneous trailing characters.
if (ch == kBase64PaddingChar) { // We got a pad char
if ((state == 0) || (state == 1)) {
return 0; // Invalid '=' in first or second position
}
if (srcLen == 0) {
if (state == 2) { // We run out of input but we still need another '='
return 0;
}
// Otherwise, we are in state 3 and only need this '='
} else {
if (state == 2) { // need another '='
while ((ch = *srcBytes++) && (srcLen-- > 0)) {
if (!ZYJQN_IsSpace(ch))
break;
}
if (ch != kBase64PaddingChar) {
return 0;
}
}
// state = 1 or 2, check if all remain padding is space
while ((ch = *srcBytes++) && (srcLen-- > 0)) {
if (!ZYJQN_IsSpace(ch)) {
return 0;
}
}
}
} else {
// We ended by seeing the end of the string.
if (requirePadding) {
// If we require padding, then anything but state 0 is an error.
if (state != 0) {
return 0;
}
} else {
// Make sure we have no partial bytes lying around. Note that we do not
// require trailing '=', so states 2 and 3 are okay too.
if (state == 1) {
return 0;
}
}
}
// If then next piece of output was valid and got written to it means we got a
// very carefully crafted input that appeared valid but contains some trailing
// bits past the real length, so just toss the thing.
if ((destIndex < destLen) &&
(destBytes[destIndex] != 0)) {
return 0;
}
return destIndex;
}
@end
//
//
// ZYJQiniuSDK.h
// ZYJQiniuSDK
//
// Created by bailong on 14-9-28.
// Copyright (c) 2014年 Qiniu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZYJQNFixedZone.h"
#import "ZYJQNAutoZone.h"
#import "ZYJQNConfiguration.h"
#import "ZYJQNFileRecorder.h"
#import "ZYJQNResponseInfo.h"
#import "ZYJQNHttpResponseInfo.h"
#import "ZYJQNUploadManager.h"
#import "ZYJQNUploadOption.h"
#import "ZYJQNUrlSafeBase64.h"
#import "ZYJQNUploadInfoReporter.h"
#import "ZYJQNPipeline.h"
//
//
......@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
+(OffcnUploadManager *)defaultService;
-(void)uploadToQNFilePath:(NSString *)filePath Finished:(void(^)(BOOL success,id response,NSString *errorMessage))finished;
-(void)uploadToQNFilePath:(NSString *)filePath Finished:(void(^)(BOOL success,id response,NSString *errorMessage))finished ProgressPercent:(void(^)(NSString *key, float percent))progressPercent;
@end
NS_ASSUME_NONNULL_END
//
//
......@@ -7,13 +7,13 @@
//
#import "OffcnUploadManager.h"
#import <QiniuSDK.h>
#import "QNTransactionManager.h"
#import "ZYJQiniuSDK.h"
#import "ZYJQNTransactionManager.h"
#import "OffcnNetworkExecutor.h"
@interface OffcnUploadManager ()
@property (nonatomic, strong) QNUploadManager *upManager;
@property (nonatomic, strong) ZYJQNUploadManager *upManager;
@property (nonatomic, strong) NSString *QNToken;
@end
......@@ -30,18 +30,21 @@ static OffcnUploadManager *uploadManager;
-(instancetype)init{
self = [super init];
if (self) {
self.upManager = [[QNUploadManager alloc] init];
self.upManager = [[ZYJQNUploadManager alloc] init];
}
return self;
}
-(void)uploadToQNFilePath:(NSString *)filePath Finished:(void(^)(BOOL success,id response,NSString *errorMessage))finished{
-(void)uploadToQNFilePath:(NSString *)filePath Finished:(void(^)(BOOL success,id response,NSString *errorMessage))finished ProgressPercent:(void(^)(NSString *key, float percent))progressPercent{
__weak typeof(self) weakSelf = self;
if (self.QNToken) {
[self uploadToQNWithQNToken:self.QNToken filePath:filePath Finished:^(BOOL success, id response, NSString *errorMessage) {
finished(success,response,errorMessage);
} ProgressPercent:^(NSString *key, float percent) {
progressPercent(key,percent);
}];
}else{
[self getQNTokenFinished:^(BOOL success, NSString *errorMessage) {
......@@ -49,6 +52,9 @@ static OffcnUploadManager *uploadManager;
[weakSelf uploadToQNWithQNToken:weakSelf.QNToken filePath:filePath Finished:^(BOOL success, id response, NSString *errorMessage) {
finished(success,response,errorMessage);
} ProgressPercent:^(NSString *key, float percent) {
progressPercent(key,percent);
}];
}else{
finished(NO,nil,errorMessage);
......@@ -64,7 +70,7 @@ static OffcnUploadManager *uploadManager;
if (success) {
NSString *token = [NSString stringWithFormat:@"%@",response];
weakSelf.QNToken = token;
NSLog(@"七牛token---%@",token);
// NSLog(@"七牛token---%@",token);
finished(YES,nil);
}else{
finished(NO,@"获取token失败");
......@@ -72,15 +78,16 @@ static OffcnUploadManager *uploadManager;
}];
}
-(void)uploadToQNWithQNToken:(NSString *)QNToken filePath:(NSString *)filePath Finished:(void(^)(BOOL success,id response,NSString *errorMessage))finished{
QNUploadOption *uploadOption = [[QNUploadOption alloc] initWithMime:nil progressHandler:^(NSString *key, float percent) {
NSLog(@"percent == %.2f", percent);
-(void)uploadToQNWithQNToken:(NSString *)QNToken filePath:(NSString *)filePath Finished:(void(^)(BOOL success,id response,NSString *errorMessage))finished ProgressPercent:(void(^)(NSString *key, float percent))progressPercent{
ZYJQNUploadOption *uploadOption = [[ZYJQNUploadOption alloc] initWithMime:nil progressHandler:^(NSString *key, float percent) {
progressPercent(key,percent);
}params:nil checkCrc:NO cancellationSignal:nil];
[self.upManager putFile:filePath key:nil token:QNToken complete:^(QNResponseInfo *info, NSString *key, NSDictionary *resp) {
NSLog(@"info ===== %@", info);
NSLog(@"key ===== %@", key);
NSLog(@"resp ===== %@", resp);
[self.upManager putFile:filePath key:nil token:QNToken complete:^(ZYJQNResponseInfo *info, NSString *key, NSDictionary *resp) {
// NSLog(@"info ===== %@", info);
// NSLog(@"key ===== %@", key);
// NSLog(@"resp ===== %@", resp);
if (resp) {
//发送消息
......
......@@ -132,6 +132,9 @@
}else{
[weakSelf tipMessageWithTitle:@"发送消息失败" message:errorMessage];
}
} ProgressPercent:^(NSString *key, float percent) {
NSLog(@"key == %@,percent == %.2f", key,percent);
}];
}
- (IBAction)noReadListAction:(UIButton *)sender {
......@@ -266,6 +269,9 @@
}else{
[weakSelf tipMessageWithTitle:@"上传失败" message:errorMessage];
}
} ProgressPercent:^(NSString *key, float percent) {
NSLog(@"key == %@,percent == %.2f", key,percent);
}];
}
- (IBAction)uploadFile:(UIButton *)sender {
......@@ -279,6 +285,9 @@
}else{
[weakSelf tipMessageWithTitle:@"上传失败" message:errorMessage];
}
} ProgressPercent:^(NSString *key, float percent) {
NSLog(@"key == %@,percent == %.2f", key,percent);
}];
}
......
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