DataGetOutcome PdsClientImpl::ResumableFileDownload()

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();
}