Files

86 lines
2.7 KiB
Swift

//
// TravelAlbumOTGUploader.swift
// suixinkan
//
import Foundation
/// 旅拍相册 OTG 上传服务协议。
@MainActor
protocol TravelAlbumOTGUploading {
/// 上传本地照片并登记为旅拍相册素材。
func upload(
record: TravelAlbumOTGPhotoRecord,
scenicId: Int,
progress: @escaping (Int) -> Void
) async throws -> TravelAlbumMaterial
}
/// 旅拍相册 OTG 上传服务,负责 OSS 上传与 `upload-material` 素材登记。
@MainActor
final class TravelAlbumOTGUploader: TravelAlbumOTGUploading {
private let uploader: OSSUploadService
private let api: any TravelAlbumServing
/// 初始化旅拍相册 OTG 上传服务。
init(
uploader: OSSUploadService? = nil,
api: (any TravelAlbumServing)? = nil
) {
self.uploader = uploader ?? NetworkServices.shared.ossUploadService
self.api = api ?? NetworkServices.shared.travelAlbumAPI
}
/// 上传本地照片并登记为旅拍相册素材。
func upload(
record: TravelAlbumOTGPhotoRecord,
scenicId: Int,
progress: @escaping (Int) -> Void
) async throws -> TravelAlbumMaterial {
guard record.albumId > 0 else {
throw TravelAlbumOTGUploadError.invalidAlbum
}
guard !record.localPath.isEmpty,
FileManager.default.fileExists(atPath: record.localPath) else {
throw TravelAlbumOTGUploadError.localFileMissing
}
guard let clientPhotoId = TravelAlbumClientPhotoID.normalize(record.clientPhotoId) else {
throw TravelAlbumOTGUploadError.clientPhotoIdMissing
}
let data = try Data(contentsOf: URL(fileURLWithPath: record.localPath))
let remoteURL = try await uploader.uploadTravelAlbumMaterial(
data: data,
fileName: record.fileName,
scenicId: scenicId,
onProgress: progress
)
return try await api.uploadMaterial(
TravelAlbumUploadMaterialRequest(
userEquityTravelId: record.albumId,
fileName: record.fileName,
fileUrl: remoteURL,
clientPhotoId: clientPhotoId
)
)
}
}
/// 旅拍相册 OTG 上传错误。
enum TravelAlbumOTGUploadError: LocalizedError, Equatable {
case invalidAlbum
case localFileMissing
case clientPhotoIdMissing
var errorDescription: String? {
switch self {
case .invalidAlbum:
return "请先选择有效的相册"
case .localFileMissing:
return "本地文件不存在,无法上传"
case .clientPhotoIdMissing:
return "照片标识缺失,请重新导入后重试"
}
}
}