void GeoJSONSource::Impl::load(FileSource& fileSource) { if (!urlOrGeoJSON.is<std::string>()) { loaded = true; return; } if (req) { return; } const std::string& url = urlOrGeoJSON.get<std::string>(); req = fileSource.request(Resource::source(url), [this](Response res) { if (res.error) { observer->onSourceError( base, std::make_exception_ptr(std::runtime_error(res.error->message))); } else if (res.notModified) { return; } else if (res.noContent) { observer->onSourceError( base, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON"))); } else { rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d; d.Parse<0>(res.data->c_str()); if (d.HasParseError()) { std::stringstream message; message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError()); observer->onSourceError(base, std::make_exception_ptr(std::runtime_error(message.str()))); return; } invalidateTiles(); conversion::Result<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d); if (!geoJSON) { Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", geoJSON.error().message.c_str()); // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for // tiles to load. setGeoJSON(GeoJSON{ FeatureCollection{} }); } else { setGeoJSON(*geoJSON); } loaded = true; observer->onSourceLoaded(base); } }); }
static optional<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id, const Convertible& value, Error& error) { auto dataValue = objectMember(value, "data"); if (!dataValue) { error = { "GeoJSON source must have a data value" }; return {}; } optional<GeoJSONOptions> options = convert<GeoJSONOptions>(value, error); if (!options) { return {}; } auto result = std::make_unique<GeoJSONSource>(id, *options); if (isObject(*dataValue)) { optional<GeoJSON> geoJSON = convert<GeoJSON>(*dataValue, error); if (!geoJSON) { return {}; } result->setGeoJSON(std::move(*geoJSON)); } else if (toString(*dataValue)) { result->setURL(*toString(*dataValue)); } else { error = { "GeoJSON data must be a URL or an object" }; return {}; } return { std::move(result) }; }