in sdk/src/PdsClientImpl.cc [798:924]
DataGetOutcome PdsClientImpl::ResumableFileDownload(const FileDownloadRequest &request) const
{
const auto& reqeustBase = static_cast<const PdsResumableBaseRequest &>(request);
int code = reqeustBase.validate();
if (code != 0) {
return DataGetOutcome(PdsError("ValidateError", reqeustBase.validateMessage(code)));
}
auto getDownloadUrlReq = FileGetDownloadUrlRequest(request.DriveID(), request.ShareID(), request.FileID());
getDownloadUrlReq.setShareToken(request.ShareToken());
auto getDownloadUrlOutcome = FileGetDownloadUrl(getDownloadUrlReq);
if (!getDownloadUrlOutcome.isSuccess()) {
return DataGetOutcome(getDownloadUrlOutcome.error());
}
auto url = getDownloadUrlOutcome.result().Url();
if (url.empty()) {
return DataGetOutcome(PdsError("DownloadUrlEmptyError", "Download data url is empty."));
}
auto punishFlag = getDownloadUrlOutcome.result().PunishFlag();
if (!configuration().enableDownloadPunishedFile && punishFlag == PunishFlagFileFreeze) {
return DataGetOutcome(PdsError("FileIsPunished", "Punished File cannot be downloaded."));
}
auto fileSize = getDownloadUrlOutcome.result().Size();
auto contentHash = getDownloadUrlOutcome.result().ContentHash();
auto crc64Hash = getDownloadUrlOutcome.result().Crc64Hash();
// small file and punished file are downloaded by single OSS GET request
if (fileSize < (int64_t)request.PartSize() || punishFlag == PunishFlagFileFreeze) {
auto getDataReq = DataGetByUrlRequest(url);
if (request.TransferProgress().Handler) {
getDataReq.setTransferProgress(request.TransferProgress());
}
if (request.ProgressControl().Handler) {
getDataReq.setProgressControl(request.ProgressControl());
}
if (request.TrafficLimit() != 0) {
getDataReq.setTrafficLimit(request.TrafficLimit());
}
getDataReq.setResponseStreamFactory([=]() {
return GetFstreamByPath(request.TempFilePath(), request.TempFilePathW(),
std::ios_base::out | std::ios_base::in | std::ios_base::trunc | std::ios_base::binary);
});
if (configuration().enableCrc64 && !crc64Hash.empty()) {
getDataReq.setFlags(getDataReq.Flags() | REQUEST_FLAG_CHECK_CRC64 | REQUEST_FLAG_SAVE_CLIENT_CRC64);
}
auto outcome = DataGetByUrl(getDataReq);
auto controller = request.ProgressControl();
if (controller.Handler) {
int32_t controlFlag = controller.Handler(controller.UserData);
if (controlFlag == ProgressControlStop || controlFlag == ProgressControlCancel) {
if (IsFileExist(request.TempFilePath())) {
RemoveFile(request.TempFilePath());
}
#ifdef _WIN32
else if (IsFileExist(request.TempFilePathW())) {
RemoveFile(request.TempFilePathW());
}
#endif
}
if (controlFlag == ProgressControlStop) {
return DataGetOutcome(PdsError("ClientError:100003", "Download stop by upper."));
}
if (controlFlag == ProgressControlCancel) {
return DataGetOutcome(PdsError("ClientError:100004", "Download cancel by upper."));
}
}
std::shared_ptr<std::iostream> content = nullptr;
outcome.result().setContent(content);
// check size
if (configuration().enableCheckDownloadFileSize) {
uint64_t localFileSize = GetFileSize(request.TempFilePath(), request.TempFilePathW());
// for punished file, downloaded file size may not be equal to origin file size
if (uint64_t(fileSize) != localFileSize && punishFlag != PunishFlagFileFreeze) {
return DataGetOutcome(PdsError("FileSizeCheckError", "Download data check size fail."));
}
}
if (configuration().enableCrc64 && !crc64Hash.empty()) {
auto localCRC64 = std::strtoull(outcome.result().Metadata().HttpMetaData().at("x-oss-hash-crc64ecma-by-client").c_str(), nullptr, 10);
uint64_t ossServerCrc64 = std::strtoull(outcome.result().Metadata().HttpMetaData().at("x-oss-hash-crc64ecma").c_str(), nullptr, 10);
if (localCRC64 != ossServerCrc64) {
if (IsFileExist(request.TempFilePath())) {
RemoveFile(request.TempFilePath());
}
#ifdef _WIN32
else if (IsFileExist(request.TempFilePathW())) {
RemoveFile(request.TempFilePathW());
}
#endif
return DataGetOutcome(PdsError("CrcCheckError", "Download data CRC checksum fail."));
}
}
bool renameSuccess = false;
if (!request.TempFilePath().empty()) {
renameSuccess = RenameFile(request.TempFilePath(), request.FilePath());
}
#ifdef _WIN32
else if (!request.TempFilePathW().empty()) {
renameSuccess = RenameFile(request.TempFilePathW(), request.FilePathW());
}
#endif
if (!renameSuccess) {
std::stringstream ss;
ss << "rename temp file failed";
return DataGetOutcome(PdsError("RenameError", ss.str()));
}
if (IsFileExist(request.TempFilePath())) {
RemoveFile(request.TempFilePath());
}
#ifdef _WIN32
else if (IsFileExist(request.TempFilePathW())) {
RemoveFile(request.TempFilePathW());
}
#endif
return outcome;
}
ResumableDownloader downloader(request, this, fileSize, contentHash, crc64Hash, url);
return downloader.Download();
}