FIRStorageDownloadTask.m 6.5 KB

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