wip
This commit is contained in:
parent
c1ce9b133d
commit
1780360fb4
|
@ -5,4 +5,9 @@ enum XMPPAction: Codable {
|
||||||
case xmppMessageSent(Message)
|
case xmppMessageSent(Message)
|
||||||
case xmppMessageSendFailed(msgId: String)
|
case xmppMessageSendFailed(msgId: String)
|
||||||
case xmppMessageSendSuccess(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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,20 @@ final class XMPPMiddleware {
|
||||||
}
|
}
|
||||||
.eraseToAnyPublisher()
|
.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:
|
default:
|
||||||
return Empty().eraseToAnyPublisher()
|
return Empty().eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,9 @@ final class XMPPService: ObservableObject {
|
||||||
client.modulesManager.register(MessageCarbonsModule())
|
client.modulesManager.register(MessageCarbonsModule())
|
||||||
client.modulesManager.register(MessageArchiveManagementModule())
|
client.modulesManager.register(MessageArchiveManagementModule())
|
||||||
|
|
||||||
|
// file transfer modules
|
||||||
|
client.modulesManager.register(HttpFileUploadModule())
|
||||||
|
|
||||||
// extensions
|
// extensions
|
||||||
client.modulesManager.register(SoftwareVersionModule())
|
client.modulesManager.register(SoftwareVersionModule())
|
||||||
client.modulesManager.register(PingModule())
|
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 {
|
// open class HTTPFileUploadHelper {
|
||||||
|
|
13
ConversationsClassic/Helpers/URL+Extensions.swift
Normal file
13
ConversationsClassic/Helpers/URL+Extensions.swift
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue