FIRStorageReference.m 18 KB

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