1 #include <mbgl/style/sources/geojson_source.hpp>
2 #include <mbgl/style/sources/geojson_source_impl.hpp>
3 #include <mbgl/style/source_observer.hpp>
4 #include <mbgl/style/conversion/json.hpp>
5 #include <mbgl/style/conversion/geojson.hpp>
6 #include <mbgl/storage/file_source.hpp>
7 #include <mbgl/util/logging.hpp>
8 
9 namespace mbgl {
10 namespace style {
11 
GeoJSONSource(const std::string & id,const GeoJSONOptions & options)12 GeoJSONSource::GeoJSONSource(const std::string& id, const GeoJSONOptions& options)
13     : Source(makeMutable<Impl>(std::move(id), options)) {
14 }
15 
16 GeoJSONSource::~GeoJSONSource() = default;
17 
impl() const18 const GeoJSONSource::Impl& GeoJSONSource::impl() const {
19     return static_cast<const Impl&>(*baseImpl);
20 }
21 
setURL(const std::string & url_)22 void GeoJSONSource::setURL(const std::string& url_) {
23     url = std::move(url_);
24 
25     // Signal that the source description needs a reload
26     if (loaded || req) {
27         loaded = false;
28         req.reset();
29         observer->onSourceDescriptionChanged(*this);
30     }
31 }
32 
setGeoJSON(const mapbox::geojson::geojson & geoJSON)33 void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) {
34     req.reset();
35     baseImpl = makeMutable<Impl>(impl(), geoJSON);
36     observer->onSourceChanged(*this);
37 }
38 
getURL() const39 optional<std::string> GeoJSONSource::getURL() const {
40     return url;
41 }
42 
loadDescription(FileSource & fileSource)43 void GeoJSONSource::loadDescription(FileSource& fileSource) {
44     if (!url) {
45         loaded = true;
46         return;
47     }
48 
49     if (req) {
50         return;
51     }
52 
53     req = fileSource.request(Resource::source(*url), [this](Response res) {
54         if (res.error) {
55             observer->onSourceError(
56                 *this, std::make_exception_ptr(std::runtime_error(res.error->message)));
57         } else if (res.notModified) {
58             return;
59         } else if (res.noContent) {
60             observer->onSourceError(
61                 *this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON")));
62         } else {
63             conversion::Error error;
64             optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error);
65             if (!geoJSON) {
66                 Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s",
67                            error.message.c_str());
68                 // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
69                 // tiles to load.
70                 baseImpl = makeMutable<Impl>(impl(), GeoJSON{ FeatureCollection{} });
71             } else {
72                 baseImpl = makeMutable<Impl>(impl(), *geoJSON);
73             }
74 
75             loaded = true;
76             observer->onSourceLoaded(*this);
77         }
78     });
79 }
80 
81 } // namespace style
82 } // namespace mbgl
83