FIRStorageDownloadTask.m 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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/FIRStorageDownloadTask.h"
  15. #import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
  16. #import "FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h"
  17. #import "FirebaseStorage/Sources/FIRStorageObservableTask_Private.h"
  18. #import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
  19. @implementation FIRStorageDownloadTask
  20. @synthesize progress = _progress;
  21. @synthesize fetcher = _fetcher;
  22. @synthesize fetcherCompletion = _fetcherCompletion;
  23. - (instancetype)initWithReference:(FIRStorageReference *)reference
  24. fetcherService:(GTMSessionFetcherService *)service
  25. dispatchQueue:(dispatch_queue_t)queue
  26. file:(nullable NSURL *)fileURL {
  27. self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
  28. if (self) {
  29. _fileURL = [fileURL copy];
  30. _progress = [NSProgress progressWithTotalUnitCount:0];
  31. }
  32. return self;
  33. }
  34. - (void)dealloc {
  35. [_fetcher stopFetching];
  36. }
  37. - (void)enqueue {
  38. [self enqueueWithData:nil];
  39. }
  40. - (void)enqueueWithData:(nullable NSData *)resumeData {
  41. __weak FIRStorageDownloadTask *weakSelf = self;
  42. [self dispatchAsync:^() {
  43. FIRStorageDownloadTask *strongSelf = weakSelf;
  44. if (!strongSelf) {
  45. return;
  46. }
  47. strongSelf.state = FIRStorageTaskStateQueueing;
  48. NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy];
  49. request.HTTPMethod = @"GET";
  50. request.timeoutInterval = strongSelf.reference.storage.maxDownloadRetryTime;
  51. NSURLComponents *components = [NSURLComponents componentsWithURL:request.URL
  52. resolvingAgainstBaseURL:NO];
  53. [components setQuery:@"alt=media"];
  54. request.URL = components.URL;
  55. GTMSessionFetcher *fetcher;
  56. if (resumeData) {
  57. fetcher = [GTMSessionFetcher fetcherWithDownloadResumeData:resumeData];
  58. fetcher.comment = @"Resuming DownloadTask";
  59. } else {
  60. fetcher = [strongSelf.fetcherService fetcherWithRequest:request];
  61. fetcher.comment = @"Starting DownloadTask";
  62. }
  63. [fetcher setResumeDataBlock:^(NSData *data) {
  64. FIRStorageDownloadTask *strong = weakSelf;
  65. if (strong && data) {
  66. strong->_downloadData = data;
  67. }
  68. }];
  69. fetcher.maxRetryInterval = strongSelf.reference.storage.maxDownloadRetryTime;
  70. if (strongSelf->_fileURL) {
  71. // Handle file downloads
  72. [fetcher setDestinationFileURL:strongSelf->_fileURL];
  73. [fetcher setDownloadProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten,
  74. int64_t totalBytesExpectedToWrite) {
  75. weakSelf.state = FIRStorageTaskStateProgress;
  76. weakSelf.progress.completedUnitCount = totalBytesWritten;
  77. weakSelf.progress.totalUnitCount = totalBytesExpectedToWrite;
  78. FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
  79. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot];
  80. weakSelf.state = FIRStorageTaskStateRunning;
  81. }];
  82. } else {
  83. // Handle data downloads
  84. [fetcher setReceivedProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten) {
  85. weakSelf.state = FIRStorageTaskStateProgress;
  86. weakSelf.progress.completedUnitCount = totalBytesWritten;
  87. int64_t totalLength = [[weakSelf.fetcher response] expectedContentLength];
  88. weakSelf.progress.totalUnitCount = totalLength;
  89. FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
  90. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot];
  91. weakSelf.state = FIRStorageTaskStateRunning;
  92. }];
  93. }
  94. strongSelf->_fetcher = fetcher;
  95. #pragma clang diagnostic push
  96. #pragma clang diagnostic ignored "-Warc-retain-cycles"
  97. strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) {
  98. // Fire last progress updates
  99. [self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot];
  100. // Handle potential issues with download
  101. if (error) {
  102. self.state = FIRStorageTaskStateFailed;
  103. self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
  104. [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot];
  105. [self removeAllObservers];
  106. self->_fetcherCompletion = nil;
  107. return;
  108. }
  109. // Download completed successfully, fire completion callbacks
  110. self.state = FIRStorageTaskStateSuccess;
  111. if (data) {
  112. self->_downloadData = data;
  113. }
  114. [self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot];
  115. [self removeAllObservers];
  116. self->_fetcherCompletion = nil;
  117. };
  118. #pragma clang diagnostic pop
  119. strongSelf.state = FIRStorageTaskStateRunning;
  120. [strongSelf.fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
  121. weakSelf.fetcherCompletion(data, error);
  122. }];
  123. }];
  124. }
  125. #pragma mark - Download Management
  126. - (void)cancel {
  127. NSError *error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeCancelled];
  128. [self cancelWithError:error];
  129. }
  130. - (void)cancelWithError:(NSError *)error {
  131. __weak FIRStorageDownloadTask *weakSelf = self;
  132. [self dispatchAsync:^() {
  133. weakSelf.state = FIRStorageTaskStateCancelled;
  134. [weakSelf.fetcher stopFetching];
  135. weakSelf.error = error;
  136. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:weakSelf.snapshot];
  137. }];
  138. }
  139. - (void)pause {
  140. __weak FIRStorageDownloadTask *weakSelf = self;
  141. [self dispatchAsync:^() {
  142. weakSelf.state = FIRStorageTaskStatePausing;
  143. [weakSelf.fetcher stopFetching];
  144. // Give the resume callback a chance to run (if scheduled)
  145. [weakSelf.fetcher waitForCompletionWithTimeout:0.001];
  146. weakSelf.state = FIRStorageTaskStatePaused;
  147. FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
  148. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:snapshot];
  149. }];
  150. }
  151. - (void)resume {
  152. __weak FIRStorageDownloadTask *weakSelf = self;
  153. [self dispatchAsync:^() {
  154. weakSelf.state = FIRStorageTaskStateResuming;
  155. FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
  156. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:snapshot];
  157. weakSelf.state = FIRStorageTaskStateRunning;
  158. [weakSelf enqueueWithData:weakSelf.downloadData];
  159. }];
  160. }
  161. @end