33#include < iostream>
44#include < thread>
55#include < nlohmann/json.hpp>
6+ #include < cpr/cpr.h>
67
78#include " projectdownloader.h"
89#include " downloaderfactory.h"
@@ -19,6 +20,8 @@ static const std::string ASSET_SUFFIX = "/get";
1920 m_cancelMutex.lock(); \
2021 if (m_cancel) { \
2122 m_downloadedAssetCount = 0 ; \
23+ m_cancelMutex.unlock (); \
24+ std::cout << " Download aborted!" << std::endl; \
2225 return false ; \
2326 } \
2427 m_cancelMutex.unlock()
@@ -41,17 +44,13 @@ bool ProjectDownloader::downloadJson(const std::string &projectId)
4144
4245 // Get project token
4346 std::cout << " Fetching project info of " << projectId << std::endl;
44- m_tokenDownloader->startDownload (PROJECT_META_PREFIX + projectId);
45- m_tokenDownloader->wait ();
47+ bool ret = m_tokenDownloader->download (PROJECT_META_PREFIX + projectId);
4648
47- if (m_tokenDownloader-> text (). empty () ) {
49+ if (!ret ) {
4850 std::cerr << " Could not fetch project info of " << projectId << std::endl;
4951 return false ;
5052 }
5153
52- if (m_tokenDownloader->isCancelled ())
53- return false ;
54-
5554 CHECK_CANCEL ();
5655
5756 nlohmann::json json;
@@ -76,17 +75,13 @@ bool ProjectDownloader::downloadJson(const std::string &projectId)
7675
7776 // Download project JSON
7877 std::cout << " Downloading project JSON of " << projectId << std::endl;
79- m_jsonDownloader->startDownload (PROJECT_JSON_PREFIX + projectId + " ?token=" + token);
80- m_jsonDownloader->wait ();
78+ ret = m_jsonDownloader->download (PROJECT_JSON_PREFIX + projectId + " ?token=" + token);
8179
82- if (m_jsonDownloader-> text (). empty () ) {
80+ if (!ret ) {
8381 std::cerr << " Failed to download project JSON of " << projectId << std::endl;
8482 return false ;
8583 }
8684
87- if (m_jsonDownloader->isCancelled ())
88- return false ;
89-
9085 CHECK_CANCEL ();
9186
9287 return true ;
@@ -100,16 +95,16 @@ bool ProjectDownloader::downloadAssets(const std::vector<std::string> &assetIds)
10095
10196 auto count = assetIds.size ();
10297 unsigned int threadCount = std::thread::hardware_concurrency ();
103- unsigned int times; // how many times we should download assets simultaneously (in "groups")
98+
99+ // Thread count: number of assets / 5, limited to maximum number of threads
100+ threadCount = std::max (1u , std::min (threadCount, static_cast <unsigned int >(std::ceil (count / 5.0 ))));
101+
104102 m_assets.clear ();
103+ m_assets.reserve (count);
105104 m_downloadedAssetCount = 0 ;
106105
107- // Calculate number of "groups"
108- if (threadCount == 0 ) {
109- times = count;
110- threadCount = 1 ;
111- } else
112- times = std::ceil (count / static_cast <double >(threadCount));
106+ for (unsigned int i = 0 ; i < count; i++)
107+ m_assets.push_back (std::string ());
113108
114109 std::cout << " Downloading " << count << " asset(s)" ;
115110
@@ -125,33 +120,55 @@ bool ProjectDownloader::downloadAssets(const std::vector<std::string> &assetIds)
125120 downloaders.push_back (m_downloaderFactory->create ());
126121
127122 // Download assets
128- for (unsigned int i = 0 ; i < times; i++) {
129- unsigned int currentCount = std::min (threadCount, static_cast <unsigned int >(count - i * threadCount));
123+ auto f = [this , &downloaders, &assetIds, count, threadCount](unsigned int thread) {
124+ auto downloader = downloaders[thread];
125+ unsigned int n = std::ceil (count / static_cast <double >(threadCount));
126+
127+ for (unsigned int i = 0 ; i < n; i++) {
128+ unsigned int index = thread * n + i;
129+
130+ if (index < count) {
131+ m_cancelMutex.lock ();
130132
131- for ( unsigned int j = 0 ; j < currentCount; j++ )
132- downloaders[j]-> startDownload (ASSET_PREFIX + assetIds[i * threadCount + j] + ASSET_SUFFIX) ;
133+ if (m_cancel )
134+ return ;
133135
134- for (unsigned int j = 0 ; j < currentCount; j++) {
135- downloaders[j]->wait ();
136- assert (m_assets.size () == i * threadCount + j);
136+ m_cancelMutex.unlock ();
137137
138- if (downloaders[j]->isCancelled ())
139- return false ;
138+ bool ret = downloader->download (ASSET_PREFIX + assetIds[index] + ASSET_SUFFIX);
140139
141- CHECK_CANCEL ();
140+ if (!ret) {
141+ std::cerr << " Failed to download asset: " << assetIds[index] << std::endl;
142+ m_cancelMutex.lock ();
143+ m_cancel = true ;
144+ m_cancelMutex.unlock ();
145+ return ;
146+ }
142147
143- m_assets.push_back (downloaders[j]->text ());
144- m_downloadedAssetCount++;
148+ m_assetsMutex.lock ();
149+ m_assets[index] = downloader->text ();
150+ m_downloadedAssetCount++;
151+ std::cout << " Downloaded assets: " << m_downloadedAssetCount << " of " << count << std::endl;
152+ m_assetsMutex.unlock ();
153+ }
145154 }
146- }
155+ };
156+
157+ std::vector<std::thread> threads;
158+
159+ for (unsigned int i = 0 ; i < threadCount; i++)
160+ threads.emplace_back (std::thread (f, i));
161+
162+ for (unsigned int i = 0 ; i < threadCount; i++)
163+ threads[i].join ();
164+
165+ CHECK_CANCEL ();
147166
148167 return true ;
149168}
150169
151170void ProjectDownloader::cancel ()
152171{
153- m_tokenDownloader->cancel ();
154- m_jsonDownloader->cancel ();
155172 m_cancelMutex.lock ();
156173 m_cancel = true ;
157174 m_cancelMutex.unlock ();
0 commit comments