- 实现了聊天消息发送功能,支持文本、图片、视频、音频、文件等多种消息类型 - 集成了文件上传下载功能,支持多媒体文件的传输和管理 - 添加了群组管理功能,包括创建群组、成员管理、权限控制等操作 - 实现了好友系统,支持好友添加、删除、分组等功能 - 集成了黑名单管理,提供用户屏蔽和解除屏蔽功能 - 添加了会话管理功能,支持对话列表、未读消息统计等 - 实现了历史消息查询和搜索功能 - 添加了实时连接状态管理和自动重连机制
86 行
3.2 KiB
Swift
86 行
3.2 KiB
Swift
import Foundation
|
|
import UniformTypeIdentifiers
|
|
|
|
public struct FileUploadResult: Codable, Sendable {
|
|
public let url: String
|
|
public let thumbnailUrl: String?
|
|
public let hash: String
|
|
public let size: Int64
|
|
public let originalName: String?
|
|
public let mimeType: String?
|
|
public let ext: String?
|
|
}
|
|
|
|
public final class FileSDK: @unchecked Sendable {
|
|
public static let shared = FileSDK()
|
|
private init() {}
|
|
|
|
public func upload(fileURL: URL, thumbnailData: Data? = nil) async throws -> FileUploadResult {
|
|
let config = await XuqmSDK.shared.requireConfig()
|
|
let tokenStore = await XuqmSDK.shared.tokenStore
|
|
let boundary = "Boundary-\(UUID().uuidString)"
|
|
|
|
let url = SDKEndpoints.apiBaseURL.appendingPathComponent("api/file/upload")
|
|
var request = URLRequest(url: url)
|
|
request.httpMethod = "POST"
|
|
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
|
if let token = tokenStore?.get() {
|
|
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
}
|
|
|
|
let body = try createMultipartBody(fileURL: fileURL, boundary: boundary, thumbnailData: thumbnailData)
|
|
let (data, response) = try await URLSession.shared.upload(for: request, from: body)
|
|
guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else {
|
|
throw URLError(.badServerResponse)
|
|
}
|
|
let wrapper = try JSONDecoder().decode(ApiResponse<FileUploadResult>.self, from: data)
|
|
guard let result = wrapper.data else {
|
|
throw URLError(.cannotDecodeContentData)
|
|
}
|
|
return result
|
|
}
|
|
|
|
private func createMultipartBody(fileURL: URL, boundary: String, thumbnailData: Data?) throws -> Data {
|
|
var body = Data()
|
|
let filename = fileURL.lastPathComponent
|
|
|
|
let mimeType: String
|
|
if #available(iOS 14.0, macOS 11.0, *) {
|
|
if let uti = UTType(filenameExtension: (fileURL.path as NSString).pathExtension),
|
|
let preferred = uti.preferredMIMEType {
|
|
mimeType = preferred
|
|
} else {
|
|
mimeType = "application/octet-stream"
|
|
}
|
|
} else {
|
|
mimeType = "application/octet-stream"
|
|
}
|
|
|
|
body.append("--\(boundary)\r\n")
|
|
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(filename)\"\r\n")
|
|
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
|
body.append(try Data(contentsOf: fileURL))
|
|
body.append("\r\n")
|
|
|
|
if let thumbnailData {
|
|
let thumbFilename = "\((filename as NSString).deletingPathExtension)_thumb.jpg"
|
|
body.append("--\(boundary)\r\n")
|
|
body.append("Content-Disposition: form-data; name=\"thumbnail\"; filename=\"\(thumbFilename)\"\r\n")
|
|
body.append("Content-Type: image/jpeg\r\n\r\n")
|
|
body.append(thumbnailData)
|
|
body.append("\r\n")
|
|
}
|
|
|
|
body.append("--\(boundary)--\r\n")
|
|
return body
|
|
}
|
|
}
|
|
|
|
private extension Data {
|
|
mutating func append(_ string: String) {
|
|
if let data = string.data(using: .utf8) {
|
|
append(data)
|
|
}
|
|
}
|
|
}
|