Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storage async await #8289

Merged
merged 18 commits into from
Jul 23, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
/// The publisher will emit events on the **main** thread.
///
/// - Parameters:
/// - size: The maximum size in bytes to download. If the download exceeds this size
/// - size: The maximum size in bytes to download. If the download exceeds this size,
/// the task will be cancelled and an error will be returned.
///
/// - Returns: A publisher emitting a `Data` instance. The publisher will emit on the *main* thread.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ NS_SWIFT_NAME(putData(_:metadata:));
* Asynchronously downloads the object at the FIRStorageReference to an NSData object in memory.
* An NSData of the provided max size will be allocated, so ensure that the device has enough free
* memory to complete the download. For downloading large files, writeToFile may be a better option.
* @param size The maximum size in bytes to download. If the download exceeds this size
* @param size The maximum size in bytes to download. If the download exceeds this size,
* the task will be cancelled and an error will be returned.
* @param completion A completion block that either returns the object data on success,
* or an error on failure.
Expand All @@ -194,7 +194,7 @@ NS_SWIFT_NAME(putData(_:metadata:));
/**
* Asynchronously retrieves a long lived download URL with a revokable token.
* This can be used to share the file with others, but can be revoked by a developer
* in the Firebase Console if desired.
* in the Firebase Console.
* @param completion A completion block that either returns the URL on success,
* or an error on failure.
*/
Expand Down
6 changes: 6 additions & 0 deletions FirebaseStorageSwift/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 8.5.0-beta
- Added four APIs to augment automatically generated `async/await` APIs. See
details via Xcode completion and at the
[source](https://github.com/firebase/firebase-ios-sdk/blob/96d60a6d472b6fed1651d5e7a0e7495230c220ec/FirebaseStorageSwift/Sources/AsyncAwait.swift).
Feedback appreciated about Firebase and `async/await`. (#8289)

# v0.1
- Initial public beta release. Extends the Storage Reference API with the Swift
Result type for all APIs that return an optional value and optional Error.
Expand Down
92 changes: 92 additions & 0 deletions FirebaseStorageSwift/Sources/AsyncAwait.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import FirebaseStorage

#if swift(>=5.5)
@available(iOS 15, *)
public extension StorageReference {
/// Asynchronously downloads the object at the StorageReference to a Data object in memory.
/// A Data object of the provided max size will be allocated, so ensure that the device has
/// enough free memory to complete the download. For downloading large files, the `write`
/// API may be a better option.
///
/// - Parameters:
/// - size: The maximum size in bytes to download. If the download exceeds this size,
/// the task will be cancelled and an error will be thrown.
/// - Returns: Data object.
func data(maxSize: Int64) async throws -> Data {
typealias DataContinuation = CheckedContinuation<Data, Error>
return try await withCheckedThrowingContinuation { (continuation: DataContinuation) in
// TODO: Use task to handle progress and cancellation.
_ = self.getData(maxSize: maxSize) { result in
continuation.resume(with: result)
}
}
}

/// Asynchronously uploads data to the currently specified StorageReference.
/// This is not recommended for large files, and one should instead upload a file from disk
/// from the Firebase Console.
///
/// - Parameters:
/// - uploadData: The Data to upload.
/// - metadata: Optional StorageMetadata containing additional information (MIME type, etc.)
/// about the object being uploaded.
/// - Returns: StorageMetadata with additional information about the object being uploaded.
func putDataAsync(_ uploadData: Data,
metadata: StorageMetadata? = nil) async throws -> StorageMetadata {
typealias MetadataContinuation = CheckedContinuation<StorageMetadata, Error>
return try await withCheckedThrowingContinuation { (continuation: MetadataContinuation) in
// TODO: Use task to handle progress and cancellation.
_ = self.putData(uploadData, metadata: metadata) { result in
continuation.resume(with: result)
}
}
}

/// Asynchronously uploads a file to the currently specified StorageReference.
///
/// - Parameters:
/// - url: A URL representing the system file path of the object to be uploaded.
/// - metadata: Optional StorageMetadata containing additional information (MIME type, etc.)
/// about the object being uploaded.
/// - Returns: StorageMetadata with additional information about the object being uploaded.
func putFileAsync(from url: URL,
metadata: StorageMetadata? = nil) async throws -> StorageMetadata {
typealias MetadataContinuation = CheckedContinuation<StorageMetadata, Error>
return try await withCheckedThrowingContinuation { (continuation: MetadataContinuation) in
// TODO: Use task to handle progress and cancellation.
_ = self.putFile(from: url, metadata: metadata) { result in
continuation.resume(with: result)
}
}
}

/// Asynchronously downloads the object at the current path to a specified system filepath.
///
/// - Parameters:
/// - fileUrl: A URL representing the system file path of the object to be uploaded.
/// - Returns: URL pointing to the file path of the downloaded file.
func writeAsync(toFile fileURL: URL) async throws -> URL {
typealias URLContinuation = CheckedContinuation<URL, Error>
return try await withCheckedThrowingContinuation { (continuation: URLContinuation) in
// TODO: Use task to handle progress and cancellation.
_ = self.write(toFile: fileURL) { result in
continuation.resume(with: result)
}
}
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

import FirebaseStorage

private enum DataError: Error {
case internalInconsistency // Thrown when both value and error are nil.
}

/// Generates a closure that returns a `Result` type from a closure that returns an optional type
/// and `Error`.
///
Expand All @@ -31,19 +35,15 @@ private func getResultCallback<T>(completion: @escaping (Result<T, Error>) -> Vo
} else if let error = error {
completion(.failure(error))
} else {
completion(.failure(NSError(domain: "FirebaseStorageSwift",
code: -1,
userInfo: [NSLocalizedDescriptionKey:
"InternalError - Return type and Error code both nil in " +
"Storage Result generator"])))
completion(.failure(DataError.internalInconsistency))
}
}
}

public extension StorageReference {
/// Asynchronously retrieves a long lived download URL with a revokable token.
/// This can be used to share the file with others, but can be revoked by a developer
/// in the Firebase Console if desired.
/// in the Firebase Console.
///
/// - Parameters:
/// - completion: A completion block returning a `Result` enum with either a URL or an `Error`.
Expand All @@ -53,7 +53,7 @@ public extension StorageReference {

/// Asynchronously downloads the object at the `StorageReference` to a `Data` object.
/// A `Data` of the provided max size will be allocated, so ensure that the device has enough
/// memory to complete. For downloading large files, writeToFile may be a better option.
/// memory to complete. For downloading large files, the `write` API may be a better option.

/// - Parameters:
/// - maxSize: The maximum size in bytes to download.
Expand Down