This commit is contained in:
fmodf 2024-07-14 20:28:54 +02:00
parent c1ce9b133d
commit 1780360fb4
5 changed files with 94 additions and 0 deletions

View file

@ -5,4 +5,9 @@ enum XMPPAction: Codable {
case xmppMessageSent(Message)
case xmppMessageSendFailed(msgId: String)
case xmppMessageSendSuccess(msgId: String)
case xmppAttachmentUpload(Message)
// case xmppAttachmentSlotRequestDone(String) //TODO: ???
case xmppAttachmentUploadFailed(msgId: String, reason: String)
case xmppAttachmentUploadSuccess(msgId: String, attachmentRemotePath: String)
}

View file

@ -100,6 +100,20 @@ final class XMPPMiddleware {
}
.eraseToAnyPublisher()
case .xmppAction(.xmppAttachmentUpload(let message)):
return Future<AppAction, Never> { [weak self] promise in
DispatchQueue.global().async {
self?.service.uploadAttachment(message: message) { done, remotePath in
if done {
promise(.success(.xmppAction(.xmppAttachmentUploadSuccess(msgId: message.id, attachmentRemotePath: remotePath))))
} else {
promise(.success(.xmppAction(.xmppAttachmentUploadFailed(msgId: message.id, reason: "Upload failed"))))
}
}
}
}
.eraseToAnyPublisher()
default:
return Empty().eraseToAnyPublisher()
}

View file

@ -83,6 +83,9 @@ final class XMPPService: ObservableObject {
client.modulesManager.register(MessageCarbonsModule())
client.modulesManager.register(MessageArchiveManagementModule())
// file transfer modules
client.modulesManager.register(HttpFileUploadModule())
// extensions
client.modulesManager.register(SoftwareVersionModule())
client.modulesManager.register(PingModule())
@ -125,6 +128,65 @@ final class XMPPService: ObservableObject {
}
}
}
func uploadAttachment(message: Message, completion: @escaping (Error?, String) -> Void) {
guard let client = getClient(for: message.from), let to = message.to else {
completion(XMPPError.bad_request("No such client"), "")
return
}
guard let fileName = message.attachmentLocalName else {
completion(XMPPError.bad_request("No such file"), "")
return
}
let url = FileProcessing.fileFolder.appendingPathComponent(fileName)
guard let data = try? Data(contentsOf: url) else {
completion(XMPPError.bad_request("No such file"), "")
return
}
let httpModule = client.module(HttpFileUploadModule.self)
httpModule.findHttpUploadComponent { res in
switch res {
case .success(let components):
guard let component = components.first(where: { $0.maxSize > data.count }) else {
completion(XMPPError.bad_request("File too big"), "")
return
}
httpModule.requestUploadSlot(componentJid: component.jid, filename: fileName, size: data.count, contentType: url.mimeType) { res in
switch res {
case .success(let slot):
var request = URLRequest(url: slot.putUri)
for (k, v) in slot.putHeaders {
request.addValue(v, forHTTPHeaderField: k)
}
request.httpMethod = "PUT"
request.httpBody = data
request.addValue(String(data.count), forHTTPHeaderField: "Content-Length")
request.addValue(url.mimeType, forHTTPHeaderField: "Content-Type")
let session = URLSession(configuration: URLSessionConfiguration.default)
session.dataTask(with: request) { _, response, error in
let code = (response as? HTTPURLResponse)?.statusCode ?? 500
guard error == nil, code == 200 || code == 201 else {
completion(XMPPError.bad_request("Upload failed"), "")
return
}
if code == 200 {
completion(XMPPError.bad_request("Invalid response code"), "")
} else {
completion(nil, slot.getUri.absoluteString)
}
}.resume()
case .failure:
completion(XMPPError.bad_request("Upload failed"), "")
}
}
case .failure:
completion(XMPPError.bad_request("No such component"), "")
}
}
}
}
// open class HTTPFileUploadHelper {

View file

@ -0,0 +1,13 @@
import UniformTypeIdentifiers
extension URL {
var mimeType: String {
let pathExtension = self.pathExtension
if let uti = UTType(filenameExtension: pathExtension) {
return uti.preferredMIMEType ?? "application/octet-stream"
} else {
return "application/octet-stream"
}
}
}