WFCUMediaMessageDownloader.m 13 KB

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