|
@@ -0,0 +1,539 @@
|
|
|
+//
|
|
|
+// PQAliOssUtil.swift
|
|
|
+// PQSpeed
|
|
|
+//
|
|
|
+// Created by SanW on 2020/12/9.
|
|
|
+// Copyright © 2020 BytesFlow. All rights reserved.
|
|
|
+//
|
|
|
+
|
|
|
+import UIKit
|
|
|
+import BFCommonKit
|
|
|
+import BFNetRequestKit
|
|
|
+
|
|
|
+// MARK: - 阿里OSS工具类
|
|
|
+
|
|
|
+/// 阿里OSS工具类
|
|
|
+public class PQAliOssUtil: NSObject {
|
|
|
+ static public let shared = PQAliOssUtil()
|
|
|
+ public var client: OSSClient?
|
|
|
+ // 文件类型:materialType (1:PICTURE, 2:VIDEO, 3:VOICE, 4:FILE, 5:GIF)
|
|
|
+ public var aliOssHander: ((_ isMatarialUpload: Bool, _ materialType: StickerType, _ fileExtensions: String, _ code: Int, _ objectKey: String?, _ contentMD5: String, _ width: CGFloat, _ height: CGFloat, _ duration: CGFloat, _ frameNumber: Int, _ netResourceUrl: String?, _ fileURL: URL?, _ data: Data?, _ msg: String?) -> Void)?
|
|
|
+ public var aliOssProgressHander: ((_ bytesSent: Int64, _ totalBytesSent: Int64, _ totalBytesExpectedToSend: Int64, _ resttime: Int64, _ uploadSpeed: String?) -> Void)?
|
|
|
+ public var lastInterfaceBytes: Int64 = 0 // 上次网速
|
|
|
+ public var oldTime: Int = 0 // 上次进度时间S
|
|
|
+ public var oloaded: Int64 = 0
|
|
|
+ public var dics: [String: Any] = [:]
|
|
|
+
|
|
|
+ public var allTasks: [String: OSSMultipartUploadRequest] = [:] // add by ak 保存当前所有任务 用于取消某个任务使用
|
|
|
+ public func startClient(accessKeyId: String, secretKeyId: String, securityToken: String, endpoint: String) -> PQAliOssUtil {
|
|
|
+ if endpoint.count == 0 {
|
|
|
+ debugPrint("endpoint is nil xxxxxx \(endpoint)")
|
|
|
+ }
|
|
|
+
|
|
|
+ let credential = OSSStsTokenCredentialProvider(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken)
|
|
|
+ let conf = OSSClientConfiguration()
|
|
|
+ conf.timeoutIntervalForRequest = 60 // 连接超时,默认15秒
|
|
|
+ conf.maxRetryCount = 3
|
|
|
+ conf.maxConcurrentRequestCount = 5 // 最大并发请求书,默认5个
|
|
|
+ client = OSSClient(endpoint: endpoint, credentialProvider: credential, clientConfiguration: conf)
|
|
|
+ return .shared
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 图片上传
|
|
|
+ /// - Parameters:
|
|
|
+ /// - bucketName: <#bucketName description#>
|
|
|
+ /// - objectKey: <#objectKey description#>
|
|
|
+ /// - data: <#data description#>
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ public func uploadObjectAsync(bucketName: String, objectKey: String, data: Data, materialType: StickerType = .IMAGE, fileExtensions: String, isMatarialUpload: Bool = false, contentMD5: String = "", width: CGFloat = 0, height: CGFloat = 0, imageUploadBlock: @escaping (_ osstask: OSSTask<AnyObject>?, _ code: Int, _ objectKey: String, _ fileExtensions: String) -> Void) -> PQAliOssUtil {
|
|
|
+ let putRequest: OSSPutObjectRequest = OSSPutObjectRequest()
|
|
|
+ putRequest.bucketName = bucketName
|
|
|
+ putRequest.objectKey = objectKey
|
|
|
+ putRequest.uploadingData = data
|
|
|
+ putRequest.uploadProgress = { [weak self] _, totalByteSent, totalBytesExpectedToSend in
|
|
|
+ debugPrint("文件上传进度:totalByteSent = \(totalByteSent),totalBytesExpectedToSend = \(totalBytesExpectedToSend)")
|
|
|
+ if totalBytesExpectedToSend > 0, totalByteSent == totalBytesExpectedToSend {
|
|
|
+ if isMatarialUpload, self?.aliOssHander != nil {
|
|
|
+ self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, 1, objectKey, contentMD5, width, height, 0, 0, nil, nil, data, "上传成功")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ putRequest.contentType = "application/octet-stream"
|
|
|
+ // putRequest.contentMd5 = contentMD5
|
|
|
+ putRequest.contentEncoding = ""
|
|
|
+ putRequest.contentDisposition = ""
|
|
|
+ let putTask: OSSTask = (client?.putObject(putRequest))!
|
|
|
+ putTask.continue(successBlock: { [weak self] (osstask) -> Any? in
|
|
|
+ if osstask.error == nil {
|
|
|
+ let task = self?.client?.presignPublicURL(withBucketName: putRequest.bucketName, withObjectKey: putRequest.objectKey)
|
|
|
+ debugPrint("图片原方法上传完成=\(objectKey)")
|
|
|
+ debugPrint("url == \(task?.result ?? "" as AnyObject)")
|
|
|
+ imageUploadBlock(osstask, 1, objectKey, fileExtensions)
|
|
|
+ } else {
|
|
|
+ if self?.aliOssHander != nil {
|
|
|
+ self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, 0, objectKey, contentMD5, width, height, 0, 0, nil, nil, data, "上传失败")
|
|
|
+ }
|
|
|
+ debugPrint("图片原方法上传失败=\(objectKey),osstask.error = \(osstask.error ?? PQError(msg: "失败"))")
|
|
|
+ imageUploadBlock(osstask, 0, objectKey, fileExtensions)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+
|
|
|
+ }).waitUntilFinished()
|
|
|
+
|
|
|
+ return .shared
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 快速上传视频
|
|
|
+ /// - Parameters:
|
|
|
+ /// - localPath: <#localPath description#>
|
|
|
+ /// - response: <#response description#>
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ class public func multipartUpload(localPath: String, response: [String: Any]?,videoSource:String? = nil) {
|
|
|
+ let accessKeyId: String = "\(response?["AccessKeyId"] ?? "")"
|
|
|
+ let secretKeyId: String = "\(response?["AccessKeySecret"] ?? "")"
|
|
|
+ let securityToken: String = "\(response?["SecurityToken"] ?? "")"
|
|
|
+ let endpoint: String = "\(response?["Host"] ?? "")"
|
|
|
+ let bucketName: String = "\(response?["Bucket"] ?? "")"
|
|
|
+ let FileName: String = "\(response?["FileName"] ?? "")"
|
|
|
+ let uploadID: String = "\(response?["Upload"] ?? "")"
|
|
|
+ var endpoints: [String] = Array<String>.init()
|
|
|
+ if response?.keys.contains("Hosts") ?? false {
|
|
|
+ endpoints = response?["Hosts"] as! [String]
|
|
|
+ endpoints.append(endpoint)
|
|
|
+ }
|
|
|
+ PQAliOssUtil.shared.PQOSSMultipartUpload(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken, bucketName: bucketName, endpoints: endpoints, FileName: FileName, fileURL: URL(fileURLWithPath: localPath.replacingOccurrences(of: "file:///", with: "")), ossUploadID: uploadID, videoSource: videoSource)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 重新上传
|
|
|
+ /// - Parameters:
|
|
|
+ /// - response: <#response description#>
|
|
|
+ /// - localPath: <#localPath description#>
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ public func reloadTask(response: [String: Any]?, localPath: String?,videoSource:String? = nil) {
|
|
|
+ if response == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let accessKeyId: String = "\(response?["AccessKeyId"] ?? "")"
|
|
|
+ let secretKeyId: String = "\(response?["AccessKeySecret"] ?? "")"
|
|
|
+ let securityToken: String = "\(response?["SecurityToken"] ?? "")"
|
|
|
+ let endpoint: String = "\(response?["Host"] ?? "")"
|
|
|
+ let bucketName: String = "\(response?["Bucket"] ?? "")"
|
|
|
+ let FileName: String = "\(response?["FileName"] ?? "")"
|
|
|
+ let uploadID: String = "\(response?["Upload"] ?? "")"
|
|
|
+ var endpoints: [String] = Array<String>.init()
|
|
|
+ if response?.keys.contains("Hosts") ?? false {
|
|
|
+ endpoints = response?["Hosts"] as! [String]
|
|
|
+ endpoints.append(endpoint)
|
|
|
+ }
|
|
|
+ debugPrint("取我方服务器STS 返回数据 \(String(describing: response))")
|
|
|
+ PQAliOssUtil.shared.PQOSSMultipartUpload(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken, bucketName: bucketName, endpoints: endpoints, FileName: FileName, fileURL: URL(fileURLWithPath: (localPath ?? "").replacingOccurrences(of: "file:///", with: "")), ossUploadID: uploadID,videoSource: videoSource)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 分片上传
|
|
|
+ /// - Parameters:
|
|
|
+ /// - accessKeyId: <#accessKeyId description#>
|
|
|
+ /// - secretKeyId: <#secretKeyId description#>
|
|
|
+ /// - securityToken: <#securityToken description#>
|
|
|
+ /// - bucketName: <#bucketName description#>
|
|
|
+ /// - endpoints: oss host域名
|
|
|
+ /// - FileName: oss 资源地址
|
|
|
+ /// - fileURL: 文件本地地址
|
|
|
+ /// - ossUploadID: oss 上传ID
|
|
|
+ /// - contentType: 文件类型
|
|
|
+ /// - materialType: 素材类型
|
|
|
+ /// - isMatarialUpload: 是否是素材上传
|
|
|
+ /// - contentMD5: 素材内容MD5值 isMatarialUpload = true时传
|
|
|
+ /// - width: 视频宽 isMatarialUpload = true时传
|
|
|
+ /// - height: 视频高 isMatarialUpload = true时传
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ public func PQOSSMultipartUpload(accessKeyId: String, secretKeyId: String, securityToken: String, bucketName: String, endpoints: [String], FileName: String, fileURL: URL, ossUploadID: String, materialType: StickerType = .VIDEO, isMatarialUpload: Bool = false, contentMD5: String = "", width: CGFloat = 0, height: CGFloat = 0,videoSource:String? = nil) -> PQAliOssUtil {
|
|
|
+ debugPrint("上传数据 参数\n accessKeyId:\(accessKeyId)\n secretKeyId:\(secretKeyId)\n securityToken:\(securityToken) \n bucketName:\(bucketName)\n endpoint:\(endpoints)\n FileName:\(FileName)")
|
|
|
+ if endpoints.count <= 0 || (endpoints.first?.count ?? 0) <= 0 {
|
|
|
+ debugPrint("endpoints 为空")
|
|
|
+ return .shared
|
|
|
+ }
|
|
|
+ #if DEBUG
|
|
|
+ // 打开 oss 日志
|
|
|
+ OSSLog.enable()
|
|
|
+ #endif
|
|
|
+
|
|
|
+ // 1,设置鉴权
|
|
|
+ let url = PQENVUtil.shared.longvideoapi + (isMatarialUpload ? materialUploadStsTokenUrl : getStsTokenUrl)
|
|
|
+
|
|
|
+ let authServerUrl = url + "?appType=\(commonParams()["appType"] as? String ?? "")" + "&machineCode=" + getMachineCode()
|
|
|
+ + "&token=" + (BFConfig.shared.token ?? "") + "&loginUid" + (BFConfig.shared.uid ?? "") + "&fileType=2" + "&uploadId=\(ossUploadID)"
|
|
|
+ debugPrint("authServerUrl is: \(authServerUrl)")
|
|
|
+ debugPrint("当前上传authServerUrl线程:\(Thread.isMainThread) ")
|
|
|
+
|
|
|
+ let provider = OSSAuthCredentialProvider(authServerUrl: authServerUrl) { (data) -> Data? in
|
|
|
+ debugPrint("当前上传provider线程:\(Thread.isMainThread) ")
|
|
|
+ // 在 OSSModel 代码中解析有自己的格式 所以接收到我方服务器后的数据要进行二次处理 AccessKeyId 等信息
|
|
|
+ let str = String(data: data, encoding: .utf8)
|
|
|
+ let jsonDic = jsonStringToDictionary(str!)
|
|
|
+ var respDic: [String: Any] = [:]
|
|
|
+ if jsonDic?.keys.contains("code") ?? false, "\(jsonDic?["code"] ?? "")" == "0" {
|
|
|
+ respDic = [
|
|
|
+ "StatusCode": "200",
|
|
|
+ "AccessKeyId": (jsonDic?["data"] as? [String: Any])?["AccessKeyId"] ?? accessKeyId,
|
|
|
+ "AccessKeySecret": (jsonDic?["data"] as? [String: Any])?["AccessKeySecret"] ?? secretKeyId,
|
|
|
+ "SecurityToken": (jsonDic?["data"] as? [String: Any])?["SecurityToken"] ?? securityToken,
|
|
|
+ "Expiration": (jsonDic?["data"] as? [String: Any])?["Expiration"] ?? securityToken,
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ let proStr = dictionaryToJsonString(respDic as [String: Any])
|
|
|
+ debugPrint("处理后准备给 OSS SDK数据 \(String(describing: proStr))")
|
|
|
+ let decodedData = proStr?.data(using: .utf8)
|
|
|
+ if decodedData != nil {
|
|
|
+ return decodedData
|
|
|
+ }
|
|
|
+ return data
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2 拼装 request
|
|
|
+ let request = OSSMultipartUploadRequest()
|
|
|
+ // add by ak set contect type . doc https://help.aliyun.com/knowledge_detail/39522.html
|
|
|
+ request.contentType = fileURL.absoluteString.mimeType() // 媒体类型
|
|
|
+ request.uploadingFileURL = fileURL
|
|
|
+ request.bucketName = bucketName
|
|
|
+ request.objectKey = FileName
|
|
|
+ // 根据文件大小 设置 part size
|
|
|
+ var fileSize: UInt64 = 0
|
|
|
+ do {
|
|
|
+ let attr = try FileManager.default.attributesOfItem(atPath: fileURL.relativePath)
|
|
|
+ fileSize = attr[FileAttributeKey.size] as! UInt64
|
|
|
+
|
|
|
+ } catch {
|
|
|
+ debugPrint("取文件大小 Error: \(error)")
|
|
|
+ if aliOssHander != nil {
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ self?.aliOssHander!(isMatarialUpload, materialType, fileURL.absoluteString.pathExtension, 260, FileName, contentMD5, width, height, 0, 0, nil, fileURL, nil, "文件已丢失")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ debugPrint("文件已经存在 \(fileURL) 文件大小 \(fileSize)")
|
|
|
+ var partSize: Int = 0
|
|
|
+ // sdk中规定kClientMaximumOfChunks = 5000;
|
|
|
+ let defaultChunkSize: UInt64 = 1024 * 1024
|
|
|
+ if ceil(Float(fileSize / defaultChunkSize)) <= 1 {
|
|
|
+ partSize = 500 * 1024
|
|
|
+ } else if ceil(Float(fileSize / defaultChunkSize)) < 5000 {
|
|
|
+ partSize = Int(fileSize / UInt64(ceil(Float(fileSize / defaultChunkSize))))
|
|
|
+ } else {
|
|
|
+ partSize = Int(ceil(Float(fileSize / 5000)))
|
|
|
+ }
|
|
|
+ debugPrint("partSize \(partSize)")
|
|
|
+ // 除最后一片外 不能小于 102400(100kb)
|
|
|
+ request.partSize = UInt(partSize)
|
|
|
+ request.uploadId = ossUploadID
|
|
|
+ request.uploadProgress = { [weak self] (bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) -> Void in
|
|
|
+ debugPrint("当前上传uploadProgress线程:\(Thread.isMainThread) ")
|
|
|
+ self?.paraseSpeedAndRestTime(bytesSent: bytesSent, totalBytesSent: totalBytesSent, totalBytesExpectedToSend: totalBytesExpectedToSend) { uploadSpeed, resttime in
|
|
|
+ if self?.aliOssProgressHander != nil {
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ self?.aliOssProgressHander!(bytesSent, totalBytesSent, totalBytesExpectedToSend, resttime, uploadSpeed)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 多个界面都要处理上传进度 所以使用通知 ? 通知有回到主线?
|
|
|
+ // postNotification(name: cOSSUploadFileProgress,userInfo: ["bytesSent":bytesSent,"totalBytesSent":totalBytesSent,"totalBytesExpectedToSend":totalBytesExpectedToSend,"resttime":resttime])
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3,设置 config
|
|
|
+ let conf = OSSClientConfiguration()
|
|
|
+ conf.timeoutIntervalForRequest = 30 // 连接超时,默认15秒
|
|
|
+ conf.maxConcurrentRequestCount = 5 // 最大并发请求书,默认5个
|
|
|
+ conf.maxRetryCount = 3 // 失败后最大重试次数,默认2次
|
|
|
+ // 打开后台上传
|
|
|
+ conf.enableBackgroundTransmitService = true
|
|
|
+ conf.backgroundSesseionIdentifier = getUniqueId(desc: "\(ossUploadID)\(fileURL.absoluteString)\(FileName)")
|
|
|
+ // 4,设置 clinet
|
|
|
+ let client = OSSClient(endpoint: endpoints[0], credentialProvider: provider, clientConfiguration: conf)
|
|
|
+ if !isMatarialUpload {
|
|
|
+ allTasks[FileName] = request
|
|
|
+ }
|
|
|
+ // 5,发起任务
|
|
|
+ let task = client.multipartUpload(request)
|
|
|
+
|
|
|
+ task.continue ({ [weak self] (osstask) -> Any? in
|
|
|
+ debugPrint("当前上传线程:\(Thread.isMainThread) ")
|
|
|
+ if osstask.error == nil {
|
|
|
+ debugPrint("上传成功")
|
|
|
+ // 文件URL的格式为:BucketName.Endpoint/ObjectName。
|
|
|
+ debugPrint(" 上传成功注意使用时拼接域名 url == \(FileName)")
|
|
|
+ request.callbackParam = ["code": 1, "objectKey": FileName, "msg": "上传成功"]
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ if self?.aliOssHander != nil {
|
|
|
+ self?.aliOssHander!(isMatarialUpload, materialType, fileURL.absoluteString.pathExtension, 1, FileName, contentMD5, width, height, 0, 0, nil, fileURL, nil, "上传成功")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果在后台发送上传成功的本地通知
|
|
|
+ if !isMatarialUpload {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ if UIApplication.shared.applicationState == .background {
|
|
|
+ sendUploadNotification(isSuccess: true)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ postNotification(name: cUploadSuccessKey, userInfo: ["code": 1, "objectKey": FileName, "msg": "上传成功"])
|
|
|
+ }
|
|
|
+ // 上传完成
|
|
|
+ var extParams:Dictionary<String,Any>?
|
|
|
+ if videoSource != nil && (videoSource?.count ?? 0) > 0 {
|
|
|
+ extParams = ["source":videoSource ?? ""]
|
|
|
+ }
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_success, pageSource: nil,extParams: extParams, remindmsg: "上传相关")
|
|
|
+ } else {
|
|
|
+ debugPrint("上传失败 \(osstask.error!)")
|
|
|
+
|
|
|
+ request.callbackParam = ["code": (osstask.error! as NSError).code, "objectKey": FileName, "msg": osstask.error?.localizedDescription ?? ""]
|
|
|
+ if self?.aliOssHander != nil {
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ self?.aliOssHander!(isMatarialUpload, materialType, fileURL.absoluteString.pathExtension, (osstask.error! as NSError).code, FileName, contentMD5, width, height, 0, 0, nil, fileURL, nil, osstask.error?.localizedDescription)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果在后台发送上传失败的本地通知
|
|
|
+ if !isMatarialUpload {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ if UIApplication.shared.applicationState == .background {
|
|
|
+ sendUploadNotification(isSuccess: false)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 上传失败
|
|
|
+ var extParams:Dictionary<String,Any>?
|
|
|
+ if videoSource != nil && (videoSource?.count ?? 0) > 0 {
|
|
|
+ extParams = ["source":videoSource ?? ""]
|
|
|
+ }
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_fail, pageSource: nil,extParams: extParams, remindmsg: "上传相关")
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ // 开始上传
|
|
|
+ var extParams:Dictionary<String,Any>?
|
|
|
+ if videoSource != nil && (videoSource?.count ?? 0) > 0 {
|
|
|
+ extParams = ["source":videoSource ?? ""]
|
|
|
+ }
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_start, pageSource: .sp_upload_coverSelect,extParams: extParams, remindmsg: "上传相关")
|
|
|
+ return .shared
|
|
|
+ }
|
|
|
+
|
|
|
+ /// add by ak 简单上传方式 本方法支持后台运行 设置支持后台时会把 DATA
|
|
|
+ /// - Parameters:
|
|
|
+ /// - accessKeyId: <#accessKeyId description#>
|
|
|
+ /// - secretKeyId: <#secretKeyId description#>
|
|
|
+ /// - securityToken: <#securityToken description#>
|
|
|
+ /// - bucketName: <#bucketName description#>
|
|
|
+ /// - endpoint: oss host域名
|
|
|
+ /// - objectKey: oss 资源地址
|
|
|
+ /// - fileURL: 文件本地地址
|
|
|
+ /// - data: 文件数据
|
|
|
+ /// - fileExtensions: 文件后缀名 mp4/mp3
|
|
|
+ /// - enableBackground: 是否支持后台下载
|
|
|
+ /// - materialType: 素材类型
|
|
|
+ /// - isMatarialUpload: 是否是素材上传
|
|
|
+ /// - contentMD5: 素材内容MD5值 isMatarialUpload = true时传
|
|
|
+ /// - width: 视频宽 isMatarialUpload = true时传
|
|
|
+ /// - height: 视频高 isMatarialUpload = true时传
|
|
|
+ /// - duration: 素材时长 isMatarialUpload = true时传
|
|
|
+ /// - frameNumber: gif素材帧数 isMatarialUpload = true时传
|
|
|
+ /// - netResourceUrl: 网络素材地址 isMatarialUpload = true时传
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ public func putObjectAsync(accessKeyId: String, secretKeyId: String, securityToken: String, bucketName: String, endpoint: [String], objectKey: String, fileURL: URL?, data: Data?, fileExtensions: String, enableBackground: Bool, materialType: StickerType = .VIDEO, isMatarialUpload: Bool = false, contentMD5: String = "", width: CGFloat = 0, height: CGFloat = 0, duration: CGFloat, frameNumber: Int, netResourceUrl: String? = nil,videoSource:String? = nil) -> PQAliOssUtil {
|
|
|
+ #if DEBUG
|
|
|
+ OSSLog.enable()
|
|
|
+ #endif
|
|
|
+ debugPrint("普通上传数据 参数 accessKeyId:\(accessKeyId) secretKeyId:\(secretKeyId) securityToken:\(securityToken) bucketName:\(bucketName) endpoint:\(endpoint) objectKey:\(objectKey) enableBackground:\(enableBackground) fileURL : \(fileURL!)")
|
|
|
+ if endpoint.count <= 0 || (endpoint.first?.count ?? 0) <= 0 {
|
|
|
+ debugPrint("endpoints 为空")
|
|
|
+ return .shared
|
|
|
+ }
|
|
|
+ let provider = OSSStsTokenCredentialProvider(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken)
|
|
|
+// let configuration = OSSClientConfiguration()
|
|
|
+// if enableBackground {
|
|
|
+// configuration.enableBackgroundTransmitService = true
|
|
|
+// configuration.backgroundSesseionIdentifier = objectKey
|
|
|
+// }
|
|
|
+// configuration.timeoutIntervalForRequest = 60 // 连接超时,默认15秒
|
|
|
+// configuration.maxConcurrentRequestCount = 20 // 最大并发请求书,默认5个
|
|
|
+// configuration.maxRetryCount = 3 // 失败后最大重试次数,默认2次
|
|
|
+ startClient(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken, endpoint: endpoint.first ?? "")
|
|
|
+ let request = OSSPutObjectRequest()
|
|
|
+ if fileURL != nil {
|
|
|
+ request.uploadingFileURL = fileURL!
|
|
|
+ request.contentType = fileURL!.absoluteString.mimeType() // 媒体类型
|
|
|
+ } else if data != nil {
|
|
|
+ request.uploadingData = data!
|
|
|
+ request.contentType = materialType.mimeType() // 媒体类型
|
|
|
+ }
|
|
|
+ request.bucketName = bucketName
|
|
|
+ request.objectKey = objectKey
|
|
|
+ // request.contentMd5 = contentMD5
|
|
|
+ request.uploadProgress = { (bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) -> Void in
|
|
|
+ var resttime: Int64 = 0
|
|
|
+ if self.oldTime == 0 {
|
|
|
+ self.oldTime = Int(Date().timeIntervalSince1970)
|
|
|
+ }
|
|
|
+ let nowTime = Int(Date().timeIntervalSince1970)
|
|
|
+ let pertime = Int(nowTime - self.oldTime)
|
|
|
+ if pertime != 0 {
|
|
|
+ var speed = totalBytesSent / Int64(pertime) // 单位b/s
|
|
|
+ if speed != 0 {
|
|
|
+ resttime = ((totalBytesExpectedToSend - totalBytesSent) / speed)
|
|
|
+
|
|
|
+ var units = "b/s" // 单位名称
|
|
|
+ if speed / 1024 > 1 {
|
|
|
+ speed = speed / 1024
|
|
|
+ units = "k/s"
|
|
|
+ }
|
|
|
+ if speed / 1024 > 1 {
|
|
|
+ speed = speed / 1024
|
|
|
+ units = "M/s"
|
|
|
+ }
|
|
|
+ debugPrint("上传速度: \(speed)\(units) 还剩时间 \(resttime)")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 多个界面都要处理上传进度 所以使用通知 ? 通知有回到主线?
|
|
|
+ postNotification(name: cOSSUploadFileProgress, userInfo: ["bytesSent": bytesSent, "totalBytesSent": totalBytesSent, "totalBytesExpectedToSend": totalBytesExpectedToSend, "resttime": resttime])
|
|
|
+ }
|
|
|
+ let task = client?.putObject(request)
|
|
|
+ if fileURL?.absoluteString.contains("_noise_") ?? false {
|
|
|
+ task?.continue ({ [weak self] (osstask) -> Any? in
|
|
|
+ debugPrint("当前上传线程:\(Thread.isMainThread) ")
|
|
|
+ if osstask.error == nil {
|
|
|
+ debugPrint("上传成功")
|
|
|
+ // 文件URL的格式为:BucketName.Endpoint/ObjectName。
|
|
|
+ debugPrint(" 上传成功注意使用时拼接域名 url == \(objectKey)")
|
|
|
+ request.callbackParam = ["code": 1, "objectKey": objectKey, "msg": "上传成功"]
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ if self?.aliOssHander != nil {
|
|
|
+ self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, 1, objectKey, contentMD5, width, height, duration, frameNumber, netResourceUrl, fileURL, data, "上传成功")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果在后台发送上传成功的本地通知
|
|
|
+ if !isMatarialUpload {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ if UIApplication.shared.applicationState == .background {
|
|
|
+ sendUploadNotification(isSuccess: true)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ postNotification(name: cUploadSuccessKey, userInfo: ["code": 1, "objectKey": objectKey, "msg": "上传成功"])
|
|
|
+ }
|
|
|
+ // 上传完成
|
|
|
+ var extParams:Dictionary<String,Any>?
|
|
|
+ if videoSource != nil && (videoSource?.count ?? 0) > 0 {
|
|
|
+ extParams = ["source":videoSource ?? ""]
|
|
|
+ }
|
|
|
+ // 上传完成
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_success, pageSource: nil,extParams: extParams, remindmsg: "上传相关")
|
|
|
+ } else {
|
|
|
+ debugPrint("上传失败 \(osstask.error!)")
|
|
|
+ request.callbackParam = ["code": (osstask.error! as NSError).code, "objectKey": objectKey, "msg": osstask.error?.localizedDescription ?? ""]
|
|
|
+ if self?.aliOssHander != nil {
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, (osstask.error! as NSError).code, objectKey, contentMD5, width, height, duration, frameNumber, netResourceUrl, fileURL, data, osstask.error?.localizedDescription)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果在后台发送上传失败的本地通知
|
|
|
+ if !isMatarialUpload {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ if UIApplication.shared.applicationState == .background {
|
|
|
+ sendUploadNotification(isSuccess: false)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 上传失败
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_fail, pageSource: nil, remindmsg: "上传相关")
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ }).waitUntilFinished()
|
|
|
+ } else {
|
|
|
+ task?.continue ({ [weak self] (osstask) -> Any? in
|
|
|
+ debugPrint("当前上传线程:\(Thread.isMainThread) ")
|
|
|
+ if osstask.error == nil {
|
|
|
+ debugPrint("上传成功")
|
|
|
+ // 文件URL的格式为:BucketName.Endpoint/ObjectName。
|
|
|
+ debugPrint(" 上传成功注意使用时拼接域名 url == \(objectKey)")
|
|
|
+ request.callbackParam = ["code": 1, "objectKey": objectKey, "msg": "上传成功"]
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ if self?.aliOssHander != nil {
|
|
|
+ self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, 1, objectKey, contentMD5, width, height, duration, frameNumber, netResourceUrl, fileURL, data, "上传成功")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果在后台发送上传成功的本地通知
|
|
|
+ if !isMatarialUpload {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ if UIApplication.shared.applicationState == .background {
|
|
|
+ sendUploadNotification(isSuccess: true)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ postNotification(name: cUploadSuccessKey, userInfo: ["code": 1, "objectKey": objectKey, "msg": "上传成功"])
|
|
|
+ }
|
|
|
+ // 上传完成
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_success, pageSource: nil, remindmsg: "上传相关")
|
|
|
+ } else {
|
|
|
+ debugPrint("上传失败 \(osstask.error!)")
|
|
|
+ request.callbackParam = ["code": (osstask.error! as NSError).code, "objectKey": objectKey, "msg": osstask.error?.localizedDescription ?? ""]
|
|
|
+ if self?.aliOssHander != nil {
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, (osstask.error! as NSError).code, objectKey, contentMD5, width, height, duration, frameNumber, netResourceUrl, fileURL, data, osstask.error?.localizedDescription)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果在后台发送上传失败的本地通知
|
|
|
+ if !isMatarialUpload {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ if UIApplication.shared.applicationState == .background {
|
|
|
+ sendUploadNotification(isSuccess: false)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 上传失败
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_fail, pageSource: nil, remindmsg: "上传相关")
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return .shared
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 取消某个任务
|
|
|
+ /// - Parameter objectKey: 任务唯一标识
|
|
|
+ public func putObjectCancel(objectKey: String) {
|
|
|
+ for key in allTasks.keys {
|
|
|
+ if key == objectKey {
|
|
|
+ allTasks[key]!.cancel()
|
|
|
+ allTasks.removeValue(forKey: key)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 解析上传速度及剩余时间
|
|
|
+ /// - Parameters:
|
|
|
+ /// - bytesSent: <#bytesSent description#>
|
|
|
+ /// - totalBytesSent: <#totalBytesSent description#>
|
|
|
+ /// - totalBytesExpectedToSend: <#totalBytesExpectedToSend description#>
|
|
|
+ /// - complateHandle: <#complateHandle description#>
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ public func paraseSpeedAndRestTime(bytesSent _: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64, complateHandle: (_ uploadSpeed: String, _ resttime: Int64) -> Void) {
|
|
|
+ let newInterfaceBytes = PQBridgeObject.getInterfaceBytes()
|
|
|
+ var interfaceBytes = abs(newInterfaceBytes - lastInterfaceBytes)
|
|
|
+ if interfaceBytes <= 0 {
|
|
|
+ interfaceBytes = 1
|
|
|
+ }
|
|
|
+ lastInterfaceBytes = newInterfaceBytes
|
|
|
+ let resttime = (totalBytesExpectedToSend - totalBytesSent) / interfaceBytes
|
|
|
+ debugPrint("interfaceBytes = \(interfaceBytes),totalBytesExpectedToSend = \(totalBytesExpectedToSend),totalBytesSent = \(totalBytesSent),")
|
|
|
+ complateHandle("\(PQBridgeObject.formatNetWork(interfaceBytes))", resttime)
|
|
|
+ }
|
|
|
+
|
|
|
+ override private init() {
|
|
|
+ super.init()
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func copy() -> Any {
|
|
|
+ return self
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func mutableCopy() -> Any {
|
|
|
+ return self
|
|
|
+ }
|
|
|
+}
|