#define MICHLIB_NOSOURCE #include "copcat.h" #include "GPL.h" #include "mirrorfuncs.h" const MString CopernicusCatalog::caturl = "https://stac.marine.copernicus.eu/metadata/catalog.stac.json"; CopernicusCatalog::CopernicusCatalog() { // Cache auto oldprefix = michlib::GPL.UsePrefix("COPERNICUS"); cache.reset(CreateCache(michlib::GPL.ParameterSValue("Cache", ""))); michlib::GPL.UsePrefix(oldprefix); if(!cache) { michlib::errmessage("Can't init cache"); cache.reset(new FakeCache); } GetCatalog(); } Error CopernicusCatalog::GetCatalog() { if(Valid()) return Error(); auto ret = GetJSON(caturl); if(ret) catalog = ret.Value(); else return ret.Add("CopernicusCatalog::GetCatalog", "can't download catalog"); return Error(); } RetVal> CopernicusCatalog::ProductList() const { static const MString pref = "CopernicusCatalog::ProductList"; if(!Valid()) return {pref, "no catalog"}; const auto& links = catalog["links"]; if(links.type() != Json::arrayValue) return {pref, "no \"links\" section in the catalog"}; std::vector out; for(Json::ArrayIndex i = 0; i < links.size(); i++) { const auto& rel = links[i]["rel"]; const auto& titl = links[i]["title"]; if(rel.type() == Json::stringValue && titl.type() == Json::stringValue && rel.asString() == "child") out.emplace_back(titl.asString().c_str()); } return out; } RetVal CopernicusCatalog::ProductURL(const MString& prod) const { static const MString pref = "CopernicusCatalog::ProductURL"; if(!Valid()) return {pref, "no catalog"}; const auto& links = catalog["links"]; if(links.type() != Json::arrayValue) return {pref, "no \"links\" section in the catalog"}; for(Json::ArrayIndex i = 0; i < links.size(); i++) { const auto& titl = links[i]["title"]; const auto& href = links[i]["href"]; if(titl.type() == Json::stringValue && href.type() == Json::stringValue && titl.asString().c_str() == prod) return DirName(caturl) + "/" + MString(href.asString().c_str()); } return {pref, "unknown product: " + prod}; } RetVal> CopernicusCatalog::DatasetList(const MString& prod) const { static const MString pref = "CopernicusCatalog::DatasetList"; MString url; { auto ret = ProductURL(prod); if(!ret) return ret.Add(pref, "Can't get url for the product " + prod); url = ret.Value(); } auto ret = GetJSON(url); if(!ret) return ret.Add(pref, "Can't download product " + prod); const auto& links = ret.Value()["links"]; if(links.type() != Json::arrayValue) return {pref, "no \"links\" section in the product " + prod + " description"}; std::vector out; for(Json::ArrayIndex i = 0; i < links.size(); i++) { const auto& rel = links[i]["rel"]; const auto& titl = links[i]["title"]; if(rel.type() == Json::stringValue && titl.type() == Json::stringValue && rel.asString() == "item") out.emplace_back(titl.asString().c_str()); } return out; } RetVal CopernicusCatalog::DatasetURL(const MString& prod, const MString& dataset) const { static const MString pref = "CopernicusCatalog::DatasetURL"; MString url; { auto ret = ProductURL(prod); if(!ret) return ret.Add(pref, "Can't get url for the product " + prod); url = ret.Value(); } auto ret = GetJSON(url); if(!ret) return ret.Add(pref, "Can't download product " + prod); const auto& links = ret.Value()["links"]; if(links.type() != Json::arrayValue) return {pref, "no \"links\" section in the product " + prod + " description"}; for(Json::ArrayIndex i = 0; i < links.size(); i++) { const auto& titl = links[i]["title"]; const auto& href = links[i]["href"]; if(titl.type() == Json::stringValue && href.type() == Json::stringValue && titl.asString().c_str() == dataset) return DirName(url) + "/" + MString(href.asString().c_str()); } return {pref, "unknown dataset: " + dataset}; } RetVal CopernicusCatalog::AssetURL(const MString& prod, const MString& dataset, const MString& asset) const { static const MString pref = "CopernicusCatalog::AssetURL"; MString url; { auto ret = DatasetURL(prod, dataset); if(!ret) return ret.Add(pref, "Can't get url for the dataset " + dataset); url = ret.Value(); } auto ret = GetJSON(url); if(!ret) return ret.Add(pref, "Can't download dataset " + dataset); const auto& href = ret.Value()["assets"][asset.Buf()]["href"]; if(!href || href.type() != Json::stringValue) return {pref, "href for the asset " + asset + " not found"}; return MString(href.asString().c_str()); } RetVal CopernicusCatalog::GetJSON(const MString& url) const { const static MString pref = "CopernicusCatalog::GetJSON"; Json::Reader reader; Json::Value obj; MString content; auto [val, suc] = cache->Get(url); if(suc) content = std::move(val); else { michlib::message(url + " not found in cache, downloading"); auto [out, res] = GetUrl(chandle, url); if(res != CURLE_OK) return Error(pref, MString("can't download JSON: ") + chandle.Err()); cache->Put(url, out, 3600); content = std::move(out); } reader.parse(content.Buf(), content.Buf() + content.Len(), obj, false); return obj; }