338 lines
9.4 KiB
Swift
338 lines
9.4 KiB
Swift
//
|
||
// UploadModels.swift
|
||
// Crush
|
||
//
|
||
// Created by Leon on 2025/7/21.
|
||
//
|
||
|
||
import Foundation
|
||
import AWSS3
|
||
|
||
// MARK: - Protocols
|
||
|
||
protocol UploadPhotoCallBackProtocol {
|
||
func mm_uploadProgress(_ progress: Float)
|
||
func mm_uploadFailed()
|
||
func mm_uploadDone(_ remoteImageUrlString: String)
|
||
}
|
||
|
||
protocol UploadPhotoDelegate: AnyObject {
|
||
|
||
// func uploadFail()
|
||
// func uploadDone()
|
||
func uploadDoneWith(_ photo: UploadPhotoM)
|
||
func uploadFailWith(_ photo: UploadPhotoM)
|
||
func uploadProgress(_ progress: Float)
|
||
func imageCheck(_ photoM: UploadPhotoM, result: Bool)
|
||
// func imageIdentyReal(_ photo: UploadPhotoM, result: Bool)
|
||
// func imageIdentifyChild(_ photo: UploadPhotoM, result: Bool)
|
||
// func imageFullCheck(_ photo: UploadPhotoM, nfswCheck: Bool, realPersonCheck: Bool)
|
||
// func imageFullCheck(_ photo: UploadPhotoM, nfswCheck: Bool, childCheck: Bool)
|
||
}
|
||
|
||
protocol UploadModelDelegate: AnyObject {
|
||
|
||
func uploadFail()
|
||
func uploadDone()
|
||
func uploadDoneWith(_ photo: UploadModel)
|
||
func uploadFailWith(_ photo: UploadModel)
|
||
func uploadProgress(_ progress: Float)
|
||
}
|
||
|
||
// MARK: - UploadEntity
|
||
|
||
class UploadEntity: NSObject, UploadPhotoCallBackProtocol {
|
||
func mm_uploadProgress(_ progress: Float) {
|
||
|
||
}
|
||
|
||
func mm_uploadFailed() {
|
||
|
||
}
|
||
|
||
func mm_uploadDone(_ remoteImageUrlString: String) {
|
||
|
||
}
|
||
|
||
weak var utility: AWSS3TransferUtility?
|
||
var addThisItemTimeStamp: Int = 0
|
||
var uploadProgress: Float = 0.0
|
||
var isFailed: Bool = false
|
||
var isDone: Bool = false
|
||
var isUploading: Bool = false
|
||
}
|
||
|
||
// MARK: - UploadModel
|
||
|
||
class UploadModel: UploadEntity {
|
||
var fileData: Data?
|
||
var s3AuthData: S3AuthData?
|
||
/// 一般是不含域名的部分链接
|
||
var remoteImageUrlString: String?
|
||
var remoteFullPath: String?
|
||
weak var delegate: UploadModelDelegate?
|
||
|
||
func suffix() -> String {
|
||
return ".mp3"
|
||
}
|
||
|
||
func contentType() -> String {
|
||
return "audio/mp3"
|
||
}
|
||
|
||
func releaseS3Utility() {
|
||
if let utility = utility, let _ = s3AuthData?.fileName {
|
||
//#warning("Confirm")
|
||
//AWSS3TransferUtility.removeS3TransferUtility(forKey: fileName)
|
||
utility.cancelAll()
|
||
}
|
||
}
|
||
|
||
// MARK: - Setter Overrides
|
||
override var uploadProgress: Float {
|
||
get { super.uploadProgress }
|
||
set {
|
||
super.uploadProgress = newValue
|
||
delegate?.uploadProgress(newValue)
|
||
}
|
||
}
|
||
|
||
override var isDone: Bool {
|
||
get { super.isDone }
|
||
set {
|
||
super.isDone = newValue
|
||
delegate?.uploadDoneWith(self)
|
||
delegate?.uploadDone()
|
||
}
|
||
}
|
||
|
||
override var isFailed: Bool {
|
||
get { super.isFailed }
|
||
set {
|
||
super.isFailed = newValue
|
||
delegate?.uploadFailWith(self)
|
||
delegate?.uploadFail()
|
||
}
|
||
}
|
||
|
||
// MARK: - UploadPhotoCallBackProtocol
|
||
override func mm_uploadProgress(_ progress: Float) {
|
||
self.uploadProgress = progress
|
||
}
|
||
|
||
override func mm_uploadFailed() {
|
||
releaseS3Utility()
|
||
isFailed = true
|
||
isUploading = false
|
||
}
|
||
|
||
override func mm_uploadDone(_ remoteImageUrlString: String) {
|
||
releaseS3Utility()
|
||
self.remoteImageUrlString = remoteImageUrlString
|
||
isDone = true
|
||
isUploading = false
|
||
}
|
||
}
|
||
|
||
// MARK: - UploadPhotoM
|
||
|
||
class UploadPhotoM: UploadEntity {
|
||
weak var delegate: UploadPhotoDelegate?
|
||
|
||
// MARK: Data
|
||
var image: UIImage?{
|
||
didSet{
|
||
if image?.size.width ?? 0 > 0 && image?.size.height ?? 0 > 0{
|
||
imageSize = image!.pixelSize
|
||
}
|
||
}
|
||
}
|
||
var imageData: Data?
|
||
var bucketEnum: BucketS3Enum = .UNKNOW
|
||
var s3AuthData: S3AuthData?
|
||
/// 一般是不含域名的部分链接
|
||
var remoteImageUrlString: String?
|
||
/// 文件全路径、含域名
|
||
var remoteFullPath: String?
|
||
var imageSize: CGSize = .zero
|
||
var suffixEnum: SuffixS3Enum = .jpeg
|
||
|
||
// MARK: Config
|
||
/// -- Config: Default true: 默认需要鉴黄
|
||
var isAutoCheckImage: Bool = true
|
||
var isHideCheckToast: Bool = false
|
||
|
||
// MARK: State
|
||
private(set) var imageCheckIsViolation: Bool = false
|
||
/// Default false
|
||
private(set) var imageChecked: Bool = false
|
||
private(set) var isOverSizeLimmit: Bool = false
|
||
private(set) var errorMsg: String?
|
||
var imageFrame: CGRect = .zero
|
||
var isEditMode: Bool = false
|
||
|
||
|
||
// MARK: Inner methods
|
||
/// true: 禁止在delegate(UploadPhotoDelegate)回调中鉴黄。 在CloudStorage中block判断和鉴黄。自动管理,上传时不需要设置
|
||
var banCheckImageInDelegateMethod: Bool = false
|
||
|
||
override init() {
|
||
super.init()
|
||
suffixEnum = .jpeg
|
||
}
|
||
|
||
// MARK: - Public Methods
|
||
func getFullUrlString() -> String {
|
||
if let fullUrl = remoteFullPath, fullUrl.count > 0 {
|
||
return fullUrl
|
||
}else if let remoteImageFull = remoteImageUrlString{
|
||
return remoteImageFull // .fullUrlFromRelativePath // ⚠️这个路径不是全路径,需要拼接一个域名,暂时不会走到此分支!
|
||
}
|
||
return ""
|
||
}
|
||
|
||
func setupValidImageUrl(url: String?){
|
||
guard let imgUrl = url else{return}
|
||
remoteFullPath = imgUrl
|
||
isDone = true
|
||
imageChecked = true
|
||
addThisItemTimeStamp = Date().timeStamp
|
||
}
|
||
|
||
/// block返回 false,表示不是黄图
|
||
func checkImageOK(_ block: ((Bool) -> Void)? = nil) {
|
||
guard let tempPath = remoteImageUrlString, tempPath.isNotBlank else {
|
||
assert(false)
|
||
block?(false)
|
||
return
|
||
}
|
||
|
||
OssProvider.request(.nsfwCheck(fileFullPath: tempPath, s3BucketEnum: bucketEnum.rawValue), modelType: Bool.self) {[weak self] result in
|
||
guard let `self` = self else {
|
||
return
|
||
}
|
||
self.isUploading = false
|
||
switch result {
|
||
case let .success(checkResult):
|
||
self.imageChecked = true
|
||
//self.realateUrlAdpatEPalAddSlash(add: true)
|
||
let nsfw = checkResult ?? true
|
||
let imgOk = !nsfw
|
||
self.delegate?.imageCheck(self, result: imgOk)
|
||
block?(imgOk)
|
||
case let .failure(error):
|
||
switch error {
|
||
case let .serviceError(code, msg):
|
||
if code == .imageCheckFailed{
|
||
self.imageChecked = true
|
||
self.imageCheckIsViolation = true
|
||
self.errorMsg = msg
|
||
self.delegate?.imageCheck(self, result: false)
|
||
}else{
|
||
self.imageCheckIsViolation = false
|
||
self.isFailed = true
|
||
self.isDone = false
|
||
self.delegate?.imageCheck(self, result: false)
|
||
}
|
||
default:
|
||
break
|
||
}
|
||
block?(false)
|
||
}
|
||
}
|
||
}
|
||
|
||
func contentType() -> String {
|
||
switch suffixEnum {
|
||
case .gif: return "image/gif"
|
||
case .png: return "image/png"
|
||
default: return "image/jpeg"
|
||
}
|
||
}
|
||
|
||
func releaseS3Utility() {
|
||
if let utility = utility {
|
||
//AWSS3TransferUtility.removeS3TransferUtility(forKey: fileName)
|
||
utility.cancelAll()
|
||
}
|
||
}
|
||
|
||
func setupPhotoOversizeLimmit() {
|
||
isOverSizeLimmit = true
|
||
}
|
||
|
||
func setupErrorMsg(_ msg: String) {
|
||
errorMsg = msg
|
||
}
|
||
|
||
// MARK: - Setter Overrides
|
||
override var uploadProgress: Float {
|
||
get { super.uploadProgress }
|
||
set {
|
||
super.uploadProgress = newValue
|
||
delegate?.uploadProgress(newValue)
|
||
}
|
||
}
|
||
|
||
override var isDone: Bool {
|
||
get { super.isDone }
|
||
set {
|
||
super.isDone = newValue
|
||
delegate?.uploadDoneWith(self)
|
||
// delegate?.uploadDone()
|
||
}
|
||
}
|
||
|
||
override var isFailed: Bool {
|
||
get { super.isFailed }
|
||
set {
|
||
super.isFailed = newValue
|
||
delegate?.uploadFailWith(self)
|
||
// delegate?.uploadFail()
|
||
}
|
||
}
|
||
|
||
// MARK: - UploadPhotoCallBackProtocol
|
||
override func mm_uploadProgress(_ progress: Float) {
|
||
self.uploadProgress = progress
|
||
}
|
||
|
||
override func mm_uploadFailed() {
|
||
releaseS3Utility()
|
||
isFailed = true
|
||
isUploading = false
|
||
}
|
||
|
||
override func mm_uploadDone(_ remoteImageUrlString: String) {
|
||
releaseS3Utility()
|
||
self.remoteImageUrlString = remoteImageUrlString
|
||
isDone = true
|
||
|
||
if isAutoCheckImage {
|
||
if !banCheckImageInDelegateMethod {
|
||
checkImageOK(nil)
|
||
}
|
||
} else {
|
||
isUploading = false
|
||
realateUrlAdpatEPalAddSlash(add: true)
|
||
}
|
||
}
|
||
|
||
// MARK: - Helper
|
||
@discardableResult
|
||
private func realateUrlAdpatEPalAddSlash(add: Bool) -> String {
|
||
var url = remoteImageUrlString ?? ""
|
||
if add {
|
||
if !url.isEmpty && !url.hasPrefix("/") {
|
||
url = "/\(url)"
|
||
}
|
||
} else {
|
||
if !url.isEmpty && url.hasPrefix("/") {
|
||
url.removeFirst()
|
||
}
|
||
}
|
||
remoteImageUrlString = url
|
||
return url
|
||
}
|
||
}
|