Skip to content

Commit

Permalink
Various BG Upload related fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
donnywals committed Nov 27, 2024
1 parent 0a89d4d commit 43fa6fc
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 95 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# TransloaditKit Changelog

## 3.3.1
* Background configuration was not set up fully correctly; this is now fixed
* TUSKit will always use a background configuration when uploading files
* Added a new initializer to TransloadIt that allows users to provide a URLSessionConfiguration instead of a URLSession

## 3.3.0

### Fixes
Expand Down
19 changes: 15 additions & 4 deletions Sources/TransloaditKit/Transloadit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,12 @@ public final class Transloadit {
}

lazy var tusClient: TUSClient = {
let tusClient = try! TUSClient(server: URL(string:"https://www.transloadit.com")!, sessionIdentifier: "TransloadIt", sessionConfiguration: session.configuration, storageDirectory: storageDir)
let config = URLSessionConfiguration.background(withIdentifier: "com.transloadit.tus.background")
let tusClient = try! TUSClient(server: URL(string:"https://www.transloadit.com")!, sessionIdentifier: "TransloadIt", sessionConfiguration: config, storageDirectory: storageDir)
tusClient.delegate = self
return tusClient
}()

let session: URLSession

public weak var fileDelegate: TransloaditFileDelegate?

/// Initialize Transloadit
Expand All @@ -77,9 +76,21 @@ public final class Transloadit {
/// - storageDir: A storagedirectory to use. Used by underlying TUSKit mechanism to store files.
/// If left empty, no directory will be made when performing non-file related tasks, such as creating assemblies. However, if you start uploading files,
/// then TUS will make a directory, whether one you specify or a default one in the documents directory.
@available(*, deprecated, message: "Use the new init(credentials:sessionConfig:storageDir:) instead.")
public init(credentials: Transloadit.Credentials, session: URLSession, storageDir: URL? = nil) {
self.api = TransloaditAPI(credentials: credentials, session: session)
self.session = session
self.storageDir = storageDir
}

/// Initialize Transloadit
/// - Parameters:
/// - credentials: The credentials with required key and secret.
/// - sessionConfiguration: A URLSessionConfiguration to use.
/// - storageDir: A storagedirectory to use. Used by underlying TUSKit mechanism to store files.
/// If left empty, no directory will be made when performing non-file related tasks, such as creating assemblies. However, if you start uploading files,
/// then TUS will make a directory, whether one you specify or a default one in the documents directory.
public init(credentials: Transloadit.Credentials, sessionConfiguration: URLSessionConfiguration, storageDir: URL? = nil) {
self.api = TransloaditAPI(credentials: credentials, sessionConfiguration: sessionConfiguration)
self.storageDir = storageDir
}

Expand Down
41 changes: 21 additions & 20 deletions Sources/TransloaditKit/TransloaditAPI+URLSessionDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import Foundation

extension TransloaditAPI: URLSessionDataDelegate {
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
guard let completionHandler = callbacks[task] else {
return
}

defer { callbacks[task] = nil }

if let error {
completionHandler.callback(.failure(error))
return
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print(error)
guard let completionHandler = callbacks[task] else {
return
}

defer { callbacks[task] = nil }

if let error {
completionHandler.callback(.failure(error))
return
}

guard let response = task.response else {
completionHandler.callback(.failure(TransloaditAPIError.incompleteServerResponse))
return
}

completionHandler.callback(.success((completionHandler.data, response)))
}

guard let response = task.response else {
completionHandler.callback(.failure(TransloaditAPIError.incompleteServerResponse))
return
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
callbacks[dataTask]?.data.append(data)
}

completionHandler.callback(.success((completionHandler.data, response)))
}

public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
callbacks[dataTask]?.data.append(data)
}
}
55 changes: 39 additions & 16 deletions Sources/TransloaditKit/TransloaditAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ final class TransloaditAPI: NSObject {
}

private let configuration: URLSessionConfiguration
private let delegateQueue: OperationQueue
private let delegateQueue: OperationQueue?
private lazy var session: URLSession = {
return URLSession(configuration: configuration, delegate: self, delegateQueue: delegateQueue)
}()
Expand All @@ -45,11 +45,22 @@ final class TransloaditAPI: NSObject {

init(credentials: Transloadit.Credentials, session: URLSession) {
self.credentials = credentials
self.configuration = session.configuration
if session.configuration.sessionSendsLaunchEvents {
self.configuration = .background(withIdentifier: "com.transloadit.bgurlsession")
} else {
self.configuration = session.configuration
}
self.delegateQueue = session.delegateQueue
super.init()
}

init(credentials: Transloadit.Credentials, sessionConfiguration: URLSessionConfiguration) {
self.credentials = credentials
self.configuration = sessionConfiguration
self.delegateQueue = nil
super.init()
}

func createAssembly(
templateId: String,
expectedNumberOfFiles: Int,
Expand All @@ -68,8 +79,8 @@ final class TransloaditAPI: NSObject {
return
}

let task = session.dataTask(with: request)
callbacks[task] = URLSessionCompletionHandler(callback: { result in
let task = session.uploadTask(with: request.request, fromFile: request.httpBody)
callbacks[task] = URLSessionCompletionHandler(callback: { result in
switch result {
case .failure(let error):
completion(.failure(.couldNotCreateAssembly(error)))
Expand Down Expand Up @@ -110,8 +121,8 @@ final class TransloaditAPI: NSObject {
return
}

let task = session.dataTask(with: request)
//task.delegate = self
try! print(Data(contentsOf: request.httpBody))
let task = session.uploadTask(with: request.request, fromFile: request.httpBody)
callbacks[task] = URLSessionCompletionHandler(callback: { result in
switch result {
case .failure(let error):
Expand Down Expand Up @@ -139,7 +150,7 @@ final class TransloaditAPI: NSObject {
templateId: String,
expectedNumberOfFiles: Int,
customFields: [String: String]
) throws -> URLRequest {
) throws -> (request: URLRequest, httpBody: URL) {

func makeBody(includeSecret: Bool) throws -> [String: String] {
// Time to allow uploads after signing.
Expand Down Expand Up @@ -196,21 +207,20 @@ final class TransloaditAPI: NSObject {

request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = try makeBodyData()
return request
}

let request = try makeRequest()
let bodyData = try makeBodyData()


return request
return (request, try writeBodyData(bodyData))
}

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

func makeBody(includeSecret: Bool) throws -> [String: String] {
// Time to allow uploads after signing.
Expand Down Expand Up @@ -267,14 +277,27 @@ final class TransloaditAPI: NSObject {

request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = try makeBodyData()
return request
}

let request = try makeRequest()
let bodyData = try makeBodyData()


return request
return (request, try writeBodyData(bodyData))
}

private func writeBodyData(_ data: Data) throws -> URL {
let appSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
let bodyDirectory = appSupport.appendingPathComponent("uploads")
let dataFile = bodyDirectory.appendingPathComponent(UUID().uuidString + ".uploadData")

if !FileManager.default.fileExists(atPath: bodyDirectory.path) {
try FileManager.default.createDirectory(at: bodyDirectory, withIntermediateDirectories: true, attributes: nil)
}

try data.write(to: dataFile)

return dataFile
}

func fetchStatus(assemblyURL: URL, completion: @escaping (Result<AssemblyStatus, TransloaditAPIError>) -> Void) {
Expand All @@ -285,7 +308,7 @@ final class TransloaditAPI: NSObject {
return request
}

let task = session.dataTask(with: makeRequest())
let task = session.downloadTask(with: makeRequest())
callbacks[task] = URLSessionCompletionHandler(callback: { result in
switch result {
case .failure:
Expand All @@ -311,7 +334,7 @@ final class TransloaditAPI: NSObject {
return request
}

let task = session.dataTask(with: makeRequest())
let task = session.downloadTask(with: makeRequest())
callbacks[task] = URLSessionCompletionHandler(callback: { result in
switch result {
case .failure:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct ContentView: View {
showingImagePicker.toggle()
}.sheet(isPresented:$showingImagePicker, content: {
PhotoPicker { [weak uploader] urls in
print(urls)
uploader?.upload(urls)
}
})
Expand Down
91 changes: 38 additions & 53 deletions TransloaditKitExample/TransloaditKitExample/PhotoPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,66 +40,51 @@ struct PhotoPicker: UIViewControllerRepresentable {
}

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {

dataFrom(pickerResults: results) { [unowned self] urls in
self.parent.didPickPhotos(urls)
}
parent.presentationMode.wrappedValue.dismiss()
}

func dataFrom(pickerResults: [PHPickerResult], completed: @escaping ([URL]) -> Void) {
let identifiers = pickerResults.compactMap(\.assetIdentifier)

let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: identifiers, options: nil)
var assetURLs = [URL]()

var expectedCount = pickerResults.count // Can't rely on count in enumerateObjects in Xcode 13
fetchResult.enumerateObjects { asset, count, _ in
asset.getURL { url in
expectedCount -= 1
guard let url = url else {
print("No url found for asset")
return
var imageURLs = [URL]()
results.forEach { result in
let semaphore = DispatchSemaphore(value: 0)
result.itemProvider.loadObject(ofClass: UIImage.self, completionHandler: { [weak self] (object, error) in
defer {
semaphore.signal()
}
assetURLs.append(url)

if expectedCount == 0 {
completed(assetURLs)
guard let self = self else { return }
if let image = object as? UIImage {
let id = UUID().uuidString + ".jpg"
let fileManager = FileManager.default
let appSupportDirectory = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
let imageURL = appSupportDirectory.appendingPathComponent(id)
if !fileManager.fileExists(atPath: appSupportDirectory.path) {
try! fileManager.createDirectory(at: appSupportDirectory, withIntermediateDirectories: true, attributes: nil)
}

if let imageData = image.jpegData(compressionQuality: 0.7) {
print(fileManager.createFile(atPath: imageURL.path, contents: imageData, attributes: nil))
imageURLs.append(imageURL)
} else {
print("Could not retrieve image data")
}

if results.count == imageURLs.count {
print("Received \(imageURLs.count) images")
self.parent.didPickPhotos(imageURLs)
}

} else {
if let object {
print(object)
}
if let error {
print(error)
}
}
}

})
semaphore.wait()
}

parent.presentationMode.wrappedValue.dismiss()
}

deinit {

}
}
}

private extension PHAsset {
// From https://stackoverflow.com/questions/38183613/how-to-get-url-for-a-phasset
func getURL(completionHandler : @escaping ((_ responseURL : URL?) -> Void)){
if self.mediaType == .image {
let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
return true
}
self.requestContentEditingInput(with: options, completionHandler: {(contentEditingInput: PHContentEditingInput?, info: [AnyHashable : Any]) -> Void in
completionHandler(contentEditingInput!.fullSizeImageURL as URL?)
})
} else if self.mediaType == .video {
let options: PHVideoRequestOptions = PHVideoRequestOptions()
options.version = .original
PHImageManager.default().requestAVAsset(forVideo: self, options: options, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [AnyHashable : Any]?) -> Void in
if let urlAsset = asset as? AVURLAsset {
let localVideoUrl: URL = urlAsset.url as URL
completionHandler(localVideoUrl)
} else {
completionHandler(nil)
}
})
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ final class MyUploader: ObservableObject {
}

init() {
let credentials = Transloadit.Credentials(key: "Ru1rwq3ITrgSEDtgna6SGZa4yY71YJgW", secret: "Xo6xlnn42cfBkNxLSDWJNCQoSNL0j1aFB9wNyaAR")
self.transloadit = Transloadit(credentials: credentials, session: URLSession.shared)
let credentials = Transloadit.Credentials(key: "", secret: "")
self.transloadit = Transloadit(credentials: credentials, sessionConfiguration: .default)
//self.transloadit = Transloadit(credentials: credentials, sessionConfiguration: .background(withIdentifier: "com.transloadit.bg_sample"))
self.transloadit.fileDelegate = self
}

Expand Down

0 comments on commit 43fa6fc

Please sign in to comment.