Skip to content
Snippets Groups Projects
MessengerReceiveFile.swift 2.32 KiB
Newer Older
import Foundation
import XCTestDynamicOverlay
import XXClient

public struct MessengerReceiveFile {
  public struct Params: Equatable {
    public init(
      transferId: Data,
      callbackIntervalMS: Int = 250
    ) {
      self.transferId = transferId
      self.callbackIntervalMS = callbackIntervalMS
    }

    public var transferId: Data
    public var callbackIntervalMS: Int
  }

  public enum CallbackInfo: Equatable {
    public enum Failure: Equatable {
      case callbackError(NSError)
      case progressError(String)
      case receiveError(NSError)
    }

    case progress(transmitted: Int, total: Int)
    case finished(Data)
    case failed(Failure)
  }

  public typealias Callback = (CallbackInfo) -> Void

  public enum Error: Swift.Error, Equatable {
    case fileTransferNotStarted
  public var run: (Params, @escaping Callback) throws -> Void
  public func callAsFunction(
    _ params: Params,
    callback: @escaping Callback
  ) throws -> Void {
    try run(params, callback)
  }
}

extension MessengerReceiveFile {
  public static func live(_ env: MessengerEnvironment) -> MessengerReceiveFile {
    MessengerReceiveFile { params, callback in
      guard let fileTransfer = env.fileTransfer() else {
        throw Error.fileTransferNotStarted
      try fileTransfer.registerReceivedProgressCallback(
        transferId: params.transferId,
        period: params.callbackIntervalMS,
        callback: FileTransferProgressCallback { result in
          switch result {
          case .success(let info):
            if let error = info.progress.error {
              callback(.failed(.progressError(error)))
            } else if info.progress.completed {
              do {
                callback(.finished(try fileTransfer.receive(transferId: params.transferId)))
              } catch {
                callback(.failed(.receiveError(error as NSError)))
              }
            } else {
              callback(.progress(
                transmitted: info.progress.transmitted,
                total: info.progress.total
              ))
            }

          case .failure(let error):
            callback(.failed(.callbackError(error)))
          }
        }
      )
    }
  }
}

extension MessengerReceiveFile {
  public static let unimplemented = MessengerReceiveFile(
    run: XCTUnimplemented("\(Self.self)")
  )
}