Skip to content
Snippets Groups Projects
Commit 0758b846 authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Implement ReceiveFileHandler

parent 14b12aba
No related branches found
No related tags found
2 merge requests!124File transfers example,!102Release 1.0.0
This commit is part of merge request !102. Comments created here will be created in the context of that merge request.
import Foundation
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
import XXModels
public struct ReceiveFileHandler {
public struct ProgressError: Error {
public init(message: String) {
self.message = message
}
public var message: String
}
public typealias OnError = (Error) -> Void
public var run: (@escaping OnError) -> Cancellable
......@@ -14,14 +24,94 @@ public struct ReceiveFileHandler {
extension ReceiveFileHandler {
public static func live(
messenger: Messenger
messenger: Messenger,
db: DBManagerGetDB,
now: @escaping () -> Date
) -> ReceiveFileHandler {
ReceiveFileHandler { onError in
messenger.registerReceiveFileCallback(.init { result in
func receiveFile(_ file: ReceivedFile) {
do {
let date = now()
try db().saveFileTransfer(XXModels.FileTransfer(
id: file.transferId,
contactId: file.senderId,
name: file.name,
type: file.type,
data: nil,
progress: 0,
isIncoming: true,
createdAt: date
))
try db().saveMessage(XXModels.Message(
senderId: file.senderId,
recipientId: try messenger.e2e.tryGet().getContact().getId(),
groupId: nil,
date: date,
status: .received,
isUnread: false,
text: "",
fileTransferId: file.transferId
))
try messenger.receiveFile(.init(
transferId: file.transferId,
callbackIntervalMS: 500
)) { info in
switch info {
case .progress(let transmitted, let total):
updateProgress(
transferId: file.transferId,
transmitted: transmitted,
total: total
)
case .finished(let data):
saveData(
transferId: file.transferId,
data: data
)
case .failed(.receiveError(let error)):
onError(error)
case .failed(.callbackError(let error)):
onError(error)
case .failed(.progressError(let message)):
onError(ProgressError(message: message))
}
}
} catch {
onError(error)
}
}
func updateProgress(transferId: Data, transmitted: Int, total: Int) {
do {
if var transfer = try db().fetchFileTransfers(.init(id: [transferId])).first {
transfer.progress = total > 0 ? Float(transmitted) / Float(total) : 0
try db().saveFileTransfer(transfer)
}
} catch {
onError(error)
}
}
func saveData(transferId: Data, data: Data) {
do {
if var transfer = try db().fetchFileTransfers(.init(id: [transferId])).first {
transfer.progress = 1
transfer.data = data
try db().saveFileTransfer(transfer)
}
} catch {
onError(error)
}
}
return messenger.registerReceiveFileCallback(.init { result in
switch result {
case .success(let file):
// TODO:
break
receiveFile(file)
case .failure(let error):
onError(error)
......
......@@ -114,7 +114,9 @@ extension AppEnvironment {
db: dbManager.getDB
),
receiveFileHandler: .live(
messenger: messenger
messenger: messenger,
db: dbManager.getDB,
now: Date.init
),
backupStorage: backupStorage,
log: .live(),
......
import CustomDump
import XCTest
import XXMessengerClient
import XXClient
import XXModels
@testable import AppCore
final class ReceiveFileHandlerTests: XCTestCase {
func testReceiveFile() {
let currentDate = Date(timeIntervalSince1970: 123)
let myContactId = "my-contact-id".data(using: .utf8)!
let receivedFile = ReceivedFile.stub()
var actions: [Action] = []
var receiveFileCallback: ReceiveFileCallback?
var receivingFileCallback: MessengerReceiveFile.Callback?
var messenger: Messenger = .unimplemented
messenger.registerReceiveFileCallback.run = { callback in
actions.append(.didRegisterReceiveFileCallback)
receiveFileCallback = callback
return Cancellable { actions.append(.didCancelReceiveFileCallback) }
}
messenger.e2e.get = {
var e2e: E2E = .unimplemented
e2e.getContact.run = {
var contact: XXClient.Contact = .unimplemented(Data())
contact.getIdFromContact.run = { _ in myContactId }
return contact
}
return e2e
}
messenger.receiveFile.run = { params, callback in
actions.append(.didReceiveFile(params))
receivingFileCallback = callback
}
var db: DBManagerGetDB = .unimplemented
db.run = {
var db: Database = .unimplemented
db.saveFileTransfer.run = { model in
actions.append(.didSaveFileTransfer(model))
return model
}
db.saveMessage.run = { model in
actions.append(.didSaveMessage(model))
return model
}
db.fetchFileTransfers.run = { query in
actions.append(.didFetchFileTransfers(query))
return [
FileTransfer(
id: receivedFile.transferId,
contactId: receivedFile.senderId,
name: receivedFile.name,
type: receivedFile.type,
data: nil,
progress: 0,
isIncoming: true,
createdAt: currentDate
)
]
}
return db
}
let handler = ReceiveFileHandler.live(
messenger: messenger,
db: db,
now: { currentDate }
)
XCTAssertNoDifference(actions, [])
actions = []
let cancellable = handler(onError: { error in
actions.append(.didCatchError(error as NSError))
})
XCTAssertNoDifference(actions, [
.didRegisterReceiveFileCallback
])
actions = []
let error = NSError(domain: "receive-file", code: 1)
receiveFileCallback?.handle(.failure(error))
XCTAssertNoDifference(actions, [
.didCatchError(error)
])
actions = []
receiveFileCallback?.handle(.success(receivedFile))
XCTAssertNoDifference(actions, [
.didSaveFileTransfer(FileTransfer(
id: receivedFile.transferId,
contactId: receivedFile.senderId,
name: receivedFile.name,
type: receivedFile.type,
data: nil,
progress: 0,
isIncoming: true,
createdAt: currentDate
)),
.didSaveMessage(Message(
networkId: nil,
senderId: receivedFile.senderId,
recipientId: myContactId,
groupId: nil,
date: currentDate,
status: .received,
isUnread: false,
text: "",
replyMessageId: nil,
roundURL: nil,
fileTransferId: receivedFile.transferId
)),
.didReceiveFile(MessengerReceiveFile.Params(
transferId: receivedFile.transferId,
callbackIntervalMS: 500
)),
])
actions = []
let receivingFileError = NSError(domain: "receiving-file", code: 2)
receivingFileCallback?(.failed(.receiveError(receivingFileError)))
XCTAssertNoDifference(actions, [
.didCatchError(receivingFileError)
])
actions = []
let receivingFileCallbackError = NSError(domain: "receiving-file-callback", code: 3)
receivingFileCallback?(.failed(.callbackError(receivingFileCallbackError)))
XCTAssertNoDifference(actions, [
.didCatchError(receivingFileCallbackError)
])
actions = []
let receivingFileProgressError = "receiving-file-progress"
receivingFileCallback?(.failed(.progressError(receivingFileProgressError)))
XCTAssertNoDifference(actions, [
.didCatchError(ReceiveFileHandler.ProgressError(message: receivingFileProgressError) as NSError)
])
actions = []
receivingFileCallback?(.progress(transmitted: 1, total: 2))
XCTAssertNoDifference(actions, [
.didFetchFileTransfers(.init(id: [receivedFile.transferId])),
.didSaveFileTransfer(FileTransfer(
id: receivedFile.transferId,
contactId: receivedFile.senderId,
name: receivedFile.name,
type: receivedFile.type,
data: nil,
progress: 0.5,
isIncoming: true,
createdAt: currentDate
)),
])
actions = []
let fileData = "file-data".data(using: .utf8)!
receivingFileCallback?(.finished(fileData))
XCTAssertNoDifference(actions, [
.didFetchFileTransfers(.init(id: [receivedFile.transferId])),
.didSaveFileTransfer(FileTransfer(
id: receivedFile.transferId,
contactId: receivedFile.senderId,
name: receivedFile.name,
type: receivedFile.type,
data: fileData,
progress: 1,
isIncoming: true,
createdAt: currentDate
)),
])
actions = []
cancellable.cancel()
XCTAssertNoDifference(actions, [
.didCancelReceiveFileCallback
])
}
}
private enum Action: Equatable {
case didRegisterReceiveFileCallback
case didCancelReceiveFileCallback
case didCatchError(NSError)
case didSaveFileTransfer(XXModels.FileTransfer)
case didSaveMessage(XXModels.Message)
case didReceiveFile(MessengerReceiveFile.Params)
case didFetchFileTransfers(XXModels.FileTransfer.Query)
}
private extension ReceivedFile {
static func stub() -> ReceivedFile {
ReceivedFile(
transferId: "received-file-transferId".data(using: .utf8)!,
senderId: "received-file-senderId".data(using: .utf8)!,
preview: "received-file-preview".data(using: .utf8)!,
name: "received-file-name",
type: "received-file-type",
size: 1234
)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment