mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
585 lines
24 KiB
Swift
585 lines
24 KiB
Swift
// Copyright 2022 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 Foundation
|
|
|
|
/// `StorageReference` represents a reference to a Google Cloud Storage object. Developers can
|
|
/// upload and download objects, as well as get/set object metadata, and delete an object at the
|
|
/// path. See the [Cloud docs](https://cloud.google.com/storage/) for more details.
|
|
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
|
|
@objc(FIRStorageReference) open class StorageReference: NSObject {
|
|
// MARK: - Public APIs
|
|
|
|
/// The `Storage` service object which created this reference.
|
|
@objc public let storage: Storage
|
|
|
|
/// The name of the Google Cloud Storage bucket associated with this reference.
|
|
/// For example, in `gs://bucket/path/to/object.txt`, the bucket would be 'bucket'.
|
|
@objc public var bucket: String {
|
|
return path.bucket
|
|
}
|
|
|
|
/// The full path to this object, not including the Google Cloud Storage bucket.
|
|
/// In `gs://bucket/path/to/object.txt`, the full path would be: `path/to/object.txt`.
|
|
@objc public var fullPath: String {
|
|
return path.object ?? ""
|
|
}
|
|
|
|
/// The short name of the object associated with this reference.
|
|
///
|
|
/// In `gs://bucket/path/to/object.txt`, the name of the object would be `object.txt`.
|
|
@objc public var name: String {
|
|
return (path.object as? NSString)?.lastPathComponent ?? ""
|
|
}
|
|
|
|
/// Creates a new `StorageReference` pointing to the root object.
|
|
/// - Returns: A new `StorageReference` pointing to the root object.
|
|
@objc open func root() -> StorageReference {
|
|
return StorageReference(storage: storage, path: path.root())
|
|
}
|
|
|
|
/// Creates a new `StorageReference` pointing to the parent of the current reference
|
|
/// or `nil` if this instance references the root location.
|
|
/// ```
|
|
/// For example:
|
|
/// path = foo/bar/baz parent = foo/bar
|
|
/// path = foo parent = (root)
|
|
/// path = (root) parent = nil
|
|
/// ```
|
|
/// - Returns: A new `StorageReference` pointing to the parent of the current reference.
|
|
@objc open func parent() -> StorageReference? {
|
|
guard let parentPath = path.parent() else {
|
|
return nil
|
|
}
|
|
return StorageReference(storage: storage, path: parentPath)
|
|
}
|
|
|
|
/// Creates a new `StorageReference` pointing to a child object of the current reference.
|
|
/// ```
|
|
/// path = foo child = bar newPath = foo/bar
|
|
/// path = foo/bar child = baz ntask.impl.snapshotwPath = foo/bar/baz
|
|
/// All leading and trailing slashes will be removed, and consecutive slashes will be
|
|
/// compressed to single slashes. For example:
|
|
/// child = /foo/bar newPath = foo/bar
|
|
/// child = foo/bar/ newPath = foo/bar
|
|
/// child = foo///bar newPath = foo/bar
|
|
/// ```
|
|
///
|
|
/// - Parameter path: The path to append to the current path.
|
|
/// - Returns: A new `StorageReference` pointing to a child location of the current reference.
|
|
@objc(child:) open func child(_ path: String) -> StorageReference {
|
|
return StorageReference(storage: storage, path: self.path.child(path))
|
|
}
|
|
|
|
// MARK: - Uploads
|
|
|
|
/// Asynchronously uploads data to the currently specified `StorageReference`,
|
|
/// without additional metadata.
|
|
/// This is not recommended for large files, and one should instead upload a file from disk.
|
|
/// - Parameters:
|
|
/// - uploadData: The data to upload.
|
|
/// - metadata: `StorageMetadata` containing additional information (MIME type, etc.)
|
|
/// about the object being uploaded.
|
|
/// - Returns: An instance of `StorageUploadTask`, which can be used to monitor or manage the
|
|
/// upload.
|
|
@objc(putData:metadata:)
|
|
@discardableResult
|
|
open func putData(_ uploadData: Data, metadata: StorageMetadata? = nil) -> StorageUploadTask {
|
|
return putData(uploadData, metadata: metadata, completion: nil)
|
|
}
|
|
|
|
/// Asynchronously uploads data to the currently specified `StorageReference`.
|
|
/// This is not recommended for large files, and one should instead upload a file from disk.
|
|
/// - Parameter uploadData The data to upload.
|
|
/// - Returns: An instance of `StorageUploadTask`, which can be used to monitor or manage the
|
|
/// upload.
|
|
@objc(putData:) @discardableResult open func __putData(_ uploadData: Data) -> StorageUploadTask {
|
|
return putData(uploadData, metadata: nil, completion: nil)
|
|
}
|
|
|
|
/// Asynchronously uploads data to the currently specified `StorageReference`.
|
|
/// This is not recommended for large files, and one should instead upload a file from disk.
|
|
/// - Parameters:
|
|
/// - uploadData: The data to upload.
|
|
/// - metadata: `StorageMetadata` containing additional information (MIME type, etc.)
|
|
/// about the object being uploaded.
|
|
/// - completion: A closure that either returns the object metadata on success,
|
|
/// or an error on failure.
|
|
/// - Returns: An instance of `StorageUploadTask`, which can be used to monitor or manage the
|
|
/// upload.
|
|
@objc(putData:metadata:completion:) @discardableResult
|
|
open func putData(_ uploadData: Data,
|
|
metadata: StorageMetadata? = nil,
|
|
completion: ((_: StorageMetadata?, _: Error?) -> Void)?) -> StorageUploadTask {
|
|
let putMetadata = metadata ?? StorageMetadata()
|
|
if let path = path.object {
|
|
putMetadata.path = path
|
|
putMetadata.name = (path as NSString).lastPathComponent as String
|
|
}
|
|
let task = StorageUploadTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
data: uploadData,
|
|
metadata: putMetadata)
|
|
startAndObserveUploadTask(task: task, completion: completion)
|
|
return task
|
|
}
|
|
|
|
/// Asynchronously uploads a file to the currently specified `StorageReference`.
|
|
/// - 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: An instance of `StorageUploadTask`, which can be used to monitor or manage the
|
|
/// upload.
|
|
@objc(putFile:metadata:) @discardableResult
|
|
open func putFile(from fileURL: URL, metadata: StorageMetadata? = nil) -> StorageUploadTask {
|
|
return putFile(from: fileURL, metadata: metadata, completion: nil)
|
|
}
|
|
|
|
/// Asynchronously uploads a file to the currently specified `StorageReference`,
|
|
/// without additional metadata.
|
|
/// @param fileURL A URL representing the system file path of the object to be uploaded.
|
|
/// @return An instance of StorageUploadTask, which can be used to monitor or manage the upload.
|
|
@objc(putFile:) @discardableResult open func __putFile(from fileURL: URL) -> StorageUploadTask {
|
|
return putFile(from: fileURL, metadata: nil, completion: nil)
|
|
}
|
|
|
|
/// Asynchronously uploads a file to the currently specified `StorageReference`.
|
|
/// - 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.
|
|
/// - completion: A completion block that either returns the object metadata on success,
|
|
/// or an error on failure.
|
|
/// - Returns: An instance of `StorageUploadTask`, which can be used to monitor or manage the
|
|
/// upload.
|
|
@objc(putFile:metadata:completion:) @discardableResult
|
|
open func putFile(from fileURL: URL,
|
|
metadata: StorageMetadata? = nil,
|
|
completion: ((_: StorageMetadata?, _: Error?) -> Void)?) -> StorageUploadTask {
|
|
let putMetadata: StorageMetadata = metadata ?? StorageMetadata()
|
|
if let path = path.object {
|
|
putMetadata.path = path
|
|
putMetadata.name = (path as NSString).lastPathComponent as String
|
|
}
|
|
let task = StorageUploadTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
file: fileURL,
|
|
metadata: putMetadata)
|
|
startAndObserveUploadTask(task: task, completion: completion)
|
|
return task
|
|
}
|
|
|
|
// MARK: - Downloads
|
|
|
|
/// Asynchronously downloads the object at the `StorageReference` to a `Data` instance in memory.
|
|
/// A `Data` buffer 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, `write(toFile:)` may be a better
|
|
/// option.
|
|
/// - Parameters:
|
|
/// - maxSize: The maximum size in bytes to download. If the download exceeds this size,
|
|
/// the task will be cancelled and an error will be returned.
|
|
/// - completion: A completion block that either returns the object data on success,
|
|
/// or an error on failure.
|
|
/// - Returns: A `StorageDownloadTask` that can be used to monitor or manage the download.
|
|
@objc(dataWithMaxSize:completion:) @discardableResult
|
|
open func getData(maxSize: Int64,
|
|
completion: @escaping ((_: Data?, _: Error?) -> Void)) -> StorageDownloadTask {
|
|
let task = StorageDownloadTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
file: nil)
|
|
|
|
task.completionData = completion
|
|
let callbackQueue = storage.callbackQueue
|
|
|
|
task.observe(.success) { snapshot in
|
|
let error = self.checkSizeOverflow(task: snapshot.task, maxSize: maxSize)
|
|
callbackQueue.async {
|
|
if let completion = task.completionData {
|
|
let data = error == nil ? task.downloadData : nil
|
|
completion(data, error)
|
|
task.completionData = nil
|
|
}
|
|
}
|
|
}
|
|
task.observe(.failure) { snapshot in
|
|
callbackQueue.async {
|
|
task.completionData?(nil, snapshot.error)
|
|
task.completionData = nil
|
|
}
|
|
}
|
|
task.observe(.progress) { snapshot in
|
|
if let error = self.checkSizeOverflow(task: snapshot.task, maxSize: maxSize) {
|
|
task.cancel(withError: error)
|
|
}
|
|
}
|
|
task.enqueue()
|
|
return task
|
|
}
|
|
|
|
/// 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.
|
|
/// - Parameter completion: A completion block that either returns the URL on success,
|
|
/// or an error on failure.
|
|
@objc(downloadURLWithCompletion:)
|
|
open func downloadURL(completion: @escaping ((_: URL?, _: Error?) -> Void)) {
|
|
StorageGetDownloadURLTask.getDownloadURLTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
completion: completion)
|
|
}
|
|
|
|
/// 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.
|
|
/// - Throws: An error if the download URL could not be retrieved.
|
|
/// - Returns: The URL on success.
|
|
open func downloadURL() async throws -> URL {
|
|
return try await withCheckedThrowingContinuation { continuation in
|
|
self.downloadURL { result in
|
|
continuation.resume(with: result)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Asynchronously downloads the object at the current path to a specified system filepath.
|
|
/// - Parameter fileURL: A file system URL representing the path the object should be downloaded
|
|
/// to.
|
|
/// - Returns A `StorageDownloadTask` that can be used to monitor or manage the download.
|
|
@objc(writeToFile:) @discardableResult
|
|
open func write(toFile fileURL: URL) -> StorageDownloadTask {
|
|
return write(toFile: fileURL, completion: nil)
|
|
}
|
|
|
|
/// Asynchronously downloads the object at the current path to a specified system filepath.
|
|
/// - Parameters:
|
|
/// - fileURL: A file system URL representing the path the object should be downloaded to.
|
|
/// - completion: A closure that fires when the file download completes, passed either
|
|
/// a URL pointing to the file path of the downloaded file on success,
|
|
/// or an error on failure.
|
|
/// - Returns: A `StorageDownloadTask` that can be used to monitor or manage the download.
|
|
@objc(writeToFile:completion:) @discardableResult
|
|
open func write(toFile fileURL: URL,
|
|
completion: ((_: URL?, _: Error?) -> Void)?) -> StorageDownloadTask {
|
|
let task = StorageDownloadTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
file: fileURL)
|
|
|
|
if let completion {
|
|
task.completionURL = completion
|
|
let callbackQueue = storage.callbackQueue
|
|
|
|
task.observe(.success) { snapshot in
|
|
callbackQueue.async {
|
|
task.completionURL?(fileURL, nil)
|
|
task.completionURL = nil
|
|
}
|
|
}
|
|
task.observe(.failure) { snapshot in
|
|
callbackQueue.async {
|
|
task.completionURL?(nil, snapshot.error)
|
|
task.completionURL = nil
|
|
}
|
|
}
|
|
}
|
|
task.enqueue()
|
|
return task
|
|
}
|
|
|
|
// MARK: - List Support
|
|
|
|
/// Lists 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.
|
|
///
|
|
/// `listAll(completion:)` is only available for projects using Firebase Rules Version 2.
|
|
/// - Parameter completion: A completion handler that will be invoked with all items and prefixes
|
|
/// under
|
|
/// the current `StorageReference`.
|
|
@objc(listAllWithCompletion:)
|
|
open func listAll(completion: @escaping ((_: StorageListResult?, _: Error?) -> Void)) {
|
|
var prefixes = [StorageReference]()
|
|
var items = [StorageReference]()
|
|
|
|
weak var weakSelf = self
|
|
|
|
var paginatedCompletion: ((_: StorageListResult?, _: Error?) -> Void)?
|
|
paginatedCompletion = { (_ listResult: StorageListResult?, _ error: Error?) in
|
|
if let error {
|
|
completion(nil, error)
|
|
return
|
|
}
|
|
guard let strongSelf = weakSelf else { return }
|
|
guard let listResult = listResult else {
|
|
fatalError("internal error: both listResult and error are nil")
|
|
}
|
|
prefixes.append(contentsOf: listResult.prefixes)
|
|
items.append(contentsOf: listResult.items)
|
|
|
|
if let pageToken = listResult.pageToken {
|
|
StorageListTask.listTask(reference: strongSelf,
|
|
queue: strongSelf.storage.dispatchQueue,
|
|
pageSize: nil,
|
|
previousPageToken: pageToken,
|
|
completion: paginatedCompletion)
|
|
} else {
|
|
let result = StorageListResult(withPrefixes: prefixes, items: items, pageToken: nil)
|
|
|
|
// Break the retain cycle we set up indirectly by passing the callback to `nextPage`.
|
|
paginatedCompletion = nil
|
|
completion(result, nil)
|
|
}
|
|
}
|
|
|
|
StorageListTask.listTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
pageSize: nil,
|
|
previousPageToken: nil,
|
|
completion: paginatedCompletion)
|
|
}
|
|
|
|
/// Lists 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.
|
|
/// `listAll()` is only available for projects using Firebase Rules Version 2.
|
|
/// - Throws: An error if the list operation failed.
|
|
/// - Returns: All items and prefixes under the current `StorageReference`.
|
|
open func listAll() async throws -> StorageListResult {
|
|
return try await withCheckedThrowingContinuation { continuation in
|
|
self.listAll { result in
|
|
continuation.resume(with: result)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// List up to `maxResults` items (files) and prefixes (folders) under this StorageReference.
|
|
///
|
|
/// "/" 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 GCS will be
|
|
/// filtered.
|
|
///
|
|
/// Only available for projects using Firebase Rules Version 2.
|
|
/// - Parameters:
|
|
/// - maxResults: The maximum number of results to return in a single page. Must be
|
|
/// greater than 0 and at most 1000.
|
|
/// - completion: A completion handler that will be invoked with up to `maxResults` items and
|
|
/// prefixes under the current `StorageReference`.
|
|
@objc(listWithMaxResults:completion:)
|
|
open func list(maxResults: Int64,
|
|
completion: @escaping ((_: StorageListResult?, _: Error?) -> Void)) {
|
|
if maxResults <= 0 || maxResults > 1000 {
|
|
completion(nil, StorageError.invalidArgument(
|
|
message: "Argument 'maxResults' must be between 1 and 1000 inclusive."
|
|
))
|
|
} else {
|
|
StorageListTask.listTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
pageSize: maxResults,
|
|
previousPageToken: nil,
|
|
completion: completion)
|
|
}
|
|
}
|
|
|
|
/// Resumes a previous call to `list(maxResults:completion:)`, starting after a pagination token.
|
|
///
|
|
/// Returns the next set of items (files) and prefixes (folders) under this `StorageReference`.
|
|
///
|
|
/// "/" is treated as a path delimiter. Storage does not support unsupported object
|
|
/// paths that end with "/" or contain two consecutive "/"s. All invalid objects in GCS will be
|
|
/// filtered.
|
|
///
|
|
/// `list(maxResults:pageToken:completion:)`is only available for projects using Firebase Rules
|
|
/// Version 2.
|
|
/// - 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.
|
|
/// - completion: A completion handler that will be invoked with the next items and prefixes
|
|
/// under the current StorageReference.
|
|
@objc(listWithMaxResults:pageToken:completion:)
|
|
open func list(maxResults: Int64,
|
|
pageToken: String,
|
|
completion: @escaping ((_: StorageListResult?, _: Error?) -> Void)) {
|
|
if maxResults <= 0 || maxResults > 1000 {
|
|
completion(nil, StorageError.invalidArgument(
|
|
message: "Argument 'maxResults' must be between 1 and 1000 inclusive."
|
|
))
|
|
} else {
|
|
StorageListTask.listTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
pageSize: maxResults,
|
|
previousPageToken: pageToken,
|
|
completion: completion)
|
|
}
|
|
}
|
|
|
|
// MARK: - Metadata Operations
|
|
|
|
/// Retrieves metadata associated with an object at the current path.
|
|
/// - Parameter completion: A completion block which returns the object metadata on success,
|
|
/// or an error on failure.
|
|
@objc(metadataWithCompletion:)
|
|
open func getMetadata(completion: @escaping ((_: StorageMetadata?, _: Error?) -> Void)) {
|
|
StorageGetMetadataTask.getMetadataTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
completion: completion)
|
|
}
|
|
|
|
/// Retrieves metadata associated with an object at the current path.
|
|
/// - Throws: An error if the object metadata could not be retrieved.
|
|
/// - Returns: The object metadata on success.
|
|
open func getMetadata() async throws -> StorageMetadata {
|
|
return try await withCheckedThrowingContinuation { continuation in
|
|
self.getMetadata { result in
|
|
continuation.resume(with: result)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Updates the metadata associated with an object at the current path.
|
|
/// - Parameters:
|
|
/// - metadata: A `StorageMetadata` object with the metadata to update.
|
|
/// - completion: A completion block which returns the `StorageMetadata` on success,
|
|
/// or an error on failure.
|
|
@objc(updateMetadata:completion:)
|
|
open func updateMetadata(_ metadata: StorageMetadata,
|
|
completion: ((_: StorageMetadata?, _: Error?) -> Void)?) {
|
|
StorageUpdateMetadataTask.updateMetadataTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
metadata: metadata,
|
|
completion: completion)
|
|
}
|
|
|
|
/// Updates the metadata associated with an object at the current path.
|
|
/// - Parameter metadata: A `StorageMetadata` object with the metadata to update.
|
|
/// - Throws: An error if the metadata update operation failed.
|
|
/// - Returns: The object metadata on success.
|
|
open func updateMetadata(_ metadata: StorageMetadata) async throws -> StorageMetadata {
|
|
return try await withCheckedThrowingContinuation { continuation in
|
|
self.updateMetadata(metadata) { result in
|
|
continuation.resume(with: result)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Delete
|
|
|
|
/// Deletes the object at the current path.
|
|
/// - Parameter completion: A completion block which returns a nonnull error on failure.
|
|
@objc(deleteWithCompletion:)
|
|
open func delete(completion: ((_: Error?) -> Void)?) {
|
|
let completionWrap = { (_: Data?, error: Error?) in
|
|
if let completion {
|
|
completion(error)
|
|
}
|
|
}
|
|
StorageDeleteTask.deleteTask(reference: self,
|
|
queue: storage.dispatchQueue,
|
|
completion: completionWrap)
|
|
}
|
|
|
|
/// Deletes the object at the current path.
|
|
/// - Throws: An error if the delete operation failed.
|
|
open func delete() async throws {
|
|
return try await withCheckedThrowingContinuation { continuation in
|
|
self.delete { error in
|
|
if let error {
|
|
continuation.resume(throwing: error)
|
|
} else {
|
|
continuation.resume()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - NSObject overrides
|
|
|
|
/// NSObject override
|
|
@objc override open func copy() -> Any {
|
|
return StorageReference(storage: storage, path: path)
|
|
}
|
|
|
|
/// NSObject override
|
|
@objc override open func isEqual(_ object: Any?) -> Bool {
|
|
guard let ref = object as? StorageReference else {
|
|
return false
|
|
}
|
|
return storage == ref.storage && path == ref.path
|
|
}
|
|
|
|
/// NSObject override
|
|
@objc override public var hash: Int {
|
|
return storage.hash ^ path.bucket.hashValue
|
|
}
|
|
|
|
/// NSObject override
|
|
@objc override public var description: String {
|
|
return "gs://\(path.bucket)/\(path.object ?? "")"
|
|
}
|
|
|
|
// MARK: - Internal APIs
|
|
|
|
/// The current path which points to an object in the Google Cloud Storage bucket.
|
|
let path: StoragePath
|
|
|
|
override init() {
|
|
storage = Storage.storage()
|
|
let storageBucket = storage.app.options.storageBucket!
|
|
path = StoragePath(with: storageBucket)
|
|
}
|
|
|
|
init(storage: Storage, path: StoragePath) {
|
|
self.storage = storage
|
|
self.path = path
|
|
}
|
|
|
|
/// For maxSize API, return an error if the size is exceeded.
|
|
private func checkSizeOverflow(task: StorageTask, maxSize: Int64) -> NSError? {
|
|
if task.progress.totalUnitCount > maxSize || task.progress.completedUnitCount > maxSize {
|
|
return StorageError.downloadSizeExceeded(
|
|
total: task.progress.totalUnitCount,
|
|
maxSize: maxSize
|
|
) as NSError
|
|
}
|
|
return nil
|
|
}
|
|
|
|
private func startAndObserveUploadTask(task: StorageUploadTask,
|
|
completion: ((_: StorageMetadata?, _: Error?) -> Void)?) {
|
|
if let completion {
|
|
task.completionMetadata = completion
|
|
let callbackQueue = storage.callbackQueue
|
|
|
|
task.observe(.success) { snapshot in
|
|
callbackQueue.async {
|
|
task.completionMetadata?(snapshot.metadata, nil)
|
|
task.completionMetadata = nil
|
|
}
|
|
}
|
|
task.observe(.failure) { snapshot in
|
|
callbackQueue.async {
|
|
task.completionMetadata?(nil, snapshot.error)
|
|
task.completionMetadata = nil
|
|
}
|
|
}
|
|
}
|
|
task.enqueue()
|
|
}
|
|
}
|