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