// // QNPartsUploadPerformer.m // QiniuSDK // // Created by yangsen on 2020/12/1. // Copyright © 2020 Qiniu. All rights reserved. // #import "QNLogUtil.h" #import "QNAsyncRun.h" #import "QNUpToken.h" #import "QNZoneInfo.h" #import "QNUploadOption.h" #import "QNConfiguration.h" #import "QNFileDelegate.h" #import "QNUploadRegionInfo.h" #import "QNRecorderDelegate.h" #import "QNUploadDomainRegion.h" #import "QNPartsUploadPerformer.h" #import "QNRequestTransaction.h" #define kQNRecordFileInfoKey @"recordFileInfo" #define kQNRecordZoneInfoKey @"recordZoneInfo" @interface QNPartsUploadPerformer() @property (nonatomic, copy) NSString *key; @property (nonatomic, copy) NSString *fileName; @property (nonatomic, strong) id file; @property (nonatomic, strong) QNUpToken *token; @property (nonatomic, strong) QNUploadOption *option; @property (nonatomic, strong) QNConfiguration *config; @property (nonatomic, strong) id recorder; @property (nonatomic, copy) NSString *recorderKey; @property (nonatomic, strong) NSNumber *recoveredFrom; @property (nonatomic, strong) id targetRegion; @property (nonatomic, strong) id currentRegion; @property (nonatomic, strong) QNUploadFileInfo *fileInfo; @property(nonatomic, assign) double previousPercent; @property(nonatomic, strong)NSMutableArray *uploadTransactions; @end @implementation QNPartsUploadPerformer - (instancetype)initWithFile:(id)file fileName:(NSString *)fileName key:(NSString *)key token:(QNUpToken *)token option:(QNUploadOption *)option configuration:(QNConfiguration *)config recorderKey:(NSString *)recorderKey { if (self = [super init]) { _file = file; _fileName = fileName; _key = key; _token = token; _option = option; _config = config; _recorder = config.recorder; _recorderKey = recorderKey; [self initData]; } return self; } - (void)initData { self.uploadTransactions = [NSMutableArray array]; [self recoverUploadInfoFromRecord]; if (!self.fileInfo) { self.fileInfo = [self getDefaultUploadFileInfo]; } } - (void)switchRegion:(id )region { [self.fileInfo clearUploadState]; self.currentRegion = region; self.recoveredFrom = nil; if (!self.targetRegion) { self.targetRegion = region; } } - (void)notifyProgress { float percent = self.fileInfo.progress; if (percent > 0.95) { percent = 0.95; } if (percent > self.previousPercent) { self.previousPercent = percent; } else { percent = self.previousPercent; } QNAsyncRunInMain(^{ self.option.progressHandler(self.key, percent); }); } - (void)recordUploadInfo { NSString *key = self.recorderKey; if (self.recorder == nil || key == nil || key.length == 0) { return; } NSDictionary *zoneInfo = [self.currentRegion zoneInfo].detailInfo; NSDictionary *fileInfo = [self.fileInfo toDictionary]; if (zoneInfo && fileInfo) { NSDictionary *info = @{kQNRecordZoneInfoKey : zoneInfo, kQNRecordFileInfoKey : fileInfo}; NSData *data = [NSJSONSerialization dataWithJSONObject:info options:NSJSONWritingPrettyPrinted error:nil]; if (data) { [self.recorder set:key data:data]; } } QNLogInfo(@"key:%@ recorderKey:%@ recordUploadInfo", self.key, self.recorderKey); } - (void)removeUploadInfoRecord { self.recoveredFrom = nil; [self.fileInfo clearUploadState]; [self.recorder del:self.recorderKey]; QNLogInfo(@"key:%@ recorderKey:%@ removeUploadInfoRecord", self.key, self.recorderKey); } - (void)recoverUploadInfoFromRecord { QNLogInfo(@"key:%@ recorderKey:%@ recorder:%@ recoverUploadInfoFromRecord", self.key, self.recorderKey, self.recorder); NSString *key = self.recorderKey; if (self.recorder == nil || key == nil || [key isEqualToString:@""]) { return; } NSData *data = [self.recorder get:key]; if (data == nil) { QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord data:nil", self.key, self.recorderKey); return; } NSError *error = nil; NSDictionary *info = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; if (error != nil || ![info isKindOfClass:[NSDictionary class]]) { QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord json error", self.key, self.recorderKey); [self.recorder del:self.key]; return; } QNZoneInfo *zoneInfo = [QNZoneInfo zoneInfoFromDictionary:info[kQNRecordZoneInfoKey]]; QNUploadFileInfo *fileInfo = [self getFileInfoWithDictionary:info[kQNRecordFileInfoKey]]; if (zoneInfo && fileInfo && ![fileInfo isEmpty] && fileInfo.size == self.file.size && fileInfo.modifyTime == self.file.modifyTime) { QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord valid", self.key, self.recorderKey); self.fileInfo = fileInfo; QNUploadDomainRegion *region = [[QNUploadDomainRegion alloc] init]; [region setupRegionData:zoneInfo]; self.currentRegion = region; self.targetRegion = region; self.recoveredFrom = @(fileInfo.progress * fileInfo.size); } else { QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord invalid", self.key, self.recorderKey); [self.recorder del:self.key]; self.currentRegion = nil; self.targetRegion = nil; self.recoveredFrom = nil; } } - (QNRequestTransaction *)createUploadRequestTransaction { QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithConfig:self.config uploadOption:self.option targetRegion:self.targetRegion currentRegion:self.currentRegion key:self.key token:self.token]; @synchronized (self) { [self.uploadTransactions addObject:transaction]; } return transaction; } - (void)destroyUploadRequestTransaction:(QNRequestTransaction *)transaction { if (transaction) { @synchronized (self) { [self.uploadTransactions removeObject:transaction]; } } } - (QNUploadFileInfo *)getFileInfoWithDictionary:(NSDictionary *)fileInfoDictionary { return nil; } - (QNUploadFileInfo *)getDefaultUploadFileInfo { return nil; } - (void)serverInit:(void (^)(QNResponseInfo * _Nullable, QNUploadRegionRequestMetrics * _Nullable, NSDictionary * _Nullable))completeHandler {} - (void)uploadNextData:(void (^)(BOOL stop, QNResponseInfo * _Nullable, QNUploadRegionRequestMetrics * _Nullable, NSDictionary * _Nullable))completeHandler {} - (void)completeUpload:(void (^)(QNResponseInfo * _Nullable, QNUploadRegionRequestMetrics * _Nullable, NSDictionary * _Nullable))completeHandler {} @end