OpenCPN Partial API docs
Loading...
Searching...
No Matches
download_mgr.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2019 Alec Leamas *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
24#include "gl_headers.h" // Must come before anything including GL stuff
25
26#include "config.h"
27#include "download_mgr.h"
28
29#include <fstream>
30#include <set>
31#include <sstream>
32
33#include <wx/bitmap.h>
34#include <wx/button.h>
35#include <wx/debug.h>
36#include <wx/file.h>
37#include <wx/image.h>
38#include <wx/log.h>
39#include <wx/panel.h>
40#include <wx/progdlg.h>
41#include <wx/sizer.h>
42#include <wx/statline.h>
43#include <wx/uri.h>
44
45#include "libgui/expand_icon.h"
46
47#include "model/downloader.h"
48#include "model/plugin_cache.h"
50#include "model/semantic_vers.h"
51#include "model/svg_utils.h"
52
53#include "catalog_mgr.h"
54#include "ocpn_platform.h"
55#include "picosha2.h"
56#include "pluginmanager.h"
57#include "styles.h"
58
59#undef major // Work around gnu's major() and minor() macros.
60#undef minor
61
62// Main window reload event
63wxDEFINE_EVENT(EVT_PLUGINS_RELOAD, wxCommandEvent);
64
68static bool checksum_ok(const std::string& path,
69 const PluginMetadata& metadata) {
70 wxLogDebug("Checksum test on %s", metadata.name.c_str());
71 if (metadata.checksum == "") {
72 wxLogDebug("No metadata checksum, aborting check,");
73 return true;
74 }
75 const size_t pos = metadata.checksum.find(':');
76 std::string checksum(metadata.checksum);
77 if (pos == std::string::npos) {
78 checksum = std::string("sha256:") + checksum;
79 }
80 std::ifstream f(path, std::ios::binary);
81 picosha2::hash256_one_by_one hasher;
82 while (!f.eof()) {
83 char buff[2048];
84 f.read(buff, sizeof(buff));
85 const std::string block(buff, f.gcount());
86 hasher.process(block.begin(), block.end());
87 }
88 hasher.finish();
89 std::string tarball_hash =
90 std::string("sha256:") + picosha2::get_hash_hex_string(hasher);
91
92 if (tarball_hash == checksum) {
93 wxLogDebug("Checksum ok: %s", tarball_hash.c_str());
94 return true;
95 }
96 wxLogMessage("Checksum fail on %s, tarball: %s, metadata: %s",
97 metadata.name.c_str(), tarball_hash.c_str(), checksum.c_str());
98 return false;
99}
100
105static ssize_t PlugInIxByName(const std::string name,
106 const ArrayOfPlugIns* plugins) {
107 for (unsigned i = 0; i < plugins->GetCount(); i += 1) {
108 if (name == plugins->Item(i)->m_common_name.Lower().ToStdString()) {
109 return i;
110 }
111 }
112 return -1;
113}
114
117 : Downloader(plugin.tarball_url),
118 m_downloaded(0),
119 m_dialog(0),
120 m_plugin(plugin),
121 m_parent(parent) {}
122
123std::string GuiDownloader::run(wxWindow* parent, bool remove_current) {
124 bool ok;
125 bool downloaded = false;
126 std::string path = ocpn::lookup_tarball(m_plugin.tarball_url.c_str());
127 if (!path.size()) {
128 long size = get_filesize();
129 std::string label(_("Downloading "));
130 label += url;
131 m_dialog =
132 new wxProgressDialog(_("Downloading"), label.c_str(), size, parent,
133 wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
134#ifdef __ANDROID__
135 m_dialog->SetBackgroundColour(wxColour(0x7c, 0xb0, 0xe9)); // light blue
136#endif
137 ok = download(path);
138 g_Platform->HideBusySpinner();
139
140 if (!ok) {
141 delete m_dialog;
142 showErrorDialog("Download error");
143 return "";
144 }
145
146 // Download aborted?
147 if (m_dialog == 0) {
148 showErrorDialog("Download aborted");
149 return "";
150 } else {
151 delete m_dialog;
152 }
153 if (!checksum_ok(path, m_plugin)) {
154 showErrorDialog("Checksum error");
155 return "";
156 }
157 m_dialog = 0; // make sure that on_chunk() doesn't misbehave.
158 downloaded = true;
159 }
160
161 auto pluginHandler = PluginHandler::GetInstance();
162 if (remove_current) {
163 wxLogMessage("Uninstalling %s", m_plugin.name.c_str());
164 pluginHandler->Uninstall(m_plugin.name);
165 }
166 ok = pluginHandler->InstallPlugin(m_plugin, path);
167 if (!ok) {
168 showErrorDialog("Installation error");
169 return "";
170 }
171
172 if (downloaded) {
173 // Cache the tarball from the tmp location to the plugin cache.
174 wxURI uri(wxString(m_plugin.tarball_url.c_str()));
175 wxFileName fn(uri.GetPath());
176 auto basename = fn.GetFullName().ToStdString();
177 if (ocpn::store_tarball(path.c_str(), basename.c_str())) {
178 wxLogMessage("Copied %s to local cache at %s", path.c_str(),
179 basename.c_str());
180 }
181 }
182
183 wxMessageDialog* dlg = new wxMessageDialog(
184 m_parent,
185 m_plugin.name + " " + m_plugin.version + _(" successfully installed"),
186 _("Installation complete"), wxOK | wxCENTRE | wxICON_INFORMATION);
187 dlg->ShowModal();
188 return path;
189}
190
191void GuiDownloader::on_chunk(const char* buff, unsigned bytes) {
192 Downloader::on_chunk(buff, bytes);
193 m_downloaded += bytes;
194 if (m_dialog && !m_dialog->Update(m_downloaded)) {
195 // User pushed Cancel button
196 delete m_dialog;
197 m_dialog = 0;
198 }
199}
200
201void GuiDownloader::showErrorDialog(const char* msg) {
202 auto dlg = new wxMessageDialog(m_parent, "", _("Installation error"),
203 wxOK | wxICON_ERROR);
204 auto last_error_msg = last_error();
205 std::string text = msg;
206 if (last_error_msg != "") {
207 text = text + ": " + error_msg;
208 }
209 text = text + "\nPlease check system log for more info.";
210 dlg->SetMessage(text);
211 dlg->ShowModal();
212 dlg->Destroy();
213}
Catalog options dialog, by default disabled.
Default downloader, usable in a CLI context.
Definition downloader.h:35
bool download(std::ostream *stream)
Download url into stream, return false on errors.
long get_filesize()
Try to get remote filesize, return 0 on failure.
std::string last_error()
Last Curl error message.
virtual void on_chunk(const char *buff, unsigned bytes)
Called when given bytes has been transferred from remote.
void on_chunk(const char *buff, unsigned bytes) override
Called when given bytes has been transferred from remote.
GuiDownloader(wxWindow *parent, PluginMetadata plugin)
Add progress and final message dialogs to the basic Downloader.
static PluginHandler * GetInstance()
Singleton factory.
Generic GUI downloads tool.
Handle downloading of files from remote urls.
Platform independent GL includes.
std::string lookup_tarball(const char *uri)
Get path to tarball in cache for given filename.
bool store_tarball(const char *path, const char *basename)
Store a tarball in tarball cache, return success/fail.
OpenCPN Platform specific support utilities.
Downloaded plugins cache.
Plugin remote repositories installation and Uninstall/list operations.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Semantic version encode/decode object.
Plugin metadata, reflects the xml format directly.
Runtime representation of a plugin block.
Chart Symbols.
SVG utilities.