| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- // 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.
- #if canImport(Combine) && swift(>=5.0)
- import Combine
- import FirebaseStorage
- import Foundation
- @available(swift 5.0)
- @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)
- public extension StorageReference {
- // MARK: - Uploads
- /// Asynchronously uploads data to the currently specified `StorageReference`.
- /// This is not recommended for large files, and one should instead upload a file from disk.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Parameters:
- /// - uploadData: The Data to upload.
- /// - metadata: metadata `StorageMetadata` containing additional information (MIME type, etc.)
- ///
- /// - Returns: A publisher emitting a `StorageMetadata` instance. The publisher will emit on the
- /// *main* thread.
- @discardableResult
- func putData(_ data: Data,
- metadata: StorageMetadata? = nil) -> Future<StorageMetadata, Error> {
- var task: StorageUploadTask?
- return Future<StorageMetadata, Error> { promise in
- task = self.putData(data, metadata: metadata) { result in
- promise(result)
- }
- }
- .handleEvents(receiveCancel: {
- task?.cancel()
- })
- .upstream
- }
- /// Asynchronously uploads a file to the currently specified `StorageReference`.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Parameters:
- /// - fileURL: A `URL` representing the system file path of the object to be uploaded.
- /// - metadata: `StorageMetadata` containing additional information (MIME type, etc.) about
- /// the object being uploaded.
- ///
- /// - Returns: A publisher emitting a `StorageMetadata` instance. The publisher will emit on the
- /// *main* thread.
- @discardableResult
- func putFile(from fileURL: URL,
- metadata: StorageMetadata? = nil)
- -> Future<StorageMetadata, Error> {
- var task: StorageUploadTask?
- return Future<StorageMetadata, Error> { promise in
- task = self.putFile(from: fileURL, metadata: metadata) { result in
- promise(result)
- }
- }
- .handleEvents(receiveCancel: {
- task?.cancel()
- })
- .upstream
- }
- // MARK: - Downloads
- /// Asynchronously downloads the object at the `StorageReference` to an `Data` object in memory.
- /// An `Data` 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.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - 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 returned.
- ///
- /// - Returns: A publisher emitting a `Data` instance. The publisher will emit on the *main*
- /// thread.
- @discardableResult
- func getData(maxSize size: Int64) -> Future<Data, Error> {
- var task: StorageDownloadTask?
- return Future<Data, Error> { promise in
- task = self.getData(maxSize: size) { result in
- promise(result)
- }
- }
- .handleEvents(receiveCancel: {
- task?.cancel()
- })
- .upstream
- }
- /// Asynchronously downloads the object at the current path to a specified system filepath.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Parameters:
- /// - fileURL: A file system URL representing the path the object should be downloaded to.
- ///
- /// - Returns: A publisher emitting a `URL` pointing to the file path of the downloaded file
- /// on success. The publisher will emit on the *main* thread.
- @discardableResult
- func write(toFile fileURL: URL) -> Future<URL, Error> {
- var task: StorageDownloadTask?
- return Future<URL, Error> { promise in
- task = self.write(toFile: fileURL) { result in
- promise(result)
- }
- }
- .handleEvents(receiveCancel: {
- task?.cancel()
- })
- .upstream
- }
- /// 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.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Returns: A publisher emitting a `URL` instance. The publisher will emit on the *main*
- /// thread.
- @discardableResult
- func downloadURL() -> Future<URL, Error> {
- Future<URL, Error> { promise in
- self.downloadURL { result in
- promise(result)
- }
- }
- }
- // MARK: - List Support
- /// List all items (files) and prefixes (folders) under this `StorageReference`.
- ///
- /// This is a helper method for calling `list()` repeatedly until there are no more results.
- /// Consistency of the result is not guaranteed if objects are inserted or removed while this
- /// operation is executing. All results are buffered in memory.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Remark:
- /// `listAll` is only available for projects using Firebase Rules Version 2.
- ///
- /// - Returns: A publisher emitting a `StorageListResult` instance. The publisher will emit on
- /// the *main* thread.
- @discardableResult
- func listAll() -> Future<StorageListResult, Error> {
- Future<StorageListResult, Error> { promise in
- self.listAll { result in
- promise(result)
- }
- }
- }
- /// List up to `maxResults` items (files) and prefixes (folders) under this `StorageReference`.
- ///
- /// Note that "/" is treated as a path delimiter. Firebase Storage does not support unsupported
- /// object
- /// paths that end with "/" or contain two consecutive "/"s. All invalid objects in Firebase
- /// Storage will be
- /// filtered.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Parameters:
- /// - maxResults: The maximum number of results to return in a single page. Must be greater
- /// than 0 and at most 1000.
- ///
- /// - Remark:
- /// `list(maxResults:)` is only available for projects using Firebase Rules Version 2.
- ///
- /// - Returns: A publisher emitting a `StorageListResult` instance. The publisher will emit on
- /// the *main* thread.
- @discardableResult
- func list(maxResults: Int64) -> Future<StorageListResult, Error> {
- Future<StorageListResult, Error> { promise in
- self.list(maxResults: maxResults) { result in
- promise(result)
- }
- }
- }
- /// Resumes a previous call to `list(maxResults:)`, starting after a pagination token.
- /// Returns the next set of items (files) and prefixes (folders) under this `StorageReference.
- ///
- /// Note that "/" is treated as a path delimiter. Firebase Storage does not support unsupported
- /// object
- /// paths that end with "/" or contain two consecutive "/"s. All invalid objects in Firebase
- /// Storage
- /// will be filtered out.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Parameters:
- /// - maxResults: The maximum number of results to return in a single page. Must be greater
- /// than 0 and at most 1000.
- /// - pageToken: A page token from a previous call to list.
- ///
- /// - Remark:
- /// `list(maxResults:pageToken:)` is only available for projects using Firebase Rules Version
- /// 2.
- ///
- /// - Returns: A publisher emitting a `StorageListResult` instance. The publisher will emit on
- /// the *main* thread.
- @discardableResult
- func list(maxResults: Int64, pageToken: String) -> Future<StorageListResult, Error> {
- Future<StorageListResult, Error> { promise in
- self.list(maxResults: maxResults, pageToken: pageToken) { result in
- promise(result)
- }
- }
- }
- // MARK: - Metadata Operations
- /// Retrieves metadata associated with an object at the current path.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Returns: A publisher emitting a `StorageMetadata` instance. The publisher will emit on the
- /// *main* thread.
- @discardableResult
- func getMetadata() -> Future<StorageMetadata, Error> {
- Future<StorageMetadata, Error> { promise in
- self.getMetadata { result in
- promise(result)
- }
- }
- }
- /// Updates the metadata associated with an object at the current path.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Parameters:
- /// - metadata: A `StorageMetadata` object with the metadata to update.
- ///
- /// - Returns: A publisher emitting a `StorageMetadata` instance. The publisher will emit on the
- /// *main* thread.
- @discardableResult
- func updateMetadata(_ metadata: StorageMetadata) -> Future<StorageMetadata, Error> {
- Future<StorageMetadata, Error> { promise in
- self.updateMetadata(metadata) { result in
- promise(result)
- }
- }
- }
- // MARK: - Delete
- /// Deletes the object at the current path.
- ///
- /// The publisher will emit events on the **main** thread.
- ///
- /// - Returns: A publisher that emits whether the call was successful or not. The publisher will
- /// emit on the *main* thread.
- @discardableResult
- func delete() -> Future<Bool, Error> {
- Future<Bool, Error> { promise in
- self.delete { error in
- if let error {
- promise(.failure(error))
- } else {
- promise(.success(true))
- }
- }
- }
- }
- }
- #endif // canImport(Combine) && swift(>=5.0)
|