Skip to content

Commit 37f9604

Browse files
authored
Merge pull request #619 from scratchcpp/stop_loading_api
Add API for stopping project loading
2 parents be9846a + a7fb0ce commit 37f9604

File tree

7 files changed

+73
-21
lines changed

7 files changed

+73
-21
lines changed

include/scratchcpp/project.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class LIBSCRATCHCPP_EXPORT Project
2929
Project(const Project &) = delete;
3030

3131
bool load();
32+
void stopLoading();
3233

3334
void start();
3435
void run();

src/internal/projectdownloader.cpp

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@ static const std::string ASSET_PREFIX = "https://assets.scratch.mit.edu/internal
1717
static const std::string ASSET_SUFFIX = "/get";
1818

1919
#define CHECK_CANCEL() \
20-
m_cancelMutex.lock(); \
2120
if (m_cancel) { \
2221
m_downloadedAssetCount = 0; \
23-
m_cancelMutex.unlock(); \
2422
std::cout << "Download aborted!" << std::endl; \
2523
return false; \
26-
} \
27-
m_cancelMutex.unlock()
24+
}
2825

2926
ProjectDownloader::ProjectDownloader(IDownloaderFactory *downloaderFactory) :
3027
m_downloaderFactory(downloaderFactory)
@@ -38,9 +35,7 @@ ProjectDownloader::ProjectDownloader(IDownloaderFactory *downloaderFactory) :
3835

3936
bool ProjectDownloader::downloadJson(const std::string &projectId)
4037
{
41-
m_cancelMutex.lock();
4238
m_cancel = false;
43-
m_cancelMutex.unlock();
4439

4540
// Get project token
4641
std::cout << "Fetching project info of " << projectId << std::endl;
@@ -89,9 +84,7 @@ bool ProjectDownloader::downloadJson(const std::string &projectId)
8984

9085
bool ProjectDownloader::downloadAssets(const std::vector<std::string> &assetIds)
9186
{
92-
m_cancelMutex.lock();
9387
m_cancel = false;
94-
m_cancelMutex.unlock();
9588

9689
auto count = assetIds.size();
9790
// unsigned int threadCount = std::thread::hardware_concurrency();
@@ -119,20 +112,14 @@ bool ProjectDownloader::downloadAssets(const std::vector<std::string> &assetIds)
119112

120113
// Download assets
121114
auto f = [this, count](std::shared_ptr<IDownloader> downloader, int index, const std::string &id) {
122-
m_cancelMutex.lock();
123-
124115
if (m_cancel)
125116
return;
126117

127-
m_cancelMutex.unlock();
128-
129118
bool ret = downloader->download(ASSET_PREFIX + id + ASSET_SUFFIX);
130119

131120
if (!ret) {
132121
std::cerr << "Failed to download asset: " << id << std::endl;
133-
m_cancelMutex.lock();
134122
m_cancel = true;
135-
m_cancelMutex.unlock();
136123
return;
137124
}
138125

@@ -178,7 +165,7 @@ bool ProjectDownloader::downloadAssets(const std::vector<std::string> &assetIds)
178165

179166
m_assetsMutex.lock();
180167

181-
if (m_downloadedAssetCount != lastCount) {
168+
if (m_downloadedAssetCount != lastCount && !m_cancel) {
182169
std::cout << "Downloaded assets: " << m_downloadedAssetCount << " of " << count << std::endl;
183170
lastCount = m_downloadedAssetCount;
184171
}
@@ -197,7 +184,7 @@ bool ProjectDownloader::downloadAssets(const std::vector<std::string> &assetIds)
197184
threads.erase(index);
198185
}
199186

200-
if (done) {
187+
if (done || m_cancel) {
201188
for (auto &[index, info] : threads)
202189
info.first.join();
203190

@@ -212,9 +199,7 @@ bool ProjectDownloader::downloadAssets(const std::vector<std::string> &assetIds)
212199

213200
void ProjectDownloader::cancel()
214201
{
215-
m_cancelMutex.lock();
216202
m_cancel = true;
217-
m_cancelMutex.unlock();
218203
m_downloadedAssetCount = 0;
219204
}
220205

src/internal/projectdownloader.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ class ProjectDownloader : public IProjectDownloader
3636
std::vector<std::string> m_assets;
3737
std::mutex m_assetsMutex;
3838
std::atomic<unsigned int> m_downloadedAssetCount = 0;
39-
bool m_cancel = false;
40-
std::mutex m_cancelMutex;
39+
std::atomic<bool> m_cancel = false;
4140
sigslot::signal<unsigned int, unsigned int> m_downloadProgressChanged;
4241
};
4342

src/project.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// SPDX-License-Identifier: Apache-2.0
22

33
#include <scratchcpp/project.h>
4+
#include <iostream>
45

56
#include "project_p.h"
7+
#include "internal/projectdownloader.h"
68

79
using namespace libscratchcpp;
810

@@ -27,6 +29,14 @@ bool Project::load()
2729
return impl->load();
2830
}
2931

32+
/*! Cancels project loading if loading in another thread. */
33+
void Project::stopLoading()
34+
{
35+
std::cout << "Aborting project loading..." << std::endl;
36+
impl->stopLoading = true;
37+
impl->downloader->cancel();
38+
}
39+
3040
/*!
3141
* Calls all "when green flag clicked" blocks.
3242
* \note Nothing will happen until run() or frame() is called.

src/project_p.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ bool ProjectPrivate::load()
4747

4848
bool ProjectPrivate::tryLoad(IProjectReader *reader)
4949
{
50+
stopLoading = false;
51+
5052
// Load from URL
5153
ProjectUrl url(fileName);
5254

@@ -57,8 +59,18 @@ bool ProjectPrivate::tryLoad(IProjectReader *reader)
5759
return false;
5860
}
5961

62+
if (stopLoading) {
63+
loadingAborted();
64+
return false;
65+
}
66+
6067
bool ret = reader->loadData(downloader->json());
6168

69+
if (stopLoading) {
70+
loadingAborted();
71+
return false;
72+
}
73+
6274
if (!ret)
6375
return false;
6476

@@ -91,7 +103,14 @@ bool ProjectPrivate::tryLoad(IProjectReader *reader)
91103
}
92104

93105
// Download assets
94-
if (!downloader->downloadAssets(assetNames)) {
106+
ret = downloader->downloadAssets(assetNames);
107+
108+
if (stopLoading) {
109+
loadingAborted();
110+
return false;
111+
}
112+
113+
if (!ret) {
95114
std::cerr << "Failed to download the project assets." << std::endl;
96115
return false;
97116
}
@@ -113,7 +132,18 @@ bool ProjectPrivate::tryLoad(IProjectReader *reader)
113132
return false;
114133
}
115134

135+
if (stopLoading) {
136+
loadingAborted();
137+
return false;
138+
}
139+
116140
bool ret = reader->load();
141+
142+
if (stopLoading) {
143+
loadingAborted();
144+
return false;
145+
}
146+
117147
if (!ret)
118148
return false;
119149
}
@@ -125,9 +155,20 @@ bool ProjectPrivate::tryLoad(IProjectReader *reader)
125155
engine->setExtensions(reader->extensions());
126156
engine->setUserAgent(reader->userAgent());
127157
engine->compile();
158+
159+
if (stopLoading) {
160+
loadingAborted();
161+
return false;
162+
}
163+
128164
return true;
129165
}
130166

167+
void ProjectPrivate::loadingAborted()
168+
{
169+
std::cout << "Loading aborted." << std::endl;
170+
}
171+
131172
void ProjectPrivate::start()
132173
{
133174
engine->start();

src/project_p.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct ProjectPrivate
2121

2222
bool load();
2323
bool tryLoad(IProjectReader *reader);
24+
void loadingAborted();
2425

2526
void start();
2627
void run();
@@ -29,6 +30,7 @@ struct ProjectPrivate
2930
sigslot::signal<unsigned int, unsigned int> &downloadProgressChanged();
3031

3132
std::string fileName;
33+
std::atomic<bool> stopLoading = false;
3234
std::shared_ptr<IEngine> engine = nullptr;
3335

3436
static IProjectDownloaderFactory *downloaderFactory;

test/project/project_test.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,17 @@ TEST(LoadProjectTest, DownloadProgressChanged)
115115
EXPECT_CALL(*downloader, downloadProgressChanged).WillOnce(ReturnRef(signal));
116116
ASSERT_EQ(&p.downloadProgressChanged(), &signal);
117117
}
118+
119+
TEST(LoadProjectTest, AbortDownload)
120+
{
121+
ProjectDownloaderFactoryMock factory;
122+
auto downloader = std::make_shared<ProjectDownloaderMock>();
123+
ProjectPrivate::downloaderFactory = &factory;
124+
125+
EXPECT_CALL(factory, create()).WillOnce(Return(downloader));
126+
Project p;
127+
ProjectPrivate::downloaderFactory = nullptr;
128+
129+
EXPECT_CALL(*downloader, cancel());
130+
p.stopLoading();
131+
}

0 commit comments

Comments
 (0)