123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- //
- // QNUploadInfoV1.m
- // QiniuSDK
- //
- // Created by yangsen on 2021/5/10.
- // Copyright © 2021 Qiniu. All rights reserved.
- //
- #import "NSData+QNMD5.h"
- #import "QNMutableArray.h"
- #import "QNUploadInfoV1.h"
- #define kTypeValue @"UploadInfoV1"
- #define kBlockSize (4 * 1024 * 1024)
- @interface QNUploadInfoV1()
- @property(nonatomic, assign)int dataSize;
- @property(nonatomic, strong)QNMutableArray *blockList;
- @property(nonatomic, assign)BOOL isEOF;
- @property(nonatomic, strong, nullable)NSError *readError;
- @end
- @implementation QNUploadInfoV1
- + (instancetype)info:(id<QNUploadSource>)source
- configuration:(nonnull QNConfiguration *)configuration {
-
- QNUploadInfoV1 *info = [QNUploadInfoV1 info:source];
- if (configuration.useConcurrentResumeUpload || configuration.chunkSize > kBlockSize) {
- info.dataSize = kBlockSize;
- } else {
- info.dataSize = configuration.chunkSize;
- }
- info.blockList = [QNMutableArray array];
- return info;
- }
- + (instancetype)info:(id <QNUploadSource>)source
- dictionary:(NSDictionary *)dictionary {
- if (dictionary == nil) {
- return nil;
- }
-
- int dataSize = [dictionary[@"dataSize"] intValue];
- NSString *type = dictionary[kQNUploadInfoTypeKey];
- NSArray *blockInfoList = dictionary[@"blockList"];
-
- QNMutableArray *blockList = [QNMutableArray array];
- if ([blockInfoList isKindOfClass:[NSArray class]]) {
- for (int i = 0; i < blockInfoList.count; i++) {
- NSDictionary *blockInfo = blockInfoList[i];
- if ([blockInfo isKindOfClass:[NSDictionary class]]) {
- QNUploadBlock *block = [QNUploadBlock blockFromDictionary:blockInfo];
- if (block == nil) {
- return nil;
- }
- [blockList addObject:block];
- }
- }
- }
-
- QNUploadInfoV1 *info = [QNUploadInfoV1 info:source];
- [info setInfoFromDictionary:dictionary];
- info.dataSize = dataSize;
- info.blockList = blockList;
-
- if (![type isEqualToString:kTypeValue] || ![[source getId] isEqualToString:[info getSourceId]]) {
- return nil;
- } else {
- return info;
- }
- }
- - (BOOL)isFirstData:(QNUploadData *)data {
- return data.index == 0;
- }
- - (BOOL)isValid {
- if (![super isValid]) {
- return false;
- }
-
- __block BOOL valid = true;
- [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
- valid = [block isValid];
- if (!valid) {
- *stop = true;
- }
- }];
- return valid;
- }
- - (BOOL)reloadSource {
- self.isEOF = false;
- self.readError = nil;
- return [super reloadSource];
- }
- - (BOOL)isSameUploadInfo:(QNUploadInfo *)info {
- if (![super isSameUploadInfo:info]) {
- return false;
- }
-
- if (![info isKindOfClass:[QNUploadInfoV1 class]]) {
- return false;
- }
-
- return self.dataSize == [(QNUploadInfoV1 *)info dataSize];
- }
- - (void)clearUploadState {
- if (self.blockList == nil || self.blockList.count == 0) {
- return;
- }
-
- [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
- [block clearUploadState];
- }];
- }
- - (void)checkInfoStateAndUpdate {
- [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
- [block checkInfoStateAndUpdate];
- }];
- }
- - (long long)uploadSize {
- if (self.blockList == nil || self.blockList.count == 0) {
- return 0;
- }
-
- __block long long uploadSize = 0;
- [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
- uploadSize += [block uploadSize];
- }];
- return uploadSize;
- }
- - (BOOL)isAllUploaded {
- if (!_isEOF) {
- return false;
- }
-
- if (self.blockList == nil || self.blockList.count == 0) {
- return true;
- }
-
- __block BOOL isAllUploaded = true;
- [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
- if (!block.isCompleted) {
- isAllUploaded = false;
- *stop = true;
- }
- }];
- return isAllUploaded;
- }
- - (NSDictionary *)toDictionary {
- NSMutableDictionary *dictionary = [[super toDictionary] mutableCopy];
- if (dictionary == nil) {
- dictionary = [NSMutableDictionary dictionary];
- }
- [dictionary setObject:kTypeValue forKey:kQNUploadInfoTypeKey];
- [dictionary setObject:@(self.dataSize) forKey:@"dataSize"];
-
- if (self.blockList != nil && self.blockList.count != 0) {
- NSMutableArray *blockInfoList = [NSMutableArray array];
- [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
- [blockInfoList addObject:[block toDictionary]];
- }];
- [dictionary setObject:[blockInfoList copy] forKey:@"blockList"];
- }
-
- return [dictionary copy];
- }
- - (QNUploadBlock *)nextUploadBlock:(NSError **)error {
- // 从 blockList 中读取需要上传的 block
- QNUploadBlock *block = [self nextUploadBlockFormBlockList];
-
- // 内存的 blockList 中没有可上传的数据,则从资源中读并创建 block
- if (block == nil) {
- if (self.isEOF) {
- return nil;
- } else if (self.readError) {
- *error = self.readError;
- return nil;
- }
-
- // 从资源中读取新的 block 进行上传
- long long blockOffset = 0;
- if (self.blockList.count > 0) {
- QNUploadBlock *lastBlock = self.blockList[self.blockList.count - 1];
- blockOffset = lastBlock.offset + (long long)(lastBlock.size);
- }
- block = [[QNUploadBlock alloc] initWithOffset:blockOffset blockSize:kBlockSize dataSize:self.dataSize index:self.blockList.count];
- }
-
- QNUploadBlock *loadBlock = [self loadBlockData:block error:error];
- if (*error != nil) {
- self.readError = *error;
- return nil;
- }
-
- if (loadBlock == nil) {
- // 没有加在到 block, 也即数据源读取结束
- self.isEOF = true;
- // 有多余的 block 则移除,移除中包含 block
- if (self.blockList.count > block.index) {
- self.blockList = [[self.blockList subarrayWithRange:NSMakeRange(0, block.index)] mutableCopy];
- }
- } else {
- // 加在到 block
- if (loadBlock.index == self.blockList.count) {
- // 新块:block index 等于 blockList size 则为新创建 block,需要加入 blockList
- [self.blockList addObject:loadBlock];
- } else if (loadBlock != block) {
- // 更换块:重新加在了 block, 更换信息
- [self.blockList replaceObjectAtIndex:loadBlock.index withObject:loadBlock];
- }
-
- // 数据源读取结束,块读取大小小于预期,读取结束
- if (loadBlock.size < kBlockSize) {
- self.isEOF = true;
- // 有多余的 block 则移除,移除中不包含 block
- if (self.blockList.count > block.index + 1) {
- self.blockList = [[self.blockList subarrayWithRange:NSMakeRange(0, block.index + 1)] mutableCopy];
- }
- }
- }
-
- return loadBlock;
- }
- - (QNUploadBlock *)nextUploadBlockFormBlockList {
- if (self.blockList == nil || self.blockList.count == 0) {
- return nil;
- }
-
- __block QNUploadBlock *block = nil;
- [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *blockP, NSUInteger idx, BOOL * _Nonnull stop) {
- QNUploadData *data = [blockP nextUploadDataWithoutCheckData];
- if (data != nil) {
- block = blockP;
- *stop = true;
- }
- }];
- return block;
- }
- // 加载块中的数据
- // 1. 数据块已加载,直接返回
- // 2. 数据块未加载,读块数据
- // 2.1 如果未读到数据,则已 EOF,返回 null
- // 2.2 如果读到数据
- // 2.2.1 如果块数据符合预期,则当片未上传,则加载片数据
- // 2.2.2 如果块数据不符合预期,创建新块,加载片信息
- - (QNUploadBlock *)loadBlockData:(QNUploadBlock *)block error:(NSError **)error {
- if (block == nil) {
- return nil;
- }
-
- // 已经加载过 block 数据
- // 没有需要上传的片 或者 有需要上传片但是已加载过片数据
- QNUploadData *nextUploadData = [block nextUploadDataWithoutCheckData];
- if (nextUploadData.state == QNUploadStateWaitToUpload && nextUploadData.data != nil) {
- return block;
- }
-
- // 未加载过 block 数据
- // 根据 block 信息加载 blockBytes
- NSData *blockBytes = nil;
- blockBytes = [self readData:block.size dataOffset:block.offset error:error];
- if (*error != nil) {
- return nil;
- }
- // 没有数据不需要上传
- if (blockBytes == nil || blockBytes.length == 0) {
- return nil;
- }
- NSString *md5 = [blockBytes qn_md5];
- // 判断当前 block 的数据是否和实际数据吻合,不吻合则之前 block 被抛弃,重新创建 block
- if (blockBytes.length != block.size || block.md5 == nil || ![block.md5 isEqualToString:md5]) {
- block = [[QNUploadBlock alloc] initWithOffset:block.offset blockSize:blockBytes.length dataSize:self.dataSize index:block.index];
- block.md5 = md5;
- }
- for (QNUploadData *data in block.uploadDataList) {
- if (data.state != QNUploadStateComplete) {
- // 还未上传的
- data.data = [blockBytes subdataWithRange:NSMakeRange((NSUInteger)data.offset, (NSUInteger)data.size)];
- data.state = QNUploadStateWaitToUpload;
- } else {
- // 已经上传的
- data.state = QNUploadStateComplete;
- }
- }
- return block;
- }
- - (QNUploadData *)nextUploadData:(QNUploadBlock *)block {
- if (block == nil) {
- return nil;
- }
- return [block nextUploadDataWithoutCheckData];
- }
- - (NSArray <NSString *> *)allBlocksContexts {
- if (self.blockList == nil || self.blockList.count == 0) {
- return nil;
- }
-
- NSMutableArray *contexts = [NSMutableArray array];
- [self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
- if (block.context && block.context.length > 0) {
- [contexts addObject:block.context];
- }
- }];
- return [contexts copy];
- }
- @end
|