30#include <wx/filename.h>
31#include <wx/jsonreader.h>
34#include "catalog_handler.h"
35#include "catalog_parser.h"
36#include "downloader.h"
37#include "observable_evtvar.h"
38#include "observable_globvar.h"
39#include "ocpn_utils.h"
40#include "base_platform.h"
41#include "plugin_handler.h"
44static const std::string SEP(
"\\");
46static const std::string SEP(
"/");
49extern wxString g_catalog_custom_url;
50extern wxString g_catalog_channel;
53static const char*
const DOWNLOAD_REPO =
54 "https://raw.githubusercontent.com/OpenCPN/plugins";
56static const char*
const DOWNLOAD_PATH =
"/@branch@/ocpn-plugins.xml";
58static const char*
const API_ENDPOINT =
"https://api.github.com/repos";
60static const char*
const API_PATH =
"/OpenCPN/plugins/branches";
63 if (g_catalog_channel ==
"") {
64 g_catalog_channel = DEFAULT_CHANNEL;
77 std::string url = std::string(DOWNLOAD_REPO) + DOWNLOAD_PATH;
78 ocpn::replace(url,
"@branch@", g_catalog_channel.ToStdString());
83 std::string path(g_catalog_custom_url.ToStdString());
85 path = std::string(DOWNLOAD_REPO) + DOWNLOAD_PATH;
86 ocpn::replace(path,
"@branch@", g_catalog_channel.ToStdString());
87 wxLogMessage(
"Effective catalog path: %s", path.c_str());
90 bool ok = downloader.
download(stream);
92 return ServerStatus::OK;
95 return ServerStatus::CURL_ERROR;
101 bool ok = downloader.
download(stream);
103 return ServerStatus::OK;
106 return ServerStatus::CURL_ERROR;
110 if (filePath ==
"") {
111 filePath = wxFileName::CreateTempFileName(
"ocpn_dl").ToStdString();
113 std::ofstream stream;
114 stream.open(filePath.c_str(), std::ios::out | std::ios::trunc);
115 if (!stream.is_open()) {
116 wxLogMessage(
"CatalogHandler: Cannot open %s for write", filePath);
117 error_msg = strerror(errno);
118 return ServerStatus::OS_ERROR;
127 if (filePath ==
"") {
128 filePath = wxFileName::CreateTempFileName(
"ocpn_dl").ToStdString();
130 std::ofstream stream;
131 stream.open(filePath.c_str(), std::ios::out | std::ios::trunc);
132 if (!stream.is_open()) {
133 wxLogMessage(
"CatalogHandler: Cannot open %s for write", filePath);
134 error_msg = strerror(errno);
135 return ServerStatus::OS_ERROR;
142catalog_status CatalogHandler::DoParseCatalog(
const std::string xml,
147 while (ctx->meta_urls.size() > 0) {
148 std::ostringstream xml;
149 url = ctx->meta_urls.back();
150 ctx->meta_urls.pop_back();
154 for (std::vector<std::string>::iterator it = ctx->parsed_metas.begin();
155 it != ctx->parsed_metas.end(); it++) {
163 ctx->parsed_metas.push_back(url);
165 wxLogMessage(
"CatalogHandler: Cannot download meta-url: %s",
168 ok = DoParseCatalog(xml.str(), ctx) == ServerStatus::OK;
174 wxLogWarning(
"Cannot parse xml starting with: %s",
175 xml.substr(0, 60).c_str());
177 return ok ? ServerStatus::OK : ServerStatus::XML_ERROR;
183 auto status = DoParseCatalog(xml, &ctx);
184 if (status == ServerStatus::OK && latest) {
185 this->latest_data.version = ctx.version;
186 this->latest_data.date = ctx.date;
187 this->latest_data.undef =
false;
195 for (
auto c : channels) {
198 catalog_channel.
Set(channel);
202 wxLogMessage(
"Attempt to set illegal active channel: %s", channel);
207 return g_catalog_channel.ToStdString();
211 g_catalog_custom_url = url;
215 if (latest_data.undef) {
216 std::ostringstream os;
224void CatalogHandler::LoadCatalogData(
const std::string& path,
226 if (!ocpn::exists(path)) {
233 file.open(path, std::ios::in);
234 if (file.is_open()) {
235 std::string xml((std::istreambuf_iterator<char>(file)),
236 std::istreambuf_iterator<char>());
239 auto status = DoParseCatalog(xml, &ctx);
240 if (status == ServerStatus::OK) {
241 data.version = ctx.version;
242 data.date = ctx.date;
249 if (user_data.undef) {
250 auto plugin_handler = PluginHandler::getInstance();
251 std::string path = g_BasePlatform->GetPrivateDataDir().ToStdString();
253 path +=
"ocpn-plugins.xml";
254 LoadCatalogData(path, user_data);
260 if (default_data.undef) {
261 auto plugin_handler = PluginHandler::getInstance();
262 std::string path = g_BasePlatform->GetSharedDataDir().ToStdString();
264 path +=
"ocpn-plugins.xml";
265 LoadCatalogData(path, default_data);
271 default_data.undef =
true;
272 user_data.undef =
true;
273 latest_data.undef =
true;
277 return g_catalog_custom_url.ToStdString();
283 Downloader downloader(std::string(API_ENDPOINT) + API_PATH);
284 bool ok = downloader.
download(stream);
286 return ServerStatus::OK;
289 return ServerStatus::CURL_ERROR;
295 parser.Parse(json.c_str(), &node);
296 if (!node.IsArray()) {
297 wxLogMessage(
"Cannot parse json (toplevel)");
298 error_msg = parser.GetErrors().Item(0).ToStdString();
299 return ServerStatus::JSON_ERROR;
301 auto branches = node.AsArray();
302 wxLogMessage(
"Got %d branches", branches->Count());
304 for (
size_t i = 0; i < branches->Count(); i += 1) {
305 auto branch = branches->Item(i);
306 channels.push_back(branch[
"name"].AsString().ToStdString());
308 if (branches->Count() > 0) {
309 wxLogMessage(
"First branch: %s", channels[0].c_str());
311 return ServerStatus::OK;
Plugin catalog management: Check for available versions and branches, download as required.
std::vector< std::string > GetChannels()
Get the downloaded list of channels, empty on errors.
ServerStatus LoadChannels(std::ostream *json)
Download channel json data, possibly return error code.
CatalogHandler()
Initiate the handler.
CatalogData DefaultCatalogData()
Data for default version, installed with main opencpn.
std::string GetDefaultUrl()
Get the default URL, with actual channel included.
CatalogData LatestCatalogData()
Data for latest parsed data marked as latest.
std::string LastErrorMsg()
Last error message, free format.
CatalogData UserCatalogData()
Data for user catalog which overrides the default one.
ServerStatus ParseCatalog(const std::string xml, bool latest=false)
Parse XML contents, save as latest data if latest is true.
std::string GetActiveChannel()
Get the branch (a.
void SetCustomUrl(const char *url)
Set a custom url, overrides also channel settings.
ServerStatus DownloadCatalog(std::ostream *stream)
Download the latest catalog to given stream.
void ClearCatalogData()
Invalidate *CatalogData caches.
std::string GetCustomUrl()
Set a custom url, overrides also channel settings.
bool SetActiveChannel(const char *channel)
Set the active channel used when downloading catalog.
Handle downloading of files from remote urls.
bool download(std::ostream *stream)
Download url into stream, return false on errors.
std::string last_error()
Last Curl error message.
Wrapper for global variable, supports notification events when value changes.
void Set(const T &arg)
Set variable value and notify all listeners.
The result from parsing the xml catalog i.
Datatypes and a single method to parse ocpn-plugins.xml XML data.