FIRStorageReference.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. // Copyright 2017 Google
  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 "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageReference.h"
  15. #import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
  16. #import "FirebaseStorage/Sources/FIRStorageDeleteTask.h"
  17. #import "FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h"
  18. #import "FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h"
  19. #import "FirebaseStorage/Sources/FIRStorageGetMetadataTask.h"
  20. #import "FirebaseStorage/Sources/FIRStorageListResult_Private.h"
  21. #import "FirebaseStorage/Sources/FIRStorageListTask.h"
  22. #import "FirebaseStorage/Sources/FIRStorageMetadata_Private.h"
  23. #import "FirebaseStorage/Sources/FIRStorageReference_Private.h"
  24. #import "FirebaseStorage/Sources/FIRStorageTaskSnapshot_Private.h"
  25. #import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
  26. #import "FirebaseStorage/Sources/FIRStorageUpdateMetadataTask.h"
  27. #import "FirebaseStorage/Sources/FIRStorageUploadTask_Private.h"
  28. #import "FirebaseStorage/Sources/FIRStorageUtils.h"
  29. #import "FirebaseStorage/Sources/FIRStorage_Private.h"
  30. #import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageTaskSnapshot.h"
  31. #import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
  32. #if SWIFT_PACKAGE
  33. @import GTMSessionFetcherCore;
  34. #else
  35. #import <GTMSessionFetcher/GTMSessionFetcher.h>
  36. #import <GTMSessionFetcher/GTMSessionFetcherService.h>
  37. #endif
  38. @implementation FIRStorageReference
  39. - (instancetype)init {
  40. FIRStorage *storage = [FIRStorage storage];
  41. NSString *storageBucket = storage.app.options.storageBucket;
  42. FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:storageBucket object:nil];
  43. FIRStorageReference *reference = [self initWithStorage:storage path:path];
  44. return reference;
  45. }
  46. - (instancetype)initWithStorage:(FIRStorage *)storage path:(FIRStoragePath *)path {
  47. self = [super init];
  48. if (self) {
  49. _storage = storage;
  50. _path = path;
  51. }
  52. return self;
  53. }
  54. #pragma mark - NSObject overrides
  55. - (instancetype)copyWithZone:(NSZone *)zone {
  56. FIRStorageReference *copiedReference = [[[self class] allocWithZone:zone] initWithStorage:_storage
  57. path:_path];
  58. return copiedReference;
  59. }
  60. - (BOOL)isEqual:(id)object {
  61. if (self == object) {
  62. return YES;
  63. }
  64. if (![object isKindOfClass:[FIRStorageReference class]]) {
  65. return NO;
  66. }
  67. BOOL isObjectEqual = [self isEqualToFIRStorageReference:(FIRStorageReference *)object];
  68. return isObjectEqual;
  69. }
  70. - (BOOL)isEqualToFIRStorageReference:(FIRStorageReference *)reference {
  71. BOOL isEqual = [_storage isEqual:reference.storage] && [_path isEqual:reference.path];
  72. return isEqual;
  73. }
  74. - (NSUInteger)hash {
  75. NSUInteger hash = [_storage hash] ^ [_path hash];
  76. return hash;
  77. }
  78. - (NSString *)description {
  79. return [self stringValue];
  80. }
  81. - (NSString *)stringValue {
  82. NSString *value = [NSString stringWithFormat:@"gs://%@/%@", _path.bucket, _path.object ?: @""];
  83. return value;
  84. }
  85. #pragma mark - Property Getters
  86. - (NSString *)bucket {
  87. NSString *bucket = _path.bucket;
  88. return bucket;
  89. }
  90. - (NSString *)fullPath {
  91. NSString *path = _path.object;
  92. if (!path) {
  93. path = @"";
  94. }
  95. return path;
  96. }
  97. - (NSString *)name {
  98. NSString *name = [_path.object lastPathComponent];
  99. if (!name) {
  100. name = @"";
  101. }
  102. return name;
  103. }
  104. #pragma mark - Path Operations
  105. - (FIRStorageReference *)root {
  106. FIRStoragePath *rootPath = [_path root];
  107. FIRStorageReference *rootReference = [[FIRStorageReference alloc] initWithStorage:_storage
  108. path:rootPath];
  109. return rootReference;
  110. }
  111. - (nullable FIRStorageReference *)parent {
  112. FIRStoragePath *parentPath = [_path parent];
  113. if (!parentPath) {
  114. return nil;
  115. }
  116. FIRStorageReference *parentReference = [[FIRStorageReference alloc] initWithStorage:_storage
  117. path:parentPath];
  118. return parentReference;
  119. }
  120. - (FIRStorageReference *)child:(NSString *)path {
  121. FIRStoragePath *childPath = [_path child:path];
  122. FIRStorageReference *childReference = [[FIRStorageReference alloc] initWithStorage:_storage
  123. path:childPath];
  124. return childReference;
  125. }
  126. #pragma mark - Uploads
  127. - (FIRStorageUploadTask *)putData:(NSData *)uploadData {
  128. return [self putData:uploadData metadata:nil completion:nil];
  129. }
  130. - (FIRStorageUploadTask *)putData:(NSData *)uploadData
  131. metadata:(nullable FIRStorageMetadata *)metadata {
  132. return [self putData:uploadData metadata:metadata completion:nil];
  133. }
  134. - (FIRStorageUploadTask *)putData:(NSData *)uploadData
  135. metadata:(nullable FIRStorageMetadata *)metadata
  136. completion:(nullable FIRStorageVoidMetadataError)completion {
  137. if (!metadata) {
  138. metadata = [[FIRStorageMetadata alloc] init];
  139. }
  140. metadata.path = _path.object;
  141. metadata.name = [_path.object lastPathComponent];
  142. FIRStorageUploadTask *task =
  143. [[FIRStorageUploadTask alloc] initWithReference:self
  144. fetcherService:_storage.fetcherServiceForApp
  145. dispatchQueue:_storage.dispatchQueue
  146. data:uploadData
  147. metadata:metadata];
  148. if (completion) {
  149. __block BOOL completed = NO;
  150. dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
  151. if (!callbackQueue) {
  152. callbackQueue = dispatch_get_main_queue();
  153. }
  154. [task observeStatus:FIRStorageTaskStatusSuccess
  155. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  156. dispatch_async(callbackQueue, ^{
  157. if (!completed) {
  158. completed = YES;
  159. completion(snapshot.metadata, nil);
  160. }
  161. });
  162. }];
  163. [task observeStatus:FIRStorageTaskStatusFailure
  164. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  165. dispatch_async(callbackQueue, ^{
  166. if (!completed) {
  167. completed = YES;
  168. completion(nil, snapshot.error);
  169. }
  170. });
  171. }];
  172. }
  173. [task enqueue];
  174. return task;
  175. }
  176. - (FIRStorageUploadTask *)putFile:(NSURL *)fileURL {
  177. return [self putFile:fileURL metadata:nil completion:nil];
  178. }
  179. - (FIRStorageUploadTask *)putFile:(NSURL *)fileURL
  180. metadata:(nullable FIRStorageMetadata *)metadata {
  181. return [self putFile:fileURL metadata:metadata completion:nil];
  182. }
  183. - (FIRStorageUploadTask *)putFile:(NSURL *)fileURL
  184. metadata:(nullable FIRStorageMetadata *)metadata
  185. completion:(nullable FIRStorageVoidMetadataError)completion {
  186. if (!metadata) {
  187. metadata = [[FIRStorageMetadata alloc] init];
  188. }
  189. metadata.path = _path.object;
  190. metadata.name = [_path.object lastPathComponent];
  191. FIRStorageUploadTask *task =
  192. [[FIRStorageUploadTask alloc] initWithReference:self
  193. fetcherService:_storage.fetcherServiceForApp
  194. dispatchQueue:_storage.dispatchQueue
  195. file:fileURL
  196. metadata:metadata];
  197. if (completion) {
  198. __block BOOL completed = NO;
  199. dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
  200. if (!callbackQueue) {
  201. callbackQueue = dispatch_get_main_queue();
  202. }
  203. [task observeStatus:FIRStorageTaskStatusSuccess
  204. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  205. dispatch_async(callbackQueue, ^{
  206. if (!completed) {
  207. completed = YES;
  208. completion(snapshot.metadata, nil);
  209. }
  210. });
  211. }];
  212. [task observeStatus:FIRStorageTaskStatusFailure
  213. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  214. dispatch_async(callbackQueue, ^{
  215. if (!completed) {
  216. completed = YES;
  217. completion(nil, snapshot.error);
  218. }
  219. });
  220. }];
  221. }
  222. [task enqueue];
  223. return task;
  224. }
  225. #pragma mark - Downloads
  226. - (FIRStorageDownloadTask *)dataWithMaxSize:(int64_t)size
  227. completion:(FIRStorageVoidDataError)completion {
  228. __block BOOL completed = NO;
  229. FIRStorageDownloadTask *task =
  230. [[FIRStorageDownloadTask alloc] initWithReference:self
  231. fetcherService:_storage.fetcherServiceForApp
  232. dispatchQueue:_storage.dispatchQueue
  233. file:nil];
  234. dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
  235. if (!callbackQueue) {
  236. callbackQueue = dispatch_get_main_queue();
  237. }
  238. [task observeStatus:FIRStorageTaskStatusSuccess
  239. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  240. FIRStorageDownloadTask *task = snapshot.task;
  241. dispatch_async(callbackQueue, ^{
  242. if (!completed) {
  243. completed = YES;
  244. completion(task.downloadData, nil);
  245. }
  246. });
  247. }];
  248. [task observeStatus:FIRStorageTaskStatusFailure
  249. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  250. dispatch_async(callbackQueue, ^{
  251. if (!completed) {
  252. completed = YES;
  253. completion(nil, snapshot.error);
  254. }
  255. });
  256. }];
  257. [task
  258. observeStatus:FIRStorageTaskStatusProgress
  259. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  260. FIRStorageDownloadTask *task = snapshot.task;
  261. if (task.progress.totalUnitCount > size || task.progress.completedUnitCount > size) {
  262. NSDictionary *infoDictionary =
  263. @{@"totalSize" : @(task.progress.totalUnitCount),
  264. @"maxAllowedSize" : @(size)};
  265. NSError *error =
  266. [FIRStorageErrors errorWithCode:FIRStorageErrorCodeDownloadSizeExceeded
  267. infoDictionary:infoDictionary];
  268. [task cancelWithError:error];
  269. }
  270. }];
  271. [task enqueue];
  272. return task;
  273. }
  274. - (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL {
  275. return [self writeToFile:fileURL completion:nil];
  276. }
  277. - (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL
  278. completion:(FIRStorageVoidURLError)completion {
  279. FIRStorageDownloadTask *task =
  280. [[FIRStorageDownloadTask alloc] initWithReference:self
  281. fetcherService:_storage.fetcherServiceForApp
  282. dispatchQueue:_storage.dispatchQueue
  283. file:fileURL];
  284. if (completion) {
  285. __block BOOL completed = NO;
  286. dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
  287. if (!callbackQueue) {
  288. callbackQueue = dispatch_get_main_queue();
  289. }
  290. [task observeStatus:FIRStorageTaskStatusSuccess
  291. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  292. dispatch_async(callbackQueue, ^{
  293. if (!completed) {
  294. completed = YES;
  295. completion(fileURL, nil);
  296. }
  297. });
  298. }];
  299. [task observeStatus:FIRStorageTaskStatusFailure
  300. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  301. dispatch_async(callbackQueue, ^{
  302. if (!completed) {
  303. completed = YES;
  304. completion(nil, snapshot.error);
  305. }
  306. });
  307. }];
  308. }
  309. [task enqueue];
  310. return task;
  311. }
  312. - (void)downloadURLWithCompletion:(FIRStorageVoidURLError)completion {
  313. FIRStorageGetDownloadURLTask *task =
  314. [[FIRStorageGetDownloadURLTask alloc] initWithReference:self
  315. fetcherService:_storage.fetcherServiceForApp
  316. dispatchQueue:_storage.dispatchQueue
  317. completion:completion];
  318. [task enqueue];
  319. }
  320. #pragma mark - List
  321. - (void)listWithMaxResults:(int64_t)maxResults completion:(FIRStorageVoidListError)completion {
  322. if (maxResults <= 0 || maxResults > 1000) {
  323. completion(nil,
  324. [FIRStorageUtils storageErrorWithDescription:
  325. @"Argument 'maxResults' must be between 1 and 1000 inclusive."
  326. code:FIRStorageErrorCodeInvalidArgument]);
  327. } else {
  328. FIRStorageListTask *task =
  329. [[FIRStorageListTask alloc] initWithReference:self
  330. fetcherService:_storage.fetcherServiceForApp
  331. dispatchQueue:_storage.dispatchQueue
  332. pageSize:@(maxResults)
  333. previousPageToken:nil
  334. completion:completion];
  335. [task enqueue];
  336. }
  337. }
  338. - (void)listWithMaxResults:(int64_t)maxResults
  339. pageToken:(NSString *)pageToken
  340. completion:(FIRStorageVoidListError)completion {
  341. if (maxResults <= 0 || maxResults > 1000) {
  342. completion(nil,
  343. [FIRStorageUtils storageErrorWithDescription:
  344. @"Argument 'maxResults' must be between 1 and 1000 inclusive."
  345. code:FIRStorageErrorCodeInvalidArgument]);
  346. } else {
  347. FIRStorageListTask *task =
  348. [[FIRStorageListTask alloc] initWithReference:self
  349. fetcherService:_storage.fetcherServiceForApp
  350. dispatchQueue:_storage.dispatchQueue
  351. pageSize:@(maxResults)
  352. previousPageToken:pageToken
  353. completion:completion];
  354. [task enqueue];
  355. }
  356. }
  357. - (void)listAllWithCompletion:(FIRStorageVoidListError)completion {
  358. NSMutableArray *prefixes = [NSMutableArray new];
  359. NSMutableArray *items = [NSMutableArray new];
  360. __weak FIRStorageReference *weakSelf = self;
  361. __block FIRStorageVoidListError paginatedCompletion =
  362. ^(FIRStorageListResult *listResult, NSError *error) {
  363. if (error) {
  364. completion(nil, error);
  365. return;
  366. }
  367. FIRStorageReference *strongSelf = weakSelf;
  368. if (!strongSelf) {
  369. return;
  370. }
  371. [prefixes addObjectsFromArray:listResult.prefixes];
  372. [items addObjectsFromArray:listResult.items];
  373. if (listResult.pageToken) {
  374. FIRStorageListTask *nextPage = [[FIRStorageListTask alloc]
  375. initWithReference:self
  376. fetcherService:strongSelf->_storage.fetcherServiceForApp
  377. dispatchQueue:strongSelf->_storage.dispatchQueue
  378. pageSize:nil
  379. previousPageToken:listResult.pageToken
  380. completion:paginatedCompletion];
  381. [nextPage enqueue];
  382. } else {
  383. FIRStorageListResult *result = [[FIRStorageListResult alloc] initWithPrefixes:prefixes
  384. items:items
  385. pageToken:nil];
  386. // Break the retain cycle we set up indirectly by passing the callback to `nextPage`.
  387. paginatedCompletion = nil;
  388. completion(result, nil);
  389. }
  390. };
  391. FIRStorageListTask *task =
  392. [[FIRStorageListTask alloc] initWithReference:self
  393. fetcherService:_storage.fetcherServiceForApp
  394. dispatchQueue:_storage.dispatchQueue
  395. pageSize:nil
  396. previousPageToken:nil
  397. completion:paginatedCompletion];
  398. [task enqueue];
  399. }
  400. #pragma mark - Metadata Operations
  401. - (void)metadataWithCompletion:(FIRStorageVoidMetadataError)completion {
  402. FIRStorageGetMetadataTask *task =
  403. [[FIRStorageGetMetadataTask alloc] initWithReference:self
  404. fetcherService:_storage.fetcherServiceForApp
  405. dispatchQueue:_storage.dispatchQueue
  406. completion:completion];
  407. [task enqueue];
  408. }
  409. - (void)updateMetadata:(FIRStorageMetadata *)metadata
  410. completion:(nullable FIRStorageVoidMetadataError)completion {
  411. FIRStorageUpdateMetadataTask *task =
  412. [[FIRStorageUpdateMetadataTask alloc] initWithReference:self
  413. fetcherService:_storage.fetcherServiceForApp
  414. dispatchQueue:_storage.dispatchQueue
  415. metadata:metadata
  416. completion:completion];
  417. [task enqueue];
  418. }
  419. #pragma mark - Delete
  420. - (void)deleteWithCompletion:(nullable FIRStorageVoidError)completion {
  421. FIRStorageDeleteTask *task =
  422. [[FIRStorageDeleteTask alloc] initWithReference:self
  423. fetcherService:_storage.fetcherServiceForApp
  424. dispatchQueue:_storage.dispatchQueue
  425. completion:completion];
  426. [task enqueue];
  427. }
  428. @end