Skip to content

Commit

Permalink
Provides an option to send fileManager and boundary with multipart fo…
Browse files Browse the repository at this point in the history
…rm data.
  • Loading branch information
ljubinkovicdj93 committed Feb 22, 2023
1 parent 77e67c0 commit 7647a3b
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 13 deletions.
12 changes: 6 additions & 6 deletions Sources/Moya/MoyaProvider+Internal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ public extension MoyaProvider {
return self.sendRequest(target, request: request, callbackQueue: callbackQueue, progress: progress, completion: completion)
case .uploadFile(let file):
return self.sendUploadFile(target, request: request, callbackQueue: callbackQueue, file: file, progress: progress, completion: completion)
case .uploadMultipart(let multipartBody), .uploadCompositeMultipart(let multipartBody, _):
guard !multipartBody.isEmpty && endpoint.method.supportsMultipart else {
case .uploadMultipart(let multipartFormData), .uploadCompositeMultipart(let multipartFormData, _):
guard !multipartFormData.parts.isEmpty && endpoint.method.supportsMultipart else {
fatalError("\(target) is not a multipart upload target.")
}
return self.sendUploadMultipart(target, request: request, callbackQueue: callbackQueue, multipartBody: multipartBody, progress: progress, completion: completion)
return self.sendUploadMultipart(target, request: request, callbackQueue: callbackQueue, multipartFormData: multipartFormData, progress: progress, completion: completion)
case .downloadDestination(let destination), .downloadParameters(_, _, let destination):
return self.sendDownloadRequest(target, request: request, callbackQueue: callbackQueue, destination: destination, progress: progress, completion: completion)
}
Expand Down Expand Up @@ -172,9 +172,9 @@ private extension MoyaProvider {
}
}

func sendUploadMultipart(_ target: Target, request: URLRequest, callbackQueue: DispatchQueue?, multipartBody: [MultipartFormData], progress: Moya.ProgressBlock? = nil, completion: @escaping Moya.Completion) -> CancellableToken {
let formData = RequestMultipartFormData()
formData.applyMoyaMultipartFormData(multipartBody)
func sendUploadMultipart(_ target: Target, request: URLRequest, callbackQueue: DispatchQueue?, multipartFormData: MultipartFormData, progress: Moya.ProgressBlock? = nil, completion: @escaping Moya.Completion) -> CancellableToken {
let formData = RequestMultipartFormData(fileManager: multipartFormData.fileManager, boundary: multipartFormData.boundary)
formData.applyMoyaMultipartFormData(multipartFormData)

let interceptor = self.interceptor(target: target)
let uploadRequest: UploadRequest = session.requestQueue.sync {
Expand Down
34 changes: 29 additions & 5 deletions Sources/Moya/MultipartFormData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,30 @@ import Alamofire

/// Represents "multipart/form-data" for an upload.
public struct MultipartFormData: Hashable {
/// `FileManager` to use for file operations, if needed. `FileManager.default` by default.
public let fileManager: FileManager

/// Separates ``parts`` in the encoded form data. `nil` by default.
public let boundary: String?

/// Blocks of data to send, separated with ``boundary``.
public let parts: [MultipartFormBodyPart]

public init(fileManager: FileManager = .default, boundary: String? = nil, parts: [MultipartFormBodyPart]) {
self.fileManager = fileManager
self.boundary = boundary
self.parts = parts
}
}

extension MultipartFormData: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: MultipartFormBodyPart...) {
self.init(parts: elements)
}
}

/// Represents the body part of "multipart/form-data" for an upload.
public struct MultipartFormBodyPart: Hashable {

/// Method to provide the form data.
public enum FormDataProvider: Hashable {
Expand Down Expand Up @@ -34,24 +58,24 @@ public struct MultipartFormData: Hashable {

// MARK: RequestMultipartFormData appending
internal extension RequestMultipartFormData {
func append(data: Data, bodyPart: MultipartFormData) {
func append(data: Data, bodyPart: MultipartFormBodyPart) {
append(data, withName: bodyPart.name, fileName: bodyPart.fileName, mimeType: bodyPart.mimeType)
}

func append(fileURL url: URL, bodyPart: MultipartFormData) {
func append(fileURL url: URL, bodyPart: MultipartFormBodyPart) {
if let fileName = bodyPart.fileName, let mimeType = bodyPart.mimeType {
append(url, withName: bodyPart.name, fileName: fileName, mimeType: mimeType)
} else {
append(url, withName: bodyPart.name)
}
}

func append(stream: InputStream, length: UInt64, bodyPart: MultipartFormData) {
func append(stream: InputStream, length: UInt64, bodyPart: MultipartFormBodyPart) {
append(stream, withLength: length, name: bodyPart.name, fileName: bodyPart.fileName ?? "", mimeType: bodyPart.mimeType ?? "")
}

func applyMoyaMultipartFormData(_ multipartBody: [Moya.MultipartFormData]) {
for bodyPart in multipartBody {
func applyMoyaMultipartFormData(_ multipartFormData: Moya.MultipartFormData) {
for bodyPart in multipartFormData.parts {
switch bodyPart.provider {
case .data(let data):
append(data: data, bodyPart: bodyPart)
Expand Down
4 changes: 2 additions & 2 deletions Sources/Moya/Task.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ public enum Task {
case uploadFile(URL)

/// A "multipart/form-data" upload task.
case uploadMultipart([MultipartFormData])
case uploadMultipart(MultipartFormData)

/// A "multipart/form-data" upload task combined with url parameters.
case uploadCompositeMultipart([MultipartFormData], urlParameters: [String: Any])
case uploadCompositeMultipart(MultipartFormData, urlParameters: [String: Any])

/// A file download task to a destination.
case downloadDestination(DownloadDestination)
Expand Down

0 comments on commit 7647a3b

Please sign in to comment.