Cancel pending style request when loading style JSON (#3989)
Signed-off-by: Bart Louwers <bart@emeel.net>
This commit is contained in:
@@ -39,10 +39,15 @@ Style::Impl::Impl(std::shared_ptr<FileSource> fileSource_, float pixelRatio, con
|
|||||||
|
|
||||||
Style::Impl::~Impl() = default;
|
Style::Impl::~Impl() = default;
|
||||||
|
|
||||||
|
void Style::Impl::cancelPendingRequest() noexcept {
|
||||||
|
styleRequest.reset();
|
||||||
|
}
|
||||||
|
|
||||||
void Style::Impl::loadJSON(const std::string& json_) {
|
void Style::Impl::loadJSON(const std::string& json_) {
|
||||||
lastError = nullptr;
|
lastError = nullptr;
|
||||||
observer->onStyleLoading();
|
observer->onStyleLoading();
|
||||||
|
|
||||||
|
cancelPendingRequest();
|
||||||
url.clear();
|
url.clear();
|
||||||
parse(json_);
|
parse(json_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,14 @@ public:
|
|||||||
void loadJSON(const std::string&);
|
void loadJSON(const std::string&);
|
||||||
void loadURL(const std::string&);
|
void loadURL(const std::string&);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cancels any pending style request.
|
||||||
|
*
|
||||||
|
* This will cancel any in-progress style URL load. Has no effect if no
|
||||||
|
* style load is in progress.
|
||||||
|
*/
|
||||||
|
void cancelPendingRequest() noexcept;
|
||||||
|
|
||||||
std::string getJSON() const;
|
std::string getJSON() const;
|
||||||
std::string getURL() const;
|
std::string getURL() const;
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,7 @@ StubFileSource::~StubFileSource() = default;
|
|||||||
std::unique_ptr<AsyncRequest> StubFileSource::request(const Resource& resource, Callback callback) {
|
std::unique_ptr<AsyncRequest> StubFileSource::request(const Resource& resource, Callback callback) {
|
||||||
auto req = std::make_unique<StubFileRequest>(*this);
|
auto req = std::make_unique<StubFileRequest>(*this);
|
||||||
if (type == ResponseType::Synchronous) {
|
if (type == ResponseType::Synchronous) {
|
||||||
std::optional<Response> res = response(resource);
|
if (const std::optional<Response> res = response(resource)) {
|
||||||
if (res) {
|
|
||||||
callback(*res);
|
callback(*res);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -79,6 +78,18 @@ void StubFileSource::remove(AsyncRequest* req) {
|
|||||||
pending.erase(it);
|
pending.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void StubFileSource::respondToAll() {
|
||||||
|
if (type != ResponseType::Manual) {
|
||||||
|
throw std::runtime_error("this method can only be called with ResponseType::Manual");
|
||||||
|
}
|
||||||
|
for (const auto& [key, value] : pending) {
|
||||||
|
auto& [resource, responseFunction, callback] = value;
|
||||||
|
if (const std::optional<Response> res = responseFunction(resource)) {
|
||||||
|
callback(*res);
|
||||||
|
}
|
||||||
|
pending.erase(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void StubFileSource::setProperty(const std::string& key, const mapbox::base::Value& value) {
|
void StubFileSource::setProperty(const std::string& key, const mapbox::base::Value& value) {
|
||||||
properties[key] = value;
|
properties[key] = value;
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ class StubFileSource : public FileSource {
|
|||||||
public:
|
public:
|
||||||
enum class ResponseType {
|
enum class ResponseType {
|
||||||
Asynchronous = 0,
|
Asynchronous = 0,
|
||||||
Synchronous
|
Synchronous,
|
||||||
|
Manual
|
||||||
};
|
};
|
||||||
|
|
||||||
StubFileSource(const ResourceOptions&, const ClientOptions&, ResponseType = ResponseType::Asynchronous);
|
StubFileSource(const ResourceOptions&, const ClientOptions&, ResponseType = ResponseType::Asynchronous);
|
||||||
@@ -26,6 +27,8 @@ public:
|
|||||||
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
|
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
|
||||||
bool canRequest(const Resource&) const override { return true; }
|
bool canRequest(const Resource&) const override { return true; }
|
||||||
void remove(AsyncRequest*);
|
void remove(AsyncRequest*);
|
||||||
|
void respondToAll();
|
||||||
|
|
||||||
void setProperty(const std::string&, const mapbox::base::Value&) override;
|
void setProperty(const std::string&, const mapbox::base::Value&) override;
|
||||||
mapbox::base::Value getProperty(const std::string&) const override;
|
mapbox::base::Value getProperty(const std::string&) const override;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <chrono>
|
||||||
#include <mbgl/test/util.hpp>
|
#include <mbgl/test/util.hpp>
|
||||||
#include <mbgl/test/stub_file_source.hpp>
|
#include <mbgl/test/stub_file_source.hpp>
|
||||||
#include <mbgl/test/fixture_log_observer.hpp>
|
#include <mbgl/test/fixture_log_observer.hpp>
|
||||||
@@ -9,6 +10,7 @@
|
|||||||
#include <mbgl/style/layers/line_layer.hpp>
|
#include <mbgl/style/layers/line_layer.hpp>
|
||||||
#include <mbgl/util/io.hpp>
|
#include <mbgl/util/io.hpp>
|
||||||
#include <mbgl/util/run_loop.hpp>
|
#include <mbgl/util/run_loop.hpp>
|
||||||
|
#include <mbgl/util/client_options.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -110,6 +112,43 @@ TEST(Style, RemoveSourceInUse) {
|
|||||||
EXPECT_EQ(log.count(logMessage), 1u);
|
EXPECT_EQ(log.count(logMessage), 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Style, LoadJSONCancelsPendingLoadURL) {
|
||||||
|
util::RunLoop loop;
|
||||||
|
|
||||||
|
auto fileSource = std::make_shared<::StubFileSource>(
|
||||||
|
ResourceOptions::Default(), ClientOptions(), StubFileSource::ResponseType::Manual);
|
||||||
|
Style::Impl style{fileSource, 1.0, {Scheduler::GetBackground(), {}}};
|
||||||
|
|
||||||
|
// Start loading a URL (this will be pending)
|
||||||
|
auto url = "http://some-url";
|
||||||
|
fileSource->styleResponse = [](const Resource&) {
|
||||||
|
Response result;
|
||||||
|
result.data = std::make_shared<std::string>(util::read_file("test/fixtures/resources/style_vector.json"));
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
style.loadURL(url);
|
||||||
|
|
||||||
|
// Before the URL request completes, load JSON directly
|
||||||
|
const std::string json = R"STYLE({
|
||||||
|
"version": 8,
|
||||||
|
"name": "Test Style",
|
||||||
|
"sources": {},
|
||||||
|
"layers": []
|
||||||
|
})STYLE";
|
||||||
|
style.loadJSON(json);
|
||||||
|
|
||||||
|
// The style should now be loaded with our JSON content
|
||||||
|
ASSERT_EQ("Test Style", style.getName());
|
||||||
|
ASSERT_EQ("", style.getURL());
|
||||||
|
ASSERT_TRUE(style.getJSON().find("Test Style") != std::string::npos);
|
||||||
|
|
||||||
|
fileSource->respondToAll();
|
||||||
|
|
||||||
|
// The style should still show our JSON content, not the URL content
|
||||||
|
ASSERT_EQ("Test Style", style.getName());
|
||||||
|
ASSERT_NE("Streets", style.getName());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Style, SourceImplsOrder) {
|
TEST(Style, SourceImplsOrder) {
|
||||||
util::RunLoop loop;
|
util::RunLoop loop;
|
||||||
auto fileSource = std::make_shared<StubFileSource>();
|
auto fileSource = std::make_shared<StubFileSource>();
|
||||||
|
|||||||
Reference in New Issue
Block a user