FIRStorageReference.m 18 KB

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