Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 102 additions & 33 deletions Sources/TransloaditKit/Transloadit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,23 +124,58 @@ public final class Transloadit {
///
/// - Parameter steps: The steps of an Assembly.
/// - Parameter expectedNumberOfFiles: The number of expected files to upload to this assembly
/// - Parameter customFields: JSON-encodable dictionary of custom parameters to pass to the assembly creation
/// - Parameter completion: The created assembly
public func createAssembly(steps: [Step], expectedNumberOfFiles: Int = 1, completion: @escaping (Result<Assembly, TransloaditError>) -> Void) {
api.createAssembly(steps: steps, expectedNumberOfFiles: expectedNumberOfFiles) { result in
public func createAssembly(
steps: [Step],
expectedNumberOfFiles: Int = 1,
customFields: [String: String] = [:],
completion: @escaping (Result<Assembly, TransloaditError>) -> Void
) {
api.createAssembly(
steps: steps,
expectedNumberOfFiles: expectedNumberOfFiles,
customFields: customFields) { result in
let transloaditResult = result.mapError { error in TransloaditError.couldNotCreateAssembly(underlyingError: error) }
completion(transloaditResult)
}
}

public func createAssembly(templateId: String, expectedNumberOfFiles: Int = 1, completion: @escaping (Result<Assembly, TransloaditError>) -> Void) {
api.createAssembly(templateId: templateId, expectedNumberOfFiles: expectedNumberOfFiles) { result in

/// Create an assembly, do not upload a file.
///
/// This is useful for when you want to import a file from a different source, such as a third party storage service.
///
/// If you wish to upload a file and check for its processing status, please refer to ` public func createAssembly(templateId: andUpload files: completion:)`
///
/// - Parameters:
/// - templateId: The templateId to use for this assembly
/// - expectedNumberOfFiles: The number of expected files to upload to this assembly
/// - customFields: JSON-encodable dictionary of custom parameters to pass to the assembly creation
/// - completion: The created Assembly
public func createAssembly(
templateId: String,
expectedNumberOfFiles: Int = 1,
customFields: [String: String] = [:],
completion: @escaping (Result<Assembly, TransloaditError>) -> Void
) {
api.createAssembly(
templateId: templateId,
expectedNumberOfFiles: expectedNumberOfFiles,
customFields: customFields
) { result in
let transloaditResult = result.mapError { error in TransloaditError.couldNotCreateAssembly(underlyingError: error) }
completion(transloaditResult)
}
}

@discardableResult
public func createAssembly(templateId: String, andUpload files: [URL], completion: @escaping (Result<Assembly, TransloaditError>) -> Void) -> TransloaditPoller {
public func createAssembly(
templateId: String,
andUpload files: [URL],
customFields: [String: String] = [:],
completion: @escaping (Result<Assembly, TransloaditError>) -> Void
) -> TransloaditPoller {
func makeMetadata(assembly: Assembly) -> [String: String] {
[:]
}
Expand All @@ -154,15 +189,21 @@ public final class Transloadit {
assertionFailure("Transloadit: Somehow already got a poller for this url and these files")
}

createAssembly(templateId: templateId, expectedNumberOfFiles: files.count, completion: { [weak self] result in
createAssembly(
templateId: templateId,
expectedNumberOfFiles: files.count,
customFields: customFields,
completion: { [weak self] result in
guard let self = self else { return }

do {
let assembly = try result.get()
try self.tusClient.uploadFiles(filePaths: files,
uploadURL: assembly.tusURL,
customHeaders: makeMetadata(assembly: assembly),
context: ["assembly": assembly.description, "fieldname": "file-input", "assembly_url": assembly.url.absoluteString])
try self.tusClient.uploadFiles(
filePaths: files,
uploadURL: assembly.tusURL,
customHeaders: makeMetadata(assembly: assembly),
context: ["assembly": assembly.description, "fieldname": "file-input", "assembly_url": assembly.url.absoluteString]
)

poller.assemblyURL = assembly.url

Expand All @@ -186,6 +227,7 @@ public final class Transloadit {
/// - Parameters:
/// - steps: The steps of an assembly.
/// - files: Paths to the files to upload
/// - customFields: JSON-encodable dictionary of extra parameters to send along with assembly creation
/// - completion: completion handler, called when upload is complete
///
/// Below you can see how you can create an assembly and poll for its upload status
Expand All @@ -200,7 +242,12 @@ public final class Transloadit {
/// }
///```
@discardableResult
public func createAssembly(steps: [Step], andUpload files: [URL], completion: @escaping (Result<Assembly, TransloaditError>) -> Void) -> TransloaditPoller {
public func createAssembly(
steps: [Step],
andUpload files: [URL],
customFields: [String: String] = [:],
completion: @escaping (Result<Assembly, TransloaditError>) -> Void
) -> TransloaditPoller {
func makeMetadata(assembly: Assembly) -> [String: String] {
[:]
}
Expand All @@ -214,25 +261,31 @@ public final class Transloadit {
assertionFailure("Transloadit: Somehow already got a poller for this url and these files")
}

createAssembly(steps: steps, expectedNumberOfFiles: files.count, completion: { [weak self] result in
guard let self = self else { return }

do {
let assembly = try result.get()
try self.tusClient.uploadFiles(filePaths: files,
uploadURL: assembly.tusURL,
customHeaders: makeMetadata(assembly: assembly),
context: ["assembly": assembly.description, "fieldname": "file-input", "assembly_url": assembly.url.absoluteString])
createAssembly(
steps: steps,
expectedNumberOfFiles: files.count,
customFields: customFields,
completion: { [weak self] result in
guard let self = self else { return }

poller.assemblyURL = assembly.url

completion(.success(assembly))
} catch let error where error is TransloaditAPIError {
completion(.failure(TransloaditError.couldNotCreateAssembly(underlyingError: error)))
} catch {
completion(.failure(TransloaditError.couldNotUploadFile(underlyingError: error)))
}
})
do {
let assembly = try result.get()
try self.tusClient.uploadFiles(
filePaths: files,
uploadURL: assembly.tusURL,
customHeaders: makeMetadata(assembly: assembly),
context: ["assembly": assembly.description, "fieldname": "file-input", "assembly_url": assembly.url.absoluteString]
)

poller.assemblyURL = assembly.url

completion(.success(assembly))
} catch let error where error is TransloaditAPIError {
completion(.failure(TransloaditError.couldNotCreateAssembly(underlyingError: error)))
} catch {
completion(.failure(TransloaditError.couldNotUploadFile(underlyingError: error)))
}
})

pollers[files] = poller
return poller
Expand All @@ -241,9 +294,17 @@ public final class Transloadit {
#if compiler(>=5.5) && canImport(_Concurrency)

@available(macOS 10.15, iOS 13, *)
public func createAssembly(steps: [Step], expectedNumberOfFiles: Int = 1) async throws -> Assembly {
public func createAssembly(
steps: [Step],
expectedNumberOfFiles: Int = 1,
customFields: [String: String] = [:]
) async throws -> Assembly {
return try await withCheckedThrowingContinuation { continuation in
createAssembly(steps: steps, expectedNumberOfFiles: expectedNumberOfFiles, completion: { result in
createAssembly(
steps: steps,
expectedNumberOfFiles: expectedNumberOfFiles,
customFields: customFields,
completion: { result in
switch result {
case .success(let assembly):
continuation.resume(returning: assembly)
Expand All @@ -255,11 +316,19 @@ public final class Transloadit {
}

@available(macOS 10.15, iOS 13, *)
public func createAssembly(steps: [Step], andUpload files: [URL]) async throws -> (Assembly, TransloaditPoller) {
public func createAssembly(
steps: [Step],
andUpload files: [URL],
customFields: [String: String] = [:]
) async throws -> (Assembly, TransloaditPoller) {

return try await withCheckedThrowingContinuation({ continuation in
var poller: TransloaditPoller!
poller = createAssembly(steps: steps, andUpload: files) { result in
poller = createAssembly(
steps: steps,
andUpload: files,
customFields: customFields
) { result in

switch result {
case .success(let assembly):
Expand Down
46 changes: 37 additions & 9 deletions Sources/TransloaditKit/TransloaditAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,17 @@ final class TransloaditAPI {
self.session = session
}

func createAssembly(templateId: String, expectedNumberOfFiles: Int, completion: @escaping (Result<Assembly, TransloaditAPIError>) -> Void) {
guard let request = try? makeAssemblyRequest(templateId: templateId, expectedNumberOfFiles: expectedNumberOfFiles) else {
func createAssembly(
templateId: String,
expectedNumberOfFiles: Int,
customFields: [String: String],
completion: @escaping (Result<Assembly, TransloaditAPIError>) -> Void
) {
guard let request = try? makeAssemblyRequest(
templateId: templateId,
expectedNumberOfFiles: expectedNumberOfFiles,
customFields: customFields
) else {
// Next runloop to make the API consistent with the network runloop. Otherwise it would return instantly, can give weird effects
DispatchQueue.main.async {
completion(.failure(TransloaditAPIError.cantSerialize))
Expand Down Expand Up @@ -71,8 +80,17 @@ final class TransloaditAPI {
task.resume()
}

func createAssembly(steps: [Step], expectedNumberOfFiles: Int, completion: @escaping (Result<Assembly, TransloaditAPIError>) -> Void) {
guard let request = try? makeAssemblyRequest(steps: steps, expectedNumberOfFiles: expectedNumberOfFiles) else {
func createAssembly(
steps: [Step],
expectedNumberOfFiles: Int,
customFields: [String: String],
completion: @escaping (Result<Assembly, TransloaditAPIError>) -> Void
) {
guard let request = try? makeAssemblyRequest(
steps: steps,
expectedNumberOfFiles: expectedNumberOfFiles,
customFields: customFields
) else {
// Next runloop to make the API consistent with the network runloop. Otherwise it would return instantly, can give weird effects
DispatchQueue.main.async {
completion(.failure(TransloaditAPIError.cantSerialize))
Expand Down Expand Up @@ -100,7 +118,11 @@ final class TransloaditAPI {
task.resume()
}

private func makeAssemblyRequest(templateId: String, expectedNumberOfFiles: Int) throws -> URLRequest {
private func makeAssemblyRequest(
templateId: String,
expectedNumberOfFiles: Int,
customFields: [String: String]
) throws -> URLRequest {

func makeBody(includeSecret: Bool) throws -> [String: String] {
// Time to allow uploads after signing.
Expand All @@ -109,7 +131,8 @@ final class TransloaditAPI {

let authObject = ["key": credentials.key, "expires": dateTime]

let params: [String: Any] = ["auth": authObject, "template_id": templateId]
var params: [String: Any] = ["auth": authObject, "template_id": templateId]
params["fields"] = customFields

let paramsData: Data
if #available(macOS 10.15, iOS 13.0, *) {
Expand Down Expand Up @@ -166,7 +189,11 @@ final class TransloaditAPI {
return request
}

private func makeAssemblyRequest(steps: [Step], expectedNumberOfFiles: Int) throws -> URLRequest {
private func makeAssemblyRequest(
steps: [Step],
expectedNumberOfFiles: Int,
customFields: [String: String]
) throws -> URLRequest {

func makeBody(includeSecret: Bool) throws -> [String: String] {
// Time to allow uploads after signing.
Expand All @@ -175,13 +202,14 @@ final class TransloaditAPI {

let authObject = ["key": credentials.key, "expires": dateTime]

let params = ["auth": authObject, "steps": steps.toDictionary]
var params: [String: Any] = ["auth": authObject, "steps": steps.toDictionary]
params["fields"] = customFields

let paramsData: Data
if #available(macOS 10.15, iOS 13.0, *) {
paramsData = try JSONSerialization.data(withJSONObject: params, options: .withoutEscapingSlashes)
} else {
paramsData = try! JSONSerialization.data(withJSONObject: params, options: [])
paramsData = try JSONSerialization.data(withJSONObject: params, options: [])
}

guard let paramsJSONString = String(data: paramsData, encoding: .utf8) else {
Expand Down
Loading