FIRStorageReference.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  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 "FIRStorageReference.h"
  15. #import "FIRStorageConstants_Private.h"
  16. #import "FIRStorageDeleteTask.h"
  17. #import "FIRStorageDownloadTask_Private.h"
  18. #import "FIRStorageGetDownloadURLTask.h"
  19. #import "FIRStorageGetMetadataTask.h"
  20. #import "FIRStorageListResult_Private.h"
  21. #import "FIRStorageListTask.h"
  22. #import "FIRStorageMetadata_Private.h"
  23. #import "FIRStorageReference_Private.h"
  24. #import "FIRStorageTaskSnapshot.h"
  25. #import "FIRStorageTaskSnapshot_Private.h"
  26. #import "FIRStorageTask_Private.h"
  27. #import "FIRStorageUpdateMetadataTask.h"
  28. #import "FIRStorageUploadTask_Private.h"
  29. #import "FIRStorageUtils.h"
  30. #import "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. 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. completion(snapshot.metadata, nil);
  154. });
  155. }];
  156. [task observeStatus:FIRStorageTaskStatusFailure
  157. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  158. dispatch_async(callbackQueue, ^{
  159. completion(nil, snapshot.error);
  160. });
  161. }];
  162. }
  163. [task enqueue];
  164. return task;
  165. }
  166. - (FIRStorageUploadTask *)putFile:(NSURL *)fileURL {
  167. return [self putFile:fileURL metadata:nil completion:nil];
  168. }
  169. - (FIRStorageUploadTask *)putFile:(NSURL *)fileURL
  170. metadata:(nullable FIRStorageMetadata *)metadata {
  171. return [self putFile:fileURL metadata:metadata completion:nil];
  172. }
  173. - (FIRStorageUploadTask *)putFile:(NSURL *)fileURL
  174. metadata:(nullable FIRStorageMetadata *)metadata
  175. completion:(nullable FIRStorageVoidMetadataError)completion {
  176. if (!metadata) {
  177. metadata = [[FIRStorageMetadata alloc] init];
  178. }
  179. metadata.path = _path.object;
  180. metadata.name = [_path.object lastPathComponent];
  181. FIRStorageUploadTask *task =
  182. [[FIRStorageUploadTask alloc] initWithReference:self
  183. fetcherService:_storage.fetcherServiceForApp
  184. dispatchQueue:_storage.dispatchQueue
  185. file:fileURL
  186. metadata:metadata];
  187. if (completion) {
  188. dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
  189. if (!callbackQueue) {
  190. callbackQueue = dispatch_get_main_queue();
  191. }
  192. [task observeStatus:FIRStorageTaskStatusSuccess
  193. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  194. dispatch_async(callbackQueue, ^{
  195. completion(snapshot.metadata, nil);
  196. });
  197. }];
  198. [task observeStatus:FIRStorageTaskStatusFailure
  199. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  200. dispatch_async(callbackQueue, ^{
  201. completion(nil, snapshot.error);
  202. });
  203. }];
  204. }
  205. [task enqueue];
  206. return task;
  207. }
  208. #pragma mark - Downloads
  209. - (FIRStorageDownloadTask *)dataWithMaxSize:(int64_t)size
  210. completion:(FIRStorageVoidDataError)completion {
  211. FIRStorageDownloadTask *task =
  212. [[FIRStorageDownloadTask alloc] initWithReference:self
  213. fetcherService:_storage.fetcherServiceForApp
  214. dispatchQueue:_storage.dispatchQueue
  215. file:nil];
  216. dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
  217. if (!callbackQueue) {
  218. callbackQueue = dispatch_get_main_queue();
  219. }
  220. [task observeStatus:FIRStorageTaskStatusSuccess
  221. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  222. FIRStorageDownloadTask *task = snapshot.task;
  223. dispatch_async(callbackQueue, ^{
  224. completion(task.downloadData, nil);
  225. });
  226. }];
  227. [task observeStatus:FIRStorageTaskStatusFailure
  228. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  229. dispatch_async(callbackQueue, ^{
  230. completion(nil, snapshot.error);
  231. });
  232. }];
  233. [task
  234. observeStatus:FIRStorageTaskStatusProgress
  235. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  236. FIRStorageDownloadTask *task = snapshot.task;
  237. if (task.progress.totalUnitCount > size || task.progress.completedUnitCount > size) {
  238. NSDictionary *infoDictionary =
  239. @{@"totalSize" : @(task.progress.totalUnitCount),
  240. @"maxAllowedSize" : @(size)};
  241. NSError *error =
  242. [FIRStorageErrors errorWithCode:FIRStorageErrorCodeDownloadSizeExceeded
  243. infoDictionary:infoDictionary];
  244. [task cancelWithError:error];
  245. }
  246. }];
  247. [task enqueue];
  248. return task;
  249. }
  250. - (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL {
  251. return [self writeToFile:fileURL completion:nil];
  252. }
  253. - (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL
  254. completion:(FIRStorageVoidURLError)completion {
  255. FIRStorageDownloadTask *task =
  256. [[FIRStorageDownloadTask alloc] initWithReference:self
  257. fetcherService:_storage.fetcherServiceForApp
  258. dispatchQueue:_storage.dispatchQueue
  259. file:fileURL];
  260. if (completion) {
  261. dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue;
  262. if (!callbackQueue) {
  263. callbackQueue = dispatch_get_main_queue();
  264. }
  265. [task observeStatus:FIRStorageTaskStatusSuccess
  266. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  267. dispatch_async(callbackQueue, ^{
  268. completion(fileURL, nil);
  269. });
  270. }];
  271. [task observeStatus:FIRStorageTaskStatusFailure
  272. handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) {
  273. dispatch_async(callbackQueue, ^{
  274. completion(nil, snapshot.error);
  275. });
  276. }];
  277. }
  278. [task enqueue];
  279. return task;
  280. }
  281. - (void)downloadURLWithCompletion:(FIRStorageVoidURLError)completion {
  282. FIRStorageGetDownloadURLTask *task =
  283. [[FIRStorageGetDownloadURLTask alloc] initWithReference:self
  284. fetcherService:_storage.fetcherServiceForApp
  285. dispatchQueue:_storage.dispatchQueue
  286. completion:completion];
  287. [task enqueue];
  288. }
  289. #pragma mark - List
  290. - (void)listWithMaxResults:(int64_t)maxResults completion:(FIRStorageVoidListError)completion {
  291. if (maxResults <= 0 || maxResults > 1000) {
  292. completion(nil,
  293. [FIRStorageUtils storageErrorWithDescription:
  294. @"Argument 'maxResults' must be between 1 and 1000 inclusive."
  295. code:FIRStorageErrorCodeInvalidArgument]);
  296. } else {
  297. FIRStorageListTask *task =
  298. [[FIRStorageListTask alloc] initWithReference:self
  299. fetcherService:_storage.fetcherServiceForApp
  300. dispatchQueue:_storage.dispatchQueue
  301. pageSize:@(maxResults)
  302. previousPageToken:nil
  303. completion:completion];
  304. [task enqueue];
  305. }
  306. }
  307. - (void)listWithMaxResults:(int64_t)maxResults
  308. pageToken:(NSString *)pageToken
  309. completion:(FIRStorageVoidListError)completion {
  310. if (maxResults <= 0 || maxResults > 1000) {
  311. completion(nil,
  312. [FIRStorageUtils storageErrorWithDescription:
  313. @"Argument 'maxResults' must be between 1 and 1000 inclusive."
  314. code:FIRStorageErrorCodeInvalidArgument]);
  315. } else {
  316. FIRStorageListTask *task =
  317. [[FIRStorageListTask alloc] initWithReference:self
  318. fetcherService:_storage.fetcherServiceForApp
  319. dispatchQueue:_storage.dispatchQueue
  320. pageSize:@(maxResults)
  321. previousPageToken:pageToken
  322. completion:completion];
  323. [task enqueue];
  324. }
  325. }
  326. - (void)listAllWithCompletion:(FIRStorageVoidListError)completion {
  327. NSMutableArray *prefixes = [NSMutableArray new];
  328. NSMutableArray *items = [NSMutableArray new];
  329. __weak FIRStorageReference *weakSelf = self;
  330. __block FIRStorageVoidListError paginatedCompletion =
  331. ^(FIRStorageListResult *listResult, NSError *error) {
  332. if (error) {
  333. completion(nil, error);
  334. }
  335. FIRStorageReference *strongSelf = weakSelf;
  336. if (!strongSelf) {
  337. return;
  338. }
  339. [prefixes addObjectsFromArray:listResult.prefixes];
  340. [items addObjectsFromArray:listResult.items];
  341. if (listResult.pageToken) {
  342. FIRStorageListTask *nextPage = [[FIRStorageListTask alloc]
  343. initWithReference:self
  344. fetcherService:strongSelf->_storage.fetcherServiceForApp
  345. dispatchQueue:strongSelf->_storage.dispatchQueue
  346. pageSize:nil
  347. previousPageToken:listResult.pageToken
  348. completion:paginatedCompletion];
  349. [nextPage enqueue];
  350. } else {
  351. FIRStorageListResult *result = [[FIRStorageListResult alloc] initWithPrefixes:prefixes
  352. items:items
  353. pageToken:nil];
  354. // Break the retain cycle we set up indirectly by passing the callback to `nextPage`.
  355. paginatedCompletion = nil;
  356. completion(result, nil);
  357. }
  358. };
  359. FIRStorageListTask *task =
  360. [[FIRStorageListTask alloc] initWithReference:self
  361. fetcherService:_storage.fetcherServiceForApp
  362. dispatchQueue:_storage.dispatchQueue
  363. pageSize:nil
  364. previousPageToken:nil
  365. completion:paginatedCompletion];
  366. [task enqueue];
  367. }
  368. #pragma mark - Metadata Operations
  369. - (void)metadataWithCompletion:(FIRStorageVoidMetadataError)completion {
  370. FIRStorageGetMetadataTask *task =
  371. [[FIRStorageGetMetadataTask alloc] initWithReference:self
  372. fetcherService:_storage.fetcherServiceForApp
  373. dispatchQueue:_storage.dispatchQueue
  374. completion:completion];
  375. [task enqueue];
  376. }
  377. - (void)updateMetadata:(FIRStorageMetadata *)metadata
  378. completion:(nullable FIRStorageVoidMetadataError)completion {
  379. FIRStorageUpdateMetadataTask *task =
  380. [[FIRStorageUpdateMetadataTask alloc] initWithReference:self
  381. fetcherService:_storage.fetcherServiceForApp
  382. dispatchQueue:_storage.dispatchQueue
  383. metadata:metadata
  384. completion:completion];
  385. [task enqueue];
  386. }
  387. #pragma mark - Delete
  388. - (void)deleteWithCompletion:(nullable FIRStorageVoidError)completion {
  389. FIRStorageDeleteTask *task =
  390. [[FIRStorageDeleteTask alloc] initWithReference:self
  391. fetcherService:_storage.fetcherServiceForApp
  392. dispatchQueue:_storage.dispatchQueue
  393. completion:completion];
  394. [task enqueue];
  395. }
  396. @end