384 if (d->m_taskTreeRunner.isRunning())
390 QByteArray jsonContent;
392 QList<QUrl> assetsToDownload;
393 QByteArray zipContent;
397 const Storage<StorageData> storage;
399 const auto onSetup = [
this, storage] {
401 d->m_manager = std::make_unique<QNetworkAccessManager>();
402 if (!d->m_temporaryDir)
403 d->m_temporaryDir = std::make_unique<QTemporaryDir>();
404 if (!d->m_temporaryDir->isValid()) {
405 qWarning() <<
"Cannot create a temporary directory.";
406 return SetupResult::StopWithError;
408 storage->tempDir = d->m_temporaryDir->path();
409 d->setLocalDownloadDir(baseLocalDir(d->m_preferredLocalDownloadDir));
410 d->m_networkErrors.clear();
411 d->m_sslErrors.clear();
412 precheckLocalFile(resolvedUrl(d->m_offlineAssetsFilePath));
413 return SetupResult::Continue;
416 const auto onJsonDownloadSetup = [
this](NetworkQuery &query) {
417 query.setRequest(QNetworkRequest(d->m_downloadBase.resolved(d->m_jsonFileName)));
418 d->setupDownload(&query, tr(
"Downloading JSON file..."));
420 const auto onJsonDownloadDone = [
this, storage](
const NetworkQuery &query, DoneWith result) {
421 if (result == DoneWith::Success) {
422 storage->jsonContent = query.reply()->readAll();
423 return DoneResult::Success;
425 qWarning() <<
"Cannot download" << d->m_downloadBase.resolved(d->m_jsonFileName)
426 << query.reply()->errorString();
427 if (d->m_offlineAssetsFilePath.isEmpty()) {
428 qWarning() <<
"Also there is no local file as a replacement";
429 return DoneResult::Error;
432 QFile file(pathFromUrl(resolvedUrl(d->m_offlineAssetsFilePath)));
433 if (!file.open(QIODevice::ReadOnly)) {
434 qWarning() <<
"Also failed to open" << d->m_offlineAssetsFilePath;
435 return DoneResult::Error;
438 storage->jsonContent = file.readAll();
439 return DoneResult::Success;
442 const auto onReadAssetsFileSetup = [storage](ConcurrentCall<DownloadableAssets> &async) {
443 async.setConcurrentCallData(readAssetsFileContent, storage->jsonContent);
445 const auto onReadAssetsFileDone = [storage](
const ConcurrentCall<DownloadableAssets> &async) {
446 storage->assets = async.result();
447 storage->assetsToDownload = storage->assets.files;
450 const auto onSkipIfAllAssetsPresent = [
this, storage] {
451 return allAssetsPresent(storage->assets.files, d->m_localDownloadDir)
452 ? SetupResult::StopWithSuccess : SetupResult::Continue;
455 const auto onZipDownloadSetup = [
this, storage](NetworkQuery &query) {
456 if (d->m_zipFileName.isEmpty())
457 return SetupResult::StopWithSuccess;
459 query.setRequest(QNetworkRequest(d->m_downloadBase.resolved(d->m_zipFileName)));
460 d->setupDownload(&query, tr(
"Downloading zip file..."));
461 return SetupResult::Continue;
463 const auto onZipDownloadDone = [storage](
const NetworkQuery &query, DoneWith result) {
464 if (result == DoneWith::Success)
465 storage->zipContent = query.reply()->readAll();
466 return DoneResult::Success;
469 const auto onUnzipSetup = [
this, storage](ConcurrentCall<
void> &async) {
470 if (storage->zipContent.isEmpty())
471 return SetupResult::StopWithSuccess;
473 async.setConcurrentCallData(unzip, storage->zipContent, storage->tempDir, d->m_zipFileName);
474 d->clearProgress(tr(
"Unzipping..."));
475 return SetupResult::Continue;
477 const auto onUnzipDone = [storage](DoneWith result) {
478 if (result == DoneWith::Success) {
480 StorageData &storageData = *storage;
481 storageData.assetsToDownload =
482 filterDownloadableAssets(storageData.assets.files, storageData.tempDir);
484 qWarning() <<
"ZipFile failed";
486 return DoneResult::Success;
489 const LoopUntil downloadIterator([storage](
int iteration) {
490 return iteration < storage->assetsToDownload.count();
493 const Storage<QByteArray> assetStorage;
495 const auto onAssetsDownloadGroupSetup = [
this, storage] {
496 d->setProgress(0, storage->assetsToDownload.size(), tr(
"Downloading assets..."));
499 const auto onAssetDownloadSetup = [
this, storage, downloadIterator](NetworkQuery &query) {
500 query.setNetworkAccessManager(d->m_manager.get());
501 query.setRequest(QNetworkRequest(storage->assets.remoteUrl.resolved(
502 storage->assetsToDownload.at(downloadIterator.iteration()))));
504 const auto onAssetDownloadDone = [assetStorage](
const NetworkQuery &query, DoneWith result) {
505 if (result == DoneWith::Success)
506 *assetStorage = query.reply()->readAll();
509 const auto onAssetWriteSetup = [storage, downloadIterator, assetStorage](
510 ConcurrentCall<
void> &async) {
511 const QString filePath = storage->tempDir.absoluteFilePath(
512 storage->assetsToDownload.at(downloadIterator.iteration()).toString());
513 async.setConcurrentCallData(writeAsset, *assetStorage, filePath);
515 const auto onAssetWriteDone = [
this, storage](DoneWith result) {
516 if (result != DoneWith::Success) {
517 qWarning() <<
"Asset write failed";
520 StorageData &storageData = *storage;
521 ++storageData.doneCount;
522 d->updateProgress(storageData.doneCount, storageData.assetsToDownload.size());
525 const LoopUntil copyIterator([storage](
int iteration) {
526 return iteration < storage->assets.files.count();
529 const auto onAssetsCopyGroupSetup = [
this, storage] {
530 storage->doneCount = 0;
531 d->setProgress(0, storage->assets.files.size(), tr(
"Copying assets..."));
534 const auto onAssetCopySetup = [
this, storage, copyIterator](ConcurrentCall<
void> &async) {
535 const QString fileName = storage->assets.files.at(copyIterator.iteration()).toString();
536 const QString sourcePath = storage->tempDir.absoluteFilePath(fileName);
537 const QString destPath = d->m_localDownloadDir.absoluteFilePath(fileName);
538 async.setConcurrentCallData(copyAndCheck, sourcePath, destPath);
540 const auto onAssetCopyDone = [
this, storage] {
541 StorageData &storageData = *storage;
542 ++storageData.doneCount;
543 d->updateProgress(storageData.doneCount, storageData.assets.files.size());
546 const auto onAssetsCopyGroupDone = [
this, storage](DoneWith result) {
547 if (result != DoneWith::Success) {
548 d->setLocalDownloadDir(storage->tempDir);
549 qWarning() <<
"Asset copy failed";
552 d->m_temporaryDir.reset();
557 onGroupSetup(onSetup),
558 NetworkQueryTask(onJsonDownloadSetup, onJsonDownloadDone),
559 ConcurrentCallTask<DownloadableAssets>(onReadAssetsFileSetup, onReadAssetsFileDone, CallDoneIf::Success),
561 onGroupSetup(onSkipIfAllAssetsPresent),
562 NetworkQueryTask(onZipDownloadSetup, onZipDownloadDone),
563 ConcurrentCallTask<
void>(onUnzipSetup, onUnzipDone),
564 For (downloadIterator) >> Do {
565 parallelIdealThreadCountLimit,
566 onGroupSetup(onAssetsDownloadGroupSetup),
569 NetworkQueryTask(onAssetDownloadSetup, onAssetDownloadDone),
570 ConcurrentCallTask<
void>(onAssetWriteSetup, onAssetWriteDone)
573 For (copyIterator) >> Do {
574 parallelIdealThreadCountLimit,
575 onGroupSetup(onAssetsCopyGroupSetup),
576 ConcurrentCallTask<
void>(onAssetCopySetup, onAssetCopyDone, CallDoneIf::Success),
577 onGroupDone(onAssetsCopyGroupDone)
581 d->m_taskTreeRunner.start(recipe, [
this](TaskTree *) { emit started(); },
582 [
this](DoneWith result) { emit finished(result == DoneWith::Success); });