nasBackupsManager.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. //
  2. // nasBackupsManager.m
  3. // 双子星云手机
  4. //
  5. // Created by xd h on 2024/8/29.
  6. //
  7. #import "nasBackupsManager.h"
  8. @interface nasBackupsManager ()
  9. /**检测任务10s后 无反馈重新开始 */
  10. @property (nonatomic, assign) NSInteger taskRenewTime; //
  11. @property (nonatomic,strong)photosBackupsTaskModel *lastModel;//最后一次备份的数据
  12. @end
  13. @implementation nasBackupsManager
  14. + (instancetype)shareInstance {
  15. static nasBackupsManager *_instance;
  16. static dispatch_once_t onceToken;
  17. dispatch_once(&onceToken, ^{
  18. _instance = [[self alloc] init];
  19. });
  20. return _instance;
  21. }
  22. - (void)AutohandlePhotosBackupsFun
  23. {
  24. NSString *curSdnId = [connectDeviceManager shareInstance].DeviceThirdIdMod.data.sdnId;
  25. if(!_sdnId || ![curSdnId isEqualToString:_sdnId])
  26. {//没有备份过 或者更换设备了
  27. [self handlePhotosBackupsFun];
  28. }
  29. else{
  30. [self checkReBackupsFileFun];
  31. }
  32. }
  33. - (void)handlePhotosBackupsFun
  34. {
  35. BOOL haveOpenBackups = [HWDataManager getBoolWithKey:stringKeyAddSn(Const_photo_backups_state)];
  36. if(!haveOpenBackups){
  37. return;
  38. }
  39. if(ksharedAppDelegate.DisabledFileTransferType){
  40. return;
  41. }
  42. //相册权限
  43. if (![[TZImageManager manager] authorizationStatusAuthorized]){
  44. [HWDataManager setBoolWithKey:Const_photo_backups_state value:NO];
  45. return;
  46. }
  47. NSString *curSdnId = [connectDeviceManager shareInstance].DeviceThirdIdMod.data.sdnId;
  48. _sdnId = curSdnId;
  49. [photosBackupsTaskModel bg_findAsync:backups_photos_tableName limit:0 orderBy:nil desc:YES complete:^(NSArray * _Nullable array) {
  50. if(!array || array.count == 0){
  51. [self getAllAlbumsFun];
  52. return;
  53. }
  54. if(array.count >1){
  55. [self keepDatabaseOneDataFun];
  56. }
  57. self->_lastModel = array.firstObject;
  58. HLog(@"1 bg_id:%@",self->_lastModel.bg_id);
  59. if(self->_lastModel.isBackupsSuspendType == backupsSuspendByUser){
  60. return;
  61. }
  62. if(self->_lastModel.curBackupsState == backupsStateFail
  63. ||self->_lastModel.curBackupsState == backupsStateDone){//上次备份完成
  64. [self getAllAlbumsFun];
  65. }
  66. else{//继续上次的备份任务
  67. [self handelBackupsModelFun:self->_lastModel];
  68. }
  69. }];
  70. }
  71. - (void)keepDatabaseOneDataFun
  72. {
  73. [photosBackupsTaskModel bg_deleteFirstObject:backups_photos_tableName];
  74. }
  75. //备份开始查询相册
  76. - (void)getAllAlbumsFun
  77. {
  78. //
  79. KWeakSelf
  80. [[TZImageManager manager] getAllAlbums:YES allowPickingImage:YES needFetchAssets:NO completion:^(NSArray<TZAlbumModel *> *models) {
  81. if(models.count >= 1){
  82. TZAlbumModel *curAlbumModel= models.firstObject;
  83. photosBackupsTaskModel * taskModel = [photosBackupsTaskModel new];
  84. //taskModel.count = curAlbumModel.count;
  85. //taskModel.result = curAlbumModel.result;
  86. taskModel.failCount = 0;
  87. taskModel.didBackupsCount = 0;
  88. taskModel.bg_tableName = backups_photos_tableName;
  89. //备份路径
  90. NSString * backupsDefaultPath = [HWDataManager getStringWithKey:stringKeyAddSn(Const_photo_backups_default_path)];
  91. if(!backupsDefaultPath || backupsDefaultPath.length == 0){
  92. backupsDefaultPath = Const_default_backups_path;
  93. [HWDataManager setStringWithKey:stringKeyAddSn(Const_photo_backups_default_path) value:backupsDefaultPath];
  94. }
  95. NSString *lastStr= [backupsDefaultPath substringFromIndex:backupsDefaultPath.length-1];
  96. if(![lastStr isEqualToString:@"/"]){
  97. backupsDefaultPath = [[NSString alloc] initWithFormat:@"%@/",backupsDefaultPath];
  98. }
  99. taskModel.backupsPath = backupsDefaultPath;
  100. NSMutableString *allLocalIdentifier= [NSMutableString new];
  101. for (PHAsset *asset in curAlbumModel.result) {
  102. if (asset.localIdentifier) {
  103. if(allLocalIdentifier.length >0){
  104. [allLocalIdentifier appendString:@"&"];
  105. }
  106. [allLocalIdentifier appendString:asset.localIdentifier];
  107. }
  108. }
  109. taskModel.totalLocalIdentifier = allLocalIdentifier;
  110. if(self->_lastModel
  111. && self->_lastModel.totalLocalIdentifier
  112. && (self->_lastModel.backupsPath && [self->_lastModel.backupsPath isEqualToString:taskModel.backupsPath])){//相册备份排重
  113. taskModel.curTaskLocalIdentifier = [weakSelf AlbumBackupsHandleNew:taskModel];
  114. taskModel.PreDidBackupsCount = self->_lastModel.PreDidBackupsCount + self->_lastModel.didBackupsCount;
  115. }
  116. else{
  117. taskModel.curTaskLocalIdentifier = allLocalIdentifier;
  118. }
  119. taskModel.count = [taskModel.curTaskLocalIdentifier componentsSeparatedByString:@"&"].count;
  120. HLog(@"2 bg_id:%@",taskModel.bg_id);
  121. [taskModel bg_saveAsync:^(BOOL isSuccess) {
  122. if(!isSuccess){
  123. HLog(@"\n\nError!!!\n\n");
  124. }
  125. else{
  126. //[self handelBackupsModelFun:taskModel];
  127. [self handlePhotosBackupsFun];
  128. }
  129. }];
  130. }
  131. }];
  132. }
  133. - (NSString*)AlbumBackupsHandleNew:(photosBackupsTaskModel * )taskModel
  134. {
  135. NSArray* curLocalIdentifierArr = [taskModel.totalLocalIdentifier componentsSeparatedByString:@"&"];
  136. NSArray* preLocalIdentifierArr = [_lastModel.totalLocalIdentifier componentsSeparatedByString:@"&"];
  137. NSMutableArray *allArr = [NSMutableArray arrayWithArray:curLocalIdentifierArr];
  138. for (NSString*localIdentifier in preLocalIdentifierArr) {
  139. for (NSString* newlocalIdentifier in allArr) {
  140. if([localIdentifier isEqualToString:newlocalIdentifier]){
  141. [allArr removeObject:newlocalIdentifier];
  142. break;
  143. }
  144. }
  145. }
  146. NSMutableString *allLocalIdentifier= [NSMutableString new];
  147. for (NSString* newlocalIdentifier in allArr) {
  148. if(allLocalIdentifier.length >0){
  149. [allLocalIdentifier appendString:@"&"];
  150. }
  151. [allLocalIdentifier appendString:newlocalIdentifier];
  152. }
  153. return allLocalIdentifier;
  154. }
  155. - (void)handelBackupsModelFun:(photosBackupsTaskModel*)backupsTaskModel
  156. {
  157. _curPhotosBackupsTaskMod = backupsTaskModel;
  158. _curPhotosBackupsTaskMod.isBackupsSuspendType = backupsSuspendNone;
  159. _curPhotosBackupsTaskMod.curBackupsState = backupsStateUploading;
  160. _curPhotosBackupsTaskMod.LocalIdentifierArr = [backupsTaskModel.curTaskLocalIdentifier componentsSeparatedByString:@"&"];
  161. if(_curPhotosBackupsTaskMod.LocalIdentifierArr.count == 0){
  162. _curPhotosBackupsTaskMod.didBackupsCount = 0;
  163. _curPhotosBackupsTaskMod.curBackupsState = backupsStateDone;
  164. [self RefreshDatabaseFun];
  165. [self changeBackupsFileStateFun];
  166. return;
  167. }
  168. if(_curPhotosBackupsTaskMod.LocalIdentifierArr.count
  169. <= (_curPhotosBackupsTaskMod.didBackupsCount + _curPhotosBackupsTaskMod.failCount))
  170. {
  171. _curPhotosBackupsTaskMod.curBackupsState = backupsStateDone;
  172. [self RefreshDatabaseFun];
  173. [self changeBackupsFileStateFun];
  174. return;
  175. }
  176. [self beginBackupsFileFun];
  177. }
  178. - (void)beginBackupsFileFun
  179. {
  180. BOOL isCanUseCellular = [HWDataManager getBoolWithKey:stringKeyAddSn(Const_file_Transfe_canUse_Cellular_all)];
  181. if(!isCanUseCellular){//不允许流量上传
  182. //
  183. if([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN){
  184. return;
  185. }
  186. }
  187. self.taskRenewTime = [iTools getNowTimeStamp];
  188. NSInteger index = _curPhotosBackupsTaskMod.didBackupsCount + _curPhotosBackupsTaskMod.failCount;
  189. if(!_curPhotosBackupsTaskMod.LocalIdentifierArr){
  190. _curPhotosBackupsTaskMod.LocalIdentifierArr = [_curPhotosBackupsTaskMod.curTaskLocalIdentifier componentsSeparatedByString:@"&"];
  191. }
  192. if(index >= _curPhotosBackupsTaskMod.LocalIdentifierArr.count){
  193. _curPhotosBackupsTaskMod.curBackupsState = backupsStateDone;
  194. [self RefreshDatabaseFun];
  195. [self changeBackupsFileStateFun];
  196. _curPhotosBackupsTaskMod = nil;
  197. return;
  198. }
  199. NSString *curLocalIdentifier = _curPhotosBackupsTaskMod.LocalIdentifierArr[index];
  200. if(!curLocalIdentifier || curLocalIdentifier.length == 0)
  201. {
  202. [self getDataWrongToChangeFailFun];
  203. return;
  204. }
  205. _curPhotosBackupsTaskMod.didUploadBytes = 0;
  206. _curPhotosBackupsTaskMod.preDidUploadBytes = 0;
  207. _curPhotosBackupsTaskMod.totalBytes = 0;
  208. PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[curLocalIdentifier] options:nil];
  209. PHAsset *curAsset = fetchResult.firstObject;
  210. NSString *fileName = [curAsset valueForKey:@"filename"];;
  211. if(!fileName){
  212. [self getDataWrongToChangeFailFun];
  213. return;
  214. }
  215. _curPhotosBackupsTaskMod.filename = fileName;
  216. KWeakSelf
  217. if(curAsset.mediaType == PHAssetMediaTypeImage){
  218. _curPhotosBackupsTaskMod.curUploadFileType = uploadFileTypeImage;
  219. [[PHImageManager defaultManager] requestImageDataForAsset:curAsset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
  220. // 直接得到最终的 NSData 数据
  221. if (imageData) {
  222. [weakSelf afterGetImageDataFun:imageData];
  223. }
  224. else{
  225. [weakSelf getDataWrongToChangeFailFun];
  226. }
  227. }];
  228. }
  229. else{
  230. _curPhotosBackupsTaskMod.curUploadFileType = uploadFileTypeVideo;
  231. //判断文件是否在app内
  232. BOOL didSaveFile = [cachesFileManager checkFileIsSaveState:_curPhotosBackupsTaskMod.filename withType:uploadFileTypeVideo];
  233. if(didSaveFile){
  234. [self afterGetVideoDataFun];
  235. return;
  236. }
  237. //真正的视频数据
  238. PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
  239. options.version = PHVideoRequestOptionsVersionOriginal;
  240. [[PHImageManager defaultManager] requestAVAssetForVideo:curAsset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
  241. if ([asset isKindOfClass:[AVURLAsset class]]) {
  242. AVURLAsset* urlAsset = (AVURLAsset*)asset;
  243. BOOL isSuc = [cachesFileManager copyVideoItemAtPath:[urlAsset.URL path] fileName:self->_curPhotosBackupsTaskMod.filename error:nil];
  244. if (isSuc) {
  245. [weakSelf afterGetVideoDataFun];
  246. }
  247. else{
  248. [weakSelf getDataWrongToChangeFailFun];
  249. }
  250. }
  251. else{
  252. [weakSelf getDataWrongToChangeFailFun];
  253. }
  254. }];
  255. }
  256. }
  257. - (void)getDataWrongToChangeFailFun
  258. {
  259. [self deleteVideoFun];
  260. _curPhotosBackupsTaskMod.failCount += 1;
  261. [self RefreshDatabaseFun];
  262. if(_curPhotosBackupsTaskMod.curBackupsState == backupsStateSuspend){
  263. return;
  264. }
  265. [self beginBackupsFileFun];
  266. }
  267. - (void)changeBackupsFileStateToFailWith:(NSString*)errorStr
  268. {
  269. [self deleteVideoFun];
  270. _curPhotosBackupsTaskMod.curBackupsState = backupsStateFail;
  271. _curPhotosBackupsTaskMod.backupsTipMsg = errorStr;
  272. [self RefreshDatabaseFun];
  273. [self changeBackupsFileStateFun];
  274. }
  275. - (void)RefreshDatabaseFun
  276. {
  277. HLog(@"3 bg_id:%@",_curPhotosBackupsTaskMod.bg_id);
  278. [_curPhotosBackupsTaskMod bg_saveOrUpdateAsync:^(BOOL isSuccess) {
  279. if(isSuccess){
  280. }
  281. }];
  282. }
  283. - (void)afterGetImageDataFun:(NSData*)imageData
  284. {
  285. _curPhotosBackupsTaskMod.imageData = imageData;
  286. _curPhotosBackupsTaskMod.didUploadBytes = 0;
  287. _curPhotosBackupsTaskMod.totalBytes = [imageData length];
  288. [[webSocketManager shareInstance] beginGotoBackupsFileFunBy:_curPhotosBackupsTaskMod];
  289. [self RefreshDatabaseFun];
  290. [self changeBackupsFileStateFun];
  291. }
  292. - (void)deleteVideoFun
  293. {
  294. if(_curPhotosBackupsTaskMod.curUploadFileType == uploadFileTypeVideo){
  295. [cachesFileManager removeItemAtPath:_curPhotosBackupsTaskMod.filename type:uploadFileTypeVideo error:nil];
  296. }
  297. }
  298. - (void)afterGetVideoDataFun
  299. {
  300. NSString *filePath = [cachesFileManager getFilePathWithName:_curPhotosBackupsTaskMod.filename type:uploadFileTypeVideo]; // 文件路径
  301. NSFileManager *manager0 = [NSFileManager defaultManager];
  302. if([manager0 fileExistsAtPath:filePath]) {
  303. NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath]; // 创建文件句柄
  304. if (fileHandle) {
  305. long long endOfFile = [fileHandle seekToEndOfFile];
  306. _curPhotosBackupsTaskMod.didUploadBytes = 0;
  307. _curPhotosBackupsTaskMod.totalBytes = endOfFile;
  308. [fileHandle closeFile];
  309. }
  310. }
  311. [[webSocketManager shareInstance] beginGotoBackupsFileFunBy:_curPhotosBackupsTaskMod];
  312. [self RefreshDatabaseFun];
  313. [self changeBackupsFileStateFun];
  314. }
  315. - (void)backupsFileDoneFun
  316. {
  317. [self deleteVideoFun];
  318. _curPhotosBackupsTaskMod.didBackupsCount += 1;
  319. // if(!_curPhotosBackupsTaskMod.didBackupsOneFileType)
  320. // {
  321. // _curPhotosBackupsTaskMod.curTaskBackupsCount += 1;
  322. // }
  323. [self RefreshDatabaseFun];
  324. [self changeBackupsFileStateFun];
  325. if(_curPhotosBackupsTaskMod.curBackupsState == backupsStateSuspend){
  326. return;
  327. }
  328. //延时 进度条视觉效果
  329. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  330. [self beginBackupsFileFun];
  331. });
  332. }
  333. //修改文件上传的状态
  334. - (void)changeBackupsFileStateFun
  335. {
  336. self.taskRenewTime = [iTools getNowTimeStamp];
  337. [[NSNotificationCenter defaultCenter] postNotificationName:backupsFileRefreshNotification object:_curPhotosBackupsTaskMod];
  338. }
  339. - (void)suspendBackupsFileFun
  340. {
  341. if(!_curPhotosBackupsTaskMod){
  342. return;
  343. }
  344. _curPhotosBackupsTaskMod.curBackupsState = backupsStateSuspend;
  345. _curPhotosBackupsTaskMod.backupsTipMsg = NSLocalizedString(@"File_backups_Record_tip_Suspend",nil);
  346. [_curPhotosBackupsTaskMod bg_saveOrUpdateAsync:^(BOOL isSuccess) {
  347. if(isSuccess){
  348. [self changeBackupsFileStateFun];
  349. }
  350. }];
  351. }
  352. //文件重新备份
  353. - (void)reBackupsFileFunBy:(photosBackupsTaskModel*)model
  354. {
  355. model.isBackupsSuspendType = backupsSuspendNone;
  356. model.curBackupsState = backupsStateUploading;
  357. _curPhotosBackupsTaskMod = model;
  358. [self RefreshDatabaseFun];
  359. [self changeBackupsFileStateFun];
  360. [self beginBackupsFileFun];
  361. // [_curPhotosBackupsTaskMod bg_saveOrUpdateAsync:^(BOOL isSuccess) {
  362. // if(isSuccess){
  363. // [self beginBackupsFileFun];
  364. // }
  365. // }];
  366. }
  367. //文件重新备份
  368. - (void)reBackupsFileFun
  369. {
  370. [self handlePhotosBackupsFun];
  371. //if(_curPhotosBackupsTaskMod.curBackupsState != backupsStateUploading)
  372. if(self->_lastModel.curBackupsState != backupsStateUploading){
  373. if(self->_lastModel.curBackupsState == backupsStateFail
  374. ||self->_lastModel.curBackupsState == backupsStateDone){//上次备份完成
  375. [self getAllAlbumsFun];
  376. }
  377. else{//继续上次的备份任务
  378. [self handelBackupsModelFun:self->_lastModel];
  379. }
  380. }
  381. }
  382. //检查是否需要重新备份
  383. - (void)checkReBackupsFileFun
  384. {
  385. if(!_curPhotosBackupsTaskMod){
  386. return;
  387. }
  388. if(_curPhotosBackupsTaskMod.curBackupsState != backupsStateUploading){
  389. return;
  390. }
  391. NSInteger curTime = [iTools getNowTimeStamp];
  392. if(self.taskRenewTime == 0){
  393. return;
  394. }
  395. if(curTime - self.taskRenewTime < 10){
  396. return;
  397. }
  398. [self beginBackupsFileFun];
  399. }
  400. //检查是否在备份中
  401. - (BOOL)checkBackupsingFun{
  402. if(!_curPhotosBackupsTaskMod){
  403. return NO;
  404. }
  405. if(_curPhotosBackupsTaskMod.curBackupsState == backupsStateSuspend){
  406. return NO;
  407. }
  408. return YES;
  409. }
  410. @end