WFCUMediaMessageDownloader.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. //
  2. // MediaMessageDownloader.m
  3. // WildFireChat
  4. //
  5. // Created by heavyrain lee on 2018/8/29.
  6. // Copyright © 2018 WildFireChat. All rights reserved.
  7. //
  8. #import "WFCUMediaMessageDownloader.h"
  9. #import "AFNetworking.h"
  10. #import <WFChatClient/WFCChatClient.h>
  11. static WFCUMediaMessageDownloader *sharedSingleton = nil;
  12. @interface WFCUMediaMessageDownloader()
  13. @property(nonatomic, strong)NSMutableDictionary<NSString*, NSNumber*> *downloadingMessages;
  14. @end
  15. @implementation WFCUMediaMessageDownloader
  16. + (instancetype)sharedDownloader {
  17. if (sharedSingleton == nil) {
  18. @synchronized (self) {
  19. if (sharedSingleton == nil) {
  20. sharedSingleton = [[WFCUMediaMessageDownloader alloc] init];
  21. sharedSingleton.downloadingMessages = [[NSMutableDictionary alloc] init];
  22. }
  23. }
  24. }
  25. return sharedSingleton;
  26. }
  27. - (void)downloadFileWithURL:(NSString*)requestURLString
  28. parameters:(NSDictionary *)parameters
  29. savedPath:(NSString*)savedPath
  30. downloadSuccess:(void (^)(NSURLResponse *response, NSURL *filePath))success
  31. downloadFailure:(void (^)(NSError *error))failure
  32. downloadProgress:(void (^)(NSProgress *downloadProgress))progress
  33. {
  34. AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
  35. NSMutableURLRequest *request =[serializer requestWithMethod:@"GET" URLString:requestURLString parameters:parameters error:nil];
  36. NSURLSessionDownloadTask *task = [[AFHTTPSessionManager manager] downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
  37. progress(downloadProgress);
  38. } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
  39. return [NSURL fileURLWithPath:[savedPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
  40. } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
  41. if(error){
  42. failure(error);
  43. }else{
  44. success(response,filePath);
  45. }
  46. }];
  47. [task resume];
  48. }
  49. - (BOOL)tryDownload:(WFCCMessage *)msg
  50. success:(void(^)(long long messageUid, NSString *localPath))successBlock
  51. error:(void(^)(long long messageUid, int error_code))errorBlock {
  52. long long messageUid = msg.messageUid;
  53. if (!messageUid) {
  54. NSLog(@"Error, try download message have invalid uid");
  55. errorBlock(0, -2);
  56. return TRUE;
  57. }
  58. if (![msg.content isKindOfClass:[WFCCMediaMessageContent class]]) {
  59. NSLog(@"Error, try download message with id %lld, but it's not media message", messageUid);
  60. errorBlock(msg.messageUid, -1);
  61. return TRUE;
  62. }
  63. WFCCMediaMessageContent *mediaContent = (WFCCMediaMessageContent *)msg.content;
  64. if (mediaContent.localPath.length) {
  65. successBlock(msg.messageUid, mediaContent.localPath);
  66. return TRUE;
  67. }
  68. NSFileManager *fileManager = [NSFileManager defaultManager];
  69. BOOL isDir;
  70. NSError *error = nil;
  71. NSString *downloadDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingString:@"/download"];
  72. if (![fileManager fileExistsAtPath:downloadDir isDirectory:&isDir]) {
  73. if(![fileManager createDirectoryAtPath:downloadDir withIntermediateDirectories:YES attributes:nil error:&error]) {
  74. errorBlock(msg.messageUid, -1);
  75. NSLog(@"Error, create download folder error");
  76. return YES;
  77. }
  78. if (error) {
  79. errorBlock(msg.messageUid, -1);
  80. NSLog(@"Error, create download folder error:%@", error);
  81. return YES;
  82. }
  83. }
  84. if (!isDir) {
  85. errorBlock(msg.messageUid, -1);
  86. NSLog(@"Error, create download folder error");
  87. return YES;
  88. }
  89. //通知UI开始显示下载动画
  90. [[NSNotificationCenter defaultCenter] postNotificationName:kMediaMessageStartDownloading object:@(messageUid)];
  91. if (self.downloadingMessages[mediaContent.remoteUrl] != nil) {
  92. return NO;
  93. }
  94. NSString *savedPath = [downloadDir stringByAppendingPathComponent:[NSString stringWithFormat:@"media_%ld", mediaContent.remoteUrl.hash]];
  95. if ([mediaContent isKindOfClass:[WFCCSoundMessageContent class]]) {
  96. savedPath = [NSString stringWithFormat:@"%@.wav", savedPath];
  97. } else if([mediaContent isKindOfClass:[WFCCVideoMessageContent class]]) {
  98. savedPath = [NSString stringWithFormat:@"%@.mp4", savedPath];
  99. } else if([mediaContent isKindOfClass:[WFCCImageMessageContent class]]) {
  100. savedPath = [NSString stringWithFormat:@"%@.jpg", savedPath];
  101. } else if([mediaContent isKindOfClass:[WFCCFileMessageContent class]]) {
  102. WFCCFileMessageContent *content = (WFCCFileMessageContent *)mediaContent;
  103. savedPath = [downloadDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%ld-%@", mediaContent.remoteUrl.hash, content.name]];
  104. }
  105. if ([fileManager fileExistsAtPath:savedPath]) {
  106. mediaContent.localPath = savedPath;
  107. [[WFCCIMService sharedWFCIMService] updateMessage:messageUid content:mediaContent];
  108. successBlock(msg.messageUid, savedPath);
  109. [[NSNotificationCenter defaultCenter] postNotificationName:kMediaMessageDownloadFinished object:@(messageUid) userInfo:@{@"result":@(YES), @"localPath":savedPath}];
  110. return YES;
  111. }
  112. [self.downloadingMessages setObject:@(messageUid) forKey:mediaContent.remoteUrl];
  113. [self downloadFileWithURL:mediaContent.remoteUrl parameters:nil savedPath:savedPath downloadSuccess:^(NSURLResponse *response, NSURL *filePath) {
  114. NSLog(@"download message content of %lld success", messageUid);
  115. dispatch_async(dispatch_get_main_queue(), ^{
  116. [[WFCUMediaMessageDownloader sharedDownloader].downloadingMessages removeObjectForKey:mediaContent.remoteUrl];
  117. WFCCMessage *newMsg = msg;
  118. if (msg.conversation.type != Chatroom_Type) {
  119. newMsg = [[WFCCIMService sharedWFCIMService] getMessageByUid:messageUid];
  120. }
  121. if (!newMsg) {
  122. NSLog(@"Error, message %lld not exist", messageUid);
  123. errorBlock(msg.messageUid, -1);
  124. return;
  125. }
  126. if (![newMsg.content isKindOfClass:[WFCCMediaMessageContent class]]) {
  127. NSLog(@"Error, message %lld not media message", messageUid);
  128. errorBlock(msg.messageUid, -1);
  129. return;
  130. }
  131. WFCCMediaMessageContent *newContent = (WFCCMediaMessageContent *)newMsg.content;
  132. newContent.localPath = filePath.absoluteString;
  133. [[WFCCIMService sharedWFCIMService] updateMessage:newMsg.messageId content:newContent];
  134. mediaContent.localPath = filePath.absoluteString;
  135. successBlock(newMsg.messageUid, filePath.absoluteString);
  136. [[NSNotificationCenter defaultCenter] postNotificationName:kMediaMessageDownloadFinished object:@(messageUid) userInfo:@{@"result":@(YES), @"localPath":filePath.absoluteString}];
  137. });
  138. } downloadFailure:^(NSError *error) {
  139. dispatch_async(dispatch_get_main_queue(), ^{
  140. [[WFCUMediaMessageDownloader sharedDownloader].downloadingMessages removeObjectForKey:mediaContent.remoteUrl];
  141. errorBlock(msg.messageUid, -1);
  142. [[NSNotificationCenter defaultCenter] postNotificationName:kMediaMessageDownloadFinished object:@(messageUid) userInfo:@{@"result":@(NO)}];
  143. });
  144. NSLog(@"download message content of %lld failure with error %@", messageUid, error);
  145. } downloadProgress:^(NSProgress *downloadProgress) {
  146. NSLog(@"总大小:%lld,当前大小:%lld",downloadProgress.totalUnitCount,downloadProgress.completedUnitCount);
  147. }];
  148. return YES;
  149. }
  150. - (BOOL)tryDownload:(NSString *)mediaPath
  151. uid:(long long)uid
  152. mediaType:(DownloadMediaType)mediaType
  153. success:(void(^)(long long uid, NSString *localPath))successBlock
  154. error:(void(^)(long long uid, int error_code))errorBlock {
  155. if (!uid) {
  156. NSLog(@"Error, try download message have invalid uid");
  157. errorBlock(0, -2);
  158. return TRUE;
  159. }
  160. if (!mediaPath.length) {
  161. NSLog(@"Error, try download message with id %lld, but it's not media message", uid);
  162. errorBlock(uid, -1);
  163. return TRUE;
  164. }
  165. NSFileManager *fileManager = [NSFileManager defaultManager];
  166. BOOL isDir;
  167. NSError *error = nil;
  168. NSString *downloadDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingString:@"/download"];
  169. if (![fileManager fileExistsAtPath:downloadDir isDirectory:&isDir]) {
  170. if(![fileManager createDirectoryAtPath:downloadDir withIntermediateDirectories:YES attributes:nil error:&error]) {
  171. errorBlock(uid, -1);
  172. NSLog(@"Error, create download folder error");
  173. return YES;
  174. }
  175. if (error) {
  176. errorBlock(uid, -1);
  177. NSLog(@"Error, create download folder error:%@", error);
  178. return YES;
  179. }
  180. }
  181. if (!isDir) {
  182. errorBlock(uid, -1);
  183. NSLog(@"Error, create download folder error");
  184. return YES;
  185. }
  186. //通知UI开始显示下载动画
  187. [[NSNotificationCenter defaultCenter] postNotificationName:kMediaMessageStartDownloading object:@(uid)];
  188. if (self.downloadingMessages[mediaPath] != nil) {
  189. return NO;
  190. }
  191. NSString *savedPath = [downloadDir stringByAppendingPathComponent:[NSString stringWithFormat:@"media_%lld", mediaPath.hash]];
  192. switch (mediaType) {
  193. case DownloadMediaType_Image:
  194. savedPath = [NSString stringWithFormat:@"%@.jpg", savedPath];
  195. break;
  196. case DownloadMediaType_Voice:
  197. savedPath = [NSString stringWithFormat:@"%@.wav", savedPath];
  198. break;
  199. case DownloadMediaType_Video:
  200. savedPath = [NSString stringWithFormat:@"%@.mp4", savedPath];
  201. break;
  202. case DownloadMediaType_File:
  203. break;
  204. default:
  205. break;
  206. }
  207. if ([fileManager fileExistsAtPath:savedPath]) {
  208. dispatch_async(dispatch_get_main_queue(), ^{
  209. successBlock(uid, savedPath);
  210. [[NSNotificationCenter defaultCenter] postNotificationName:kMediaMessageDownloadFinished object:@(uid) userInfo:@{@"result":@(YES), @"localPath":savedPath}];
  211. });
  212. return YES;
  213. }
  214. [self.downloadingMessages setObject:@(uid) forKey:mediaPath];
  215. [self downloadFileWithURL:mediaPath parameters:nil savedPath:savedPath downloadSuccess:^(NSURLResponse *response, NSURL *filePath) {
  216. NSLog(@"download message content of %lld success", uid);
  217. dispatch_async(dispatch_get_main_queue(), ^{
  218. [[WFCUMediaMessageDownloader sharedDownloader].downloadingMessages removeObjectForKey:mediaPath];
  219. successBlock(uid, filePath.absoluteString);
  220. [[NSNotificationCenter defaultCenter] postNotificationName:kMediaMessageDownloadFinished object:@(uid) userInfo:@{@"result":@(YES), @"localPath":filePath.absoluteString}];
  221. });
  222. } downloadFailure:^(NSError *error) {
  223. dispatch_async(dispatch_get_main_queue(), ^{
  224. [[WFCUMediaMessageDownloader sharedDownloader].downloadingMessages removeObjectForKey:mediaPath];
  225. errorBlock(uid, -1);
  226. [[NSNotificationCenter defaultCenter] postNotificationName:kMediaMessageDownloadFinished object:@(uid) userInfo:@{@"result":@(NO)}];
  227. });
  228. NSLog(@"download message content of %lld failure with error %@", uid, error);
  229. } downloadProgress:^(NSProgress *downloadProgress) {
  230. NSLog(@"总大小:%lld,当前大小:%lld",downloadProgress.totalUnitCount,downloadProgress.completedUnitCount);
  231. }];
  232. return YES;
  233. }
  234. - (void)dealloc {
  235. [[NSNotificationCenter defaultCenter] removeObserver:self];
  236. }
  237. @end