StorageReference.swift 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. // Copyright 2022 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import Foundation
  15. import FirebaseStorageInternal
  16. /**
  17. * `StorageReference` represents a reference to a Google Cloud Storage object. Developers can
  18. * upload and download objects, as well as get/set object metadata, and delete an object at the
  19. * path. See the Cloud docs for more details: https://cloud.google.com/storage/
  20. */
  21. @objc(FIRStorageReference) open class StorageReference: NSObject {
  22. // MARK: - Public APIs
  23. /**
  24. * The `Storage` service object which created this reference.
  25. */
  26. @objc public let storage: Storage
  27. /**
  28. * The name of the Google Cloud Storage bucket associated with this reference.
  29. * For example, in `gs://bucket/path/to/object.txt`, the bucket would be 'bucket'.
  30. */
  31. @objc public let bucket: String
  32. /**
  33. * The full path to this object, not including the Google Cloud Storage bucket.
  34. * In `gs://bucket/path/to/object.txt`, the full path would be: `path/to/object.txt`
  35. */
  36. @objc public let fullPath: String
  37. /**
  38. * The short name of the object associated with this reference.
  39. * In `gs://bucket/path/to/object.txt`, the name of the object would be `object.txt`.
  40. */
  41. @objc public let name: String
  42. /**
  43. * Creates a new `StorageReference` pointing to the root object.
  44. * - Returns: A new `StorageReference` pointing to the root object.
  45. */
  46. @objc open func root() -> StorageReference {
  47. return StorageReference(impl: impl.root(), storage: storage)
  48. }
  49. /**
  50. * Creates a new `StorageReference` pointing to the parent of the current reference
  51. * or `nil` if this instance references the root location.
  52. * For example:
  53. * path = foo/bar/baz parent = foo/bar
  54. * path = foo parent = (root)
  55. * path = (root) parent = nil
  56. * - Returns: A new `StorageReference` pointing to the parent of the current reference.
  57. */
  58. @objc open func parent() -> StorageReference? {
  59. guard let parent = impl.parent() else {
  60. return nil
  61. }
  62. return StorageReference(impl: parent, storage: storage)
  63. }
  64. /**
  65. * Creates a new `StorageReference` pointing to a child object of the current reference.
  66. * path = foo child = bar newPath = foo/bar
  67. * path = foo/bar child = baz ntask.impl.snapshotwPath = foo/bar/baz
  68. * All leading and trailing slashes will be removed, and consecutive slashes will be
  69. * compressed to single slashes. For example:
  70. * child = /foo/bar newPath = foo/bar
  71. * child = foo/bar/ newPath = foo/bar
  72. * child = foo///bar newPath = foo/bar
  73. * - Parameter path The path to append to the current path.
  74. * - Returns: A new `StorageReference` pointing to a child location of the current reference.
  75. */
  76. @objc(child:) open func child(_ path: String) -> StorageReference {
  77. return StorageReference(impl: impl.child(path), storage: storage)
  78. }
  79. // MARK: - Uploads
  80. /**
  81. * Asynchronously uploads data to the currently specified `StorageReference`,
  82. * without additional metadata.
  83. * This is not recommended for large files, and one should instead upload a file from disk.
  84. * - Parameters:
  85. * - uploadData: The data to upload.
  86. * - metadata: `StorageMetadata` containing additional information (MIME type, etc.)
  87. * about the object being uploaded.
  88. * - Returns: An instance of `StorageUploadTask`, which can be used to monitor or manage the upload.
  89. */
  90. @objc(putData:metadata:)
  91. @discardableResult
  92. open func putData(_ uploadData: Data, metadata: StorageMetadata? = nil) -> StorageUploadTask {
  93. return StorageUploadTask(impl.put(uploadData, metadata: metadata?.impl))
  94. }
  95. /**
  96. * Asynchronously uploads data to the currently specified `StorageReference`.
  97. * This is not recommended for large files, and one should instead upload a file from disk.
  98. * - Parameter uploadData The data to upload.
  99. * - Returns: An instance of `StorageUploadTask`, which can be used to monitor or manage the upload.
  100. */
  101. @objc(putData:) @discardableResult open func __putData(_ uploadData: Data) -> StorageUploadTask {
  102. return StorageUploadTask(impl.put(uploadData))
  103. }
  104. /**
  105. * Asynchronously uploads data to the currently specified `StorageReference`.
  106. * This is not recommended for large files, and one should instead upload a file from disk.
  107. * - Parameters:
  108. * - uploadData: The data to upload.
  109. * - metadata: `StorageMetadata` containing additional information (MIME type, etc.)
  110. * about the object being uploaded.
  111. * - completion: A closure that either returns the object metadata on success,
  112. * or an error on failure.
  113. * - Returns: An instance of `StorageUploadTask`, which can be used to monitor or manage the upload.
  114. */
  115. @objc(putData:metadata:completion:) @discardableResult
  116. open func putData(_ uploadData: Data,
  117. metadata: StorageMetadata? = nil,
  118. completion: ((_: StorageMetadata?, _: Error?) -> Void)?) -> StorageUploadTask {
  119. return StorageUploadTask(impl.put(uploadData, metadata: metadata?.impl) { impl, error in
  120. if let completion = completion {
  121. self.adaptMetadataCallback(completion: completion)(impl, error)
  122. }
  123. })
  124. }
  125. /**
  126. * Asynchronously uploads a file to the currently specified `StorageReference`.
  127. * - Parameters:
  128. * - fileURL: A URL representing the system file path of the object to be uploaded.
  129. * - metadata: `StorageMetadata` containing additional information (MIME type, etc.)
  130. * about the object being uploaded.
  131. * - Returns: An instance of `StorageUploadTask`, which can be used to monitor or manage the upload.
  132. */
  133. @objc(putFile:metadata:) @discardableResult
  134. open func putFile(from fileURL: URL, metadata: StorageMetadata? = nil) -> StorageUploadTask {
  135. return StorageUploadTask(impl.putFile(fileURL, metadata: metadata?.impl))
  136. }
  137. /**
  138. * Asynchronously uploads a file to the currently specified `StorageReference`,
  139. * without additional metadata.
  140. * @param fileURL A URL representing the system file path of the object to be uploaded.
  141. * @return An instance of StorageUploadTask, which can be used to monitor or manage the upload.
  142. */
  143. @objc(putFile:) @discardableResult open func __putFile(from fileURL: URL) -> StorageUploadTask {
  144. return StorageUploadTask(impl.putFile(fileURL))
  145. }
  146. /**
  147. * Asynchronously uploads a file to the currently specified `StorageReference`.
  148. * - Parameters:
  149. * - fileURL: A URL representing the system file path of the object to be uploaded.
  150. * - metadata: `StorageMetadata` containing additional information (MIME type, etc.)
  151. * about the object being uploaded.
  152. * - completion: A completion block that either returns the object metadata on success,
  153. * or an error on failure.
  154. * - Returns: An instance of `StorageUploadTask`, which can be used to monitor or manage the upload.
  155. */
  156. @objc(putFile:metadata:completion:) @discardableResult
  157. open func putFile(from fileURL: URL,
  158. metadata: StorageMetadata? = nil,
  159. completion: ((_: StorageMetadata?, _: Error?) -> Void)?) -> StorageUploadTask {
  160. return StorageUploadTask(impl.putFile(fileURL, metadata: metadata?.impl) { impl, error in
  161. if let completion = completion {
  162. self.adaptMetadataCallback(completion: completion)(impl, error)
  163. }
  164. })
  165. }
  166. // MARK: - Downloads
  167. /**
  168. * Asynchronously downloads the object at the `StorageReference` to a `Data` instance in memory.
  169. * A `Data` buffer of the provided max size will be allocated, so ensure that the device has enough free
  170. * memory to complete the download. For downloading large files, `write(toFile:)` may be a better option.
  171. * - Parameters:
  172. * - maxSize: The maximum size in bytes to download. If the download exceeds this size,
  173. * the task will be cancelled and an error will be returned.
  174. * - completion: A completion block that either returns the object data on success,
  175. * or an error on failure.
  176. * - Returns: An `StorageDownloadTask` that can be used to monitor or manage the download.
  177. */
  178. @objc(dataWithMaxSize:completion:) @discardableResult
  179. open func getData(maxSize: Int64,
  180. completion: @escaping ((_: Data?, _: Error?) -> Void)) -> StorageDownloadTask {
  181. return StorageDownloadTask(impl.data(withMaxSize: maxSize, completion: completion))
  182. }
  183. /**
  184. * Asynchronously retrieves a long lived download URL with a revokable token.
  185. * This can be used to share the file with others, but can be revoked by a developer
  186. * in the Firebase Console.
  187. * - Parameter completion A completion block that either returns the URL on success,
  188. * or an error on failure.
  189. */
  190. @objc(downloadURLWithCompletion:)
  191. open func downloadURL(completion: @escaping ((_: URL?, _: Error?) -> Void)) {
  192. impl.downloadURL(completion: completion)
  193. }
  194. #if compiler(>=5.5) && canImport(_Concurrency)
  195. /**
  196. * Asynchronously retrieves a long lived download URL with a revokable token.
  197. * This can be used to share the file with others, but can be revoked by a developer
  198. * in the Firebase Console.
  199. * - Throws: An error if the download URL could not be retrieved.
  200. * - Returns: The URL on success.
  201. */
  202. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  203. open func downloadURL() async throws -> URL {
  204. return try await impl.downloadURL()
  205. }
  206. #endif // compiler(>=5.5) && canImport(_Concurrency)
  207. /**
  208. * Asynchronously downloads the object at the current path to a specified system filepath.
  209. * - Parameter fileURL A file system URL representing the path the object should be downloaded to.
  210. * - Returns An `StorageDownloadTask` that can be used to monitor or manage the download.
  211. */
  212. @objc(writeToFile:) @discardableResult
  213. open func write(toFile fileURL: URL) -> StorageDownloadTask {
  214. return StorageDownloadTask(impl.write(toFile: fileURL))
  215. }
  216. /**
  217. * Asynchronously downloads the object at the current path to a specified system filepath.
  218. * - Parameters:
  219. * - fileURL: A file system URL representing the path the object should be downloaded to.
  220. * - completion: A closure that fires when the file download completes, passed either
  221. * a URL pointing to the file path of the downloaded file on success,
  222. * or an error on failure.
  223. * - Returns: A `StorageDownloadTask` that can be used to monitor or manage the download.
  224. */
  225. @objc(writeToFile:completion:) @discardableResult
  226. open func write(toFile fileURL: URL,
  227. completion: ((_: URL?, _: Error?) -> Void)?) -> StorageDownloadTask {
  228. return StorageDownloadTask(impl.write(toFile: fileURL, completion: completion))
  229. }
  230. // MARK: - List Support
  231. /**
  232. * Lists all items (files) and prefixes (folders) under this `StorageReference`.
  233. *
  234. * This is a helper method for calling `list()` repeatedly until there are no more results.
  235. * Consistency of the result is not guaranteed if objects are inserted or removed while this
  236. * operation is executing. All results are buffered in memory.
  237. *
  238. * `listAll(completion:)` is only available for projects using Firebase Rules Version 2.
  239. *
  240. * - Parameter completion A completion handler that will be invoked with all items and prefixes under
  241. * the current `StorageReference`.
  242. */
  243. @objc(listAllWithCompletion:)
  244. open func listAll(completion: @escaping ((_: StorageListResult?, _: Error?) -> Void)) {
  245. impl.listAll { listResult, error in
  246. if error != nil {
  247. completion(nil, error)
  248. } else {
  249. completion(StorageListResult(listResult), error)
  250. }
  251. }
  252. }
  253. #if compiler(>=5.5) && canImport(_Concurrency)
  254. /**
  255. * Lists all items (files) and prefixes (folders) under this StorageReference.
  256. *
  257. * This is a helper method for calling list() repeatedly until there are no more results.
  258. * Consistency of the result is not guaranteed if objects are inserted or removed while this
  259. * operation is executing. All results are buffered in memory.
  260. *
  261. * `listAll()` is only available for projects using Firebase Rules Version 2.
  262. *
  263. * - Throws: An error if the list operation failed.
  264. * - Returns: All items and prefixes under the current `StorageReference`.
  265. */
  266. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  267. open func listAll() async throws -> StorageListResult {
  268. return try await StorageListResult(impl.listAll())
  269. }
  270. #endif // compiler(>=5.5) && canImport(_Concurrency)
  271. /**
  272. * List up to `maxResults` items (files) and prefixes (folders) under this StorageReference.
  273. *
  274. * "/" is treated as a path delimiter. Firebase Storage does not support unsupported object
  275. * paths that end with "/" or contain two consecutive "/"s. All invalid objects in GCS will be
  276. * filtered.
  277. *
  278. * `list(maxResults:completion:)` is only available for projects using Firebase Rules Version 2.
  279. *
  280. * - Parameters:
  281. * - maxResults: The maximum number of results to return in a single page. Must be greater
  282. * than 0 and at most 1000.
  283. * - completion: A completion handler that will be invoked with up to `maxResults` items and
  284. * prefixes under the current `StorageReference`.
  285. */
  286. @objc(listWithMaxResults:completion:)
  287. open func list(maxResults: Int64,
  288. completion: @escaping ((_: StorageListResult?, _: Error?) -> Void)) {
  289. impl.list(withMaxResults: maxResults) { listResult, error in
  290. if error != nil {
  291. completion(nil, error)
  292. } else {
  293. completion(StorageListResult(listResult), error)
  294. }
  295. }
  296. }
  297. /**
  298. * Resumes a previous call to `list(maxResults:completion:)`, starting after a pagination token.
  299. * Returns the next set of items (files) and prefixes (folders) under this `StorageReference`.
  300. *
  301. * "/" is treated as a path delimiter. Storage does not support unsupported object
  302. * paths that end with "/" or contain two consecutive "/"s. All invalid objects in GCS will be
  303. * filtered.
  304. *
  305. * `list(maxResults:pageToken:completion:)`is only available for projects using Firebase Rules
  306. * Version 2.
  307. *
  308. * - Parameters:
  309. * - maxResults: The maximum number of results to return in a single page. Must be greater
  310. * than 0 and at most 1000.
  311. * - pageToken: A page token from a previous call to list.
  312. * - completion: A completion handler that will be invoked with the next items and prefixes
  313. * under the current StorageReference.
  314. */
  315. @objc(listWithMaxResults:pageToken:completion:)
  316. open func list(maxResults: Int64,
  317. pageToken: String,
  318. completion: @escaping ((_: StorageListResult?, _: Error?) -> Void)) {
  319. impl.list(withMaxResults: maxResults, pageToken: pageToken) { listResult, error in
  320. if error != nil {
  321. completion(nil, error)
  322. } else {
  323. completion(StorageListResult(listResult), error)
  324. }
  325. }
  326. }
  327. // MARK: - Metadata Operations
  328. /**
  329. * Retrieves metadata associated with an object at the current path.
  330. * - Parameter completion A completion block which returns the object metadata on success,
  331. * or an error on failure.
  332. */
  333. @objc(metadataWithCompletion:)
  334. open func getMetadata(completion: @escaping ((_: StorageMetadata?, _: Error?) -> Void)) {
  335. impl.metadata { impl, error in
  336. self.adaptMetadataCallback(completion: completion)(impl, error)
  337. }
  338. }
  339. #if compiler(>=5.5) && canImport(_Concurrency)
  340. /**
  341. * Retrieves metadata associated with an object at the current path.
  342. * - Throws: An error if the object metadata could not be retrieved.
  343. * - Returns: The object metadata on success.
  344. */
  345. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  346. open func getMetadata() async throws -> StorageMetadata {
  347. return try await StorageMetadata(impl: impl.metadata())
  348. }
  349. #endif // compiler(>=5.5) && canImport(_Concurrency)
  350. /**
  351. * Updates the metadata associated with an object at the current path.
  352. * - Parameters:
  353. * - metadata: A `StorageMetadata` object with the metadata to update.
  354. * - completion: A completion block which returns the `StorageMetadata` on success,
  355. * or an error on failure.
  356. */
  357. @objc(updateMetadata:completion:)
  358. open func updateMetadata(_ metadata: StorageMetadata,
  359. completion: ((_: StorageMetadata?, _: Error?) -> Void)?) {
  360. impl.update(metadata.impl) { impl, error in
  361. if let completion = completion {
  362. self.adaptMetadataCallback(completion: completion)(impl, error)
  363. }
  364. }
  365. }
  366. #if compiler(>=5.5) && canImport(_Concurrency)
  367. /**
  368. * Updates the metadata associated with an object at the current path.
  369. * - Parameter metadata A `StorageMetadata` object with the metadata to update.
  370. * - Throws: An error if the metadata update operation failed.
  371. * - Returns: The object metadata on success.
  372. */
  373. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  374. open func updateMetadata(_ metadata: StorageMetadata) async throws -> StorageMetadata {
  375. return try await StorageMetadata(impl: impl.update(metadata.impl))
  376. }
  377. #endif // compiler(>=5.5) && canImport(_Concurrency)
  378. private func adaptMetadataCallback(completion: @escaping (StorageMetadata?, Error?) -> Void) ->
  379. (_: FIRIMPLStorageMetadata?, _: Error?)
  380. -> Void {
  381. return { (impl: FIRIMPLStorageMetadata?, error: Error?) in
  382. if let impl = impl {
  383. completion(StorageMetadata(impl: impl), error)
  384. } else {
  385. completion(nil, error)
  386. }
  387. }
  388. }
  389. // MARK: - Delete
  390. /**
  391. * Deletes the object at the current path.
  392. * - Parameter completion A completion block which returns a nonnull error on failure.
  393. */
  394. @objc(deleteWithCompletion:)
  395. open func delete(completion: ((_: Error?) -> Void)?) {
  396. impl.delete(completion: completion)
  397. }
  398. #if compiler(>=5.5) && canImport(_Concurrency)
  399. /**
  400. * Deletes the object at the current path.
  401. * - Throws: An error if the delete operation failed.
  402. */
  403. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  404. open func delete() async throws {
  405. return try await impl.delete()
  406. }
  407. #endif // compiler(>=5.5) && canImport(_Concurrency)
  408. // MARK: - NSObject overrides
  409. @objc open func copy(_ zone: NSZone) -> StorageReference {
  410. return StorageReference(impl.copy() as! FIRIMPLStorageReference)
  411. }
  412. @objc override open func isEqual(_ object: Any?) -> Bool {
  413. guard let ref = object as? StorageReference else {
  414. return false
  415. }
  416. return impl.isEqual(ref.impl)
  417. }
  418. @objc override public var hash: Int {
  419. return impl.hash
  420. }
  421. @objc override public var description: String {
  422. return impl.description
  423. }
  424. // MARK: - Internal APIs
  425. private let impl: FIRIMPLStorageReference
  426. internal convenience init(_ impl: FIRIMPLStorageReference) {
  427. self.init(impl: impl, storage: Storage(app: impl.storage.app, bucket: impl.bucket))
  428. }
  429. internal init(impl: FIRIMPLStorageReference, storage: Storage) {
  430. self.impl = impl
  431. self.storage = storage
  432. bucket = impl.bucket
  433. fullPath = impl.fullPath
  434. name = impl.name
  435. }
  436. }