-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathAsyncAwait.swift
199 lines (192 loc) · 8.68 KB
/
AsyncAwait.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// 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 Foundation
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
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:
/// - maxSize: The maximum size in bytes to download. If the download exceeds this size,
/// the task will be cancelled and an error will be thrown.
/// - Throws: An error if the operation failed, for example if the data exceeded `maxSize`.
/// - Returns: Data object.
func data(maxSize: Int64) async throws -> sending Data {
return try await withCheckedThrowingContinuation { continuation in
_ = 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.
/// - onProgress: An optional closure function to return a `Progress` instance while the
/// upload proceeds.
/// - Throws: An error if the operation failed, for example if Storage was unreachable.
/// - Returns: StorageMetadata with additional information about the object being uploaded.
func putDataAsync(_ uploadData: Data,
metadata: StorageMetadata? = nil,
onProgress: ((Progress?) -> Void)? = nil) async throws
-> sending StorageMetadata {
guard let onProgress = onProgress else {
return try await withCheckedThrowingContinuation { continuation in
self.putData(uploadData, metadata: metadata) { result in
continuation.resume(with: result)
}
}
}
let uploadTask = putData(uploadData, metadata: metadata)
return try await withCheckedThrowingContinuation { continuation in
uploadTask.observe(.progress) {
onProgress($0.progress)
}
uploadTask.observe(.success) { _ in
continuation.resume(with: .success(uploadTask.metadata!))
}
uploadTask.observe(.failure) { snapshot in
continuation.resume(with: .failure(
snapshot.error ?? StorageError
.internalError(message: "Internal Storage Error in putDataAsync")
))
}
}
}
/// 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.
/// - onProgress: An optional closure function to return a `Progress` instance while the
/// upload proceeds.
/// - Throws: An error if the operation failed, for example if no file was present at the
/// specified `url`.
/// - Returns: `StorageMetadata` with additional information about the object being uploaded.
func putFileAsync(from url: URL,
metadata: StorageMetadata? = nil,
onProgress: ((Progress?) -> Void)? = nil) async throws
-> sending StorageMetadata {
guard let onProgress = onProgress else {
return try await withCheckedThrowingContinuation { continuation in
self.putFile(from: url, metadata: metadata) { result in
continuation.resume(with: result)
}
}
}
let uploadTask = putFile(from: url, metadata: metadata)
return try await withCheckedThrowingContinuation { continuation in
uploadTask.observe(.progress) {
onProgress($0.progress)
}
uploadTask.observe(.success) { _ in
continuation.resume(with: .success(uploadTask.metadata!))
}
uploadTask.observe(.failure) { snapshot in
continuation.resume(with: .failure(
snapshot.error ?? StorageError
.internalError(message: "Internal Storage Error in putFileAsync")
))
}
}
}
/// 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.
/// - onProgress: An optional closure function to return a `Progress` instance while the
/// download proceeds.
/// - Throws: An error if the operation failed, for example if Storage was unreachable
/// or `fileURL` did not reference a valid path on disk.
/// - Returns: A `URL` pointing to the file path of the downloaded file.
func writeAsync(toFile fileURL: URL,
onProgress: ((Progress?) -> Void)? = nil) async throws -> sending URL {
guard let onProgress = onProgress else {
return try await withCheckedThrowingContinuation { continuation in
_ = self.write(toFile: fileURL) { result in
continuation.resume(with: result)
}
}
}
let downloadTask = write(toFile: fileURL)
return try await withCheckedThrowingContinuation { continuation in
downloadTask.observe(.progress) {
onProgress($0.progress)
}
downloadTask.observe(.success) { _ in
continuation.resume(with: .success(fileURL))
}
downloadTask.observe(.failure) { snapshot in
continuation.resume(with: .failure(
snapshot.error ?? StorageError
.internalError(message: "Internal Storage Error in writeAsync")
))
}
}
}
/// 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.
/// - Throws: An error if the operation failed, for example if Storage was unreachable
/// or the storage reference referenced an invalid path.
/// - Returns: A `StorageListResult` containing the contents of the storage reference.
func list(maxResults: Int64) async throws -> sending StorageListResult {
typealias ListContinuation = CheckedContinuation<StorageListResult, Error>
return try await withCheckedThrowingContinuation { (continuation: ListContinuation) in
self.list(maxResults: maxResults) { 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.
/// - pageToken: A page token from a previous call to list.
/// - Throws:
/// - An error if the operation failed, for example if Storage was unreachable
/// or the storage reference referenced an invalid path.
/// - Returns:
/// - completion A `Result` enum with either the list or an `Error`.
func list(maxResults: Int64, pageToken: String) async throws -> sending StorageListResult {
typealias ListContinuation = CheckedContinuation<StorageListResult, Error>
return try await withCheckedThrowingContinuation { (continuation: ListContinuation) in
self.list(maxResults: maxResults, pageToken: pageToken) { result in
continuation.resume(with: result)
}
}
}
}