From 7dbb2ed6a3f97b585ed7341a9199bfd40627da6b Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 13 Apr 2018 15:08:58 +0200 Subject: [PATCH] Configuration updates downloading --- lib/Slic3r/GUI.pm | 5 +- resources/profiles/PrusaResearch.idx | 3 - resources/profiles/PrusaResearch.ini | 3 +- xs/src/libslic3r/utils.cpp | 2 +- xs/src/slic3r/Config/Version.cpp | 4 +- xs/src/slic3r/GUI/AppConfig.cpp | 6 +- xs/src/slic3r/GUI/ConfigSnapshotDialog.cpp | 3 - xs/src/slic3r/GUI/ConfigWizard.cpp | 3 +- xs/src/slic3r/GUI/ConfigWizard_private.hpp | 6 +- xs/src/slic3r/Utils/PresetUpdater.cpp | 224 ++++++++++++--------- xs/src/slic3r/Utils/PresetUpdater.hpp | 4 +- xs/xsp/Utils_PresetUpdater.xsp | 4 +- 12 files changed, 148 insertions(+), 119 deletions(-) diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index b592c4289..40cfcad89 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -103,7 +103,7 @@ sub OnInit { # my $version_check = $self->{app_config}->get('version_check'); $self->{preset_updater} = Slic3r::PresetUpdater->new($VERSION_ONLINE_EVENT, $self->{app_config}); - eval { $self->{preset_updater}->config_update() }; + eval { $self->{preset_updater}->config_update($self->{app_config}) }; if ($@) { warn $@ . "\n"; fatal_error(undef, $@); @@ -158,7 +158,8 @@ sub OnInit { Slic3r::GUI::config_wizard(1); } - # $self->{preset_updater}->download($self->{preset_bundle}); + # TODO: call periodically? + $self->{preset_updater}->sync($self->{app_config}, $self->{preset_bundle}); }); # The following event is emited by the C++ menu implementation of application language change. diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index 28f17f10a..837bc7bac 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,8 +1,5 @@ # This is an example configuration version index. # The index contains version numbers -min_slic3r_version =1.39.0 -0.2.0-alpha "some test comment" -max_slic3r_version= 1.39.4 0.1.0 another test comment # some empty lines diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index cf82855cf..0ca094880 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -8,8 +8,7 @@ name = Prusa Research config_version = 0.1.0 # Where to get the updates from? # TODO: proper URL -# config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch.ini -config_update_url = https://gist.githubusercontent.com/vojtechkral/4d8fd4a3b8699a01ec892c264178461c/raw/e9187c3e15ceaf1a90f29b7c43cf3ccc746140f0/PrusaResearch.ini +config_update_url = https://raw.githubusercontent.com/vojtechkral/slic3r-settings-tmp/master/PrusaResearch # The printer models will be shown by the Configuration Wizard in this order, # also the first model installed & the first nozzle installed will be activated after install. diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp index 703d5ff66..733757e25 100644 --- a/xs/src/libslic3r/utils.cpp +++ b/xs/src/libslic3r/utils.cpp @@ -119,7 +119,7 @@ static std::string g_data_dir; void set_data_dir(const std::string &dir) { - g_data_dir = dir + "-alpha"; // FIXME: Resolve backcompat problems + g_data_dir = dir; } const std::string& data_dir() diff --git a/xs/src/slic3r/Config/Version.cpp b/xs/src/slic3r/Config/Version.cpp index 5430e569c..b1abc5c63 100644 --- a/xs/src/slic3r/Config/Version.cpp +++ b/xs/src/slic3r/Config/Version.cpp @@ -153,10 +153,10 @@ Index::const_iterator Index::find(const Semver &ver) const Index::const_iterator Index::recommended() const { int idx = -1; - const_iterator highest = m_configs.end(); + const_iterator highest = this->end(); for (const_iterator it = this->begin(); it != this->end(); ++ it) if (it->is_current_slic3r_supported() && - (highest == this->end() || highest->max_slic3r_version < it->max_slic3r_version)) + (highest == this->end() || highest->config_version < it->config_version)) highest = it; return highest; } diff --git a/xs/src/slic3r/GUI/AppConfig.cpp b/xs/src/slic3r/GUI/AppConfig.cpp index ee77f877a..d0f2f1019 100644 --- a/xs/src/slic3r/GUI/AppConfig.cpp +++ b/xs/src/slic3r/GUI/AppConfig.cpp @@ -46,11 +46,15 @@ void AppConfig::set_defaults() set("no_defaults", "1"); if (get("show_incompatible_presets").empty()) set("show_incompatible_presets", "0"); - // Version check is enabled by default in the config, but it is not implemented yet. // XXX + if (get("version_check").empty()) set("version_check", "1"); + // TODO: proper URL + if (get("version_check_url").empty()) + set("version_check_url", "https://gist.githubusercontent.com/vojtechkral/4d8fd4a3b8699a01ec892c264178461c/raw/e9187c3e15ceaf1a90f29b7c43cf3ccc746140f0/slic3rPE.version"); if (get("preset_update").empty()) set("preset_update", "1"); + // Use OpenGL 1.1 even if OpenGL 2.0 is available. This is mainly to support some buggy Intel HD Graphics drivers. // https://github.com/prusa3d/Slic3r/issues/233 if (get("use_legacy_opengl").empty()) diff --git a/xs/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/xs/src/slic3r/GUI/ConfigSnapshotDialog.cpp index 730b97a32..8739b8fa2 100644 --- a/xs/src/slic3r/GUI/ConfigSnapshotDialog.cpp +++ b/xs/src/slic3r/GUI/ConfigSnapshotDialog.cpp @@ -86,9 +86,6 @@ ConfigSnapshotDialog::ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); html->SetBorders(2); std::string text = generate_html_page(snapshot_db); - FILE *file = ::fopen("d:\\temp\\configsnapshotdialog.html", "wt"); - fwrite(text.data(), 1, text.size(), file); - fclose(file); html->SetPage(text.c_str()); vsizer->Add(html, 1, wxEXPAND | wxALIGN_LEFT | wxRIGHT | wxBOTTOM, 0); html->Bind(wxEVT_HTML_LINK_CLICKED, &ConfigSnapshotDialog::onLinkClicked, this); diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index f353ab7f7..5b49fc025 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -660,7 +660,8 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese app_config->set_vendors(appconfig_vendors); app_config->set("version_check", page_update->version_check ? "1" : "0"); app_config->set("preset_update", page_update->preset_update ? "1" : "0"); - app_config->reset_selections(); // XXX: only on "fresh start"? + app_config->reset_selections(); + // ^ TODO: replace with appropriate printer selection preset_bundle->load_presets(*app_config); } else { for (ConfigWizardPage *page = page_firmware; page != nullptr; page = page->page_next()) { diff --git a/xs/src/slic3r/GUI/ConfigWizard_private.hpp b/xs/src/slic3r/GUI/ConfigWizard_private.hpp index 137b276b8..c93e0a80d 100644 --- a/xs/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/xs/src/slic3r/GUI/ConfigWizard_private.hpp @@ -17,7 +17,6 @@ #include "libslic3r/PrintConfig.hpp" #include "AppConfig.hpp" #include "Preset.hpp" -// #include "PresetBundle.hpp" #include "BedShapeDialog.hpp" namespace fs = boost::filesystem; @@ -173,9 +172,8 @@ private: struct ConfigWizard::priv { ConfigWizard *q; - AppConfig appconfig_vendors; - // PresetBundle bundle_vendors; - std::unordered_map vendors; + AppConfig appconfig_vendors; // TODO: use order-preserving container + std::unordered_map vendors; // TODO: just set? std::unordered_map vendors_rsrc; std::unique_ptr custom_config; diff --git a/xs/src/slic3r/Utils/PresetUpdater.cpp b/xs/src/slic3r/Utils/PresetUpdater.cpp index 28b977321..257c7f552 100644 --- a/xs/src/slic3r/Utils/PresetUpdater.cpp +++ b/xs/src/slic3r/Utils/PresetUpdater.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include @@ -25,19 +27,17 @@ using Slic3r::GUI::Config::Version; using Slic3r::GUI::Config::Snapshot; using Slic3r::GUI::Config::SnapshotDB; -// XXX: Prevent incomplete file downloads: download a tmp file, then move -// Delete incomplete ones on startup. namespace Slic3r { -// TODO: proper URL -// TODO: Actually, use index -static const std::string SLIC3R_VERSION_URL = "https://gist.githubusercontent.com/vojtechkral/4d8fd4a3b8699a01ec892c264178461c/raw/e9187c3e15ceaf1a90f29b7c43cf3ccc746140f0/slic3rPE.version"; enum { SLIC3R_VERSION_BODY_MAX = 256, }; +static const char *INDEX_FILENAME = "index.idx"; +static const char *TMP_EXTENSION = ".download"; + struct Update { @@ -45,7 +45,7 @@ struct Update fs::path target; Version version; - Update(const fs::path &source, fs::path &&target, const Version &version) : + Update(fs::path &&source, const fs::path &target, const Version &version) : source(source), target(std::move(target)), version(version) @@ -60,9 +60,11 @@ typedef std::vector Updates; struct PresetUpdater::priv { int version_online_event; - AppConfig *app_config; - bool version_check; - bool preset_update; + std::vector index_db; + + bool enabled_version_check; + bool enabled_config_update; + std::string version_check_url; fs::path cache_path; fs::path rsrc_path; @@ -73,7 +75,11 @@ struct PresetUpdater::priv priv(int event, AppConfig *app_config); - void download(const std::set vendors) const; + void set_download_prefs(AppConfig *app_config); + bool get_file(const std::string &url, const fs::path &target_path) const; + void prune_tmps() const; + void sync_version() const; + void sync_config(const std::set vendors) const; void check_install_indices() const; Updates config_update() const; @@ -81,21 +87,62 @@ struct PresetUpdater::priv PresetUpdater::priv::priv(int event, AppConfig *app_config) : version_online_event(event), - app_config(app_config), - version_check(false), - preset_update(false), cache_path(fs::path(Slic3r::data_dir()) / "cache"), rsrc_path(fs::path(resources_dir()) / "profiles"), vendor_path(fs::path(Slic3r::data_dir()) / "vendor"), cancel(false) -{} - -void PresetUpdater::priv::download(const std::set vendors) const { - if (!version_check) { return; } + set_download_prefs(app_config); + check_install_indices(); + index_db = std::move(Index::load_db()); +} - // Download current Slic3r version - Http::get(SLIC3R_VERSION_URL) +void PresetUpdater::priv::set_download_prefs(AppConfig *app_config) +{ + enabled_version_check = app_config->get("version_check") == "1"; + version_check_url = app_config->get("version_check_url"); + enabled_config_update = app_config->get("preset_update") == "1"; +} + +bool PresetUpdater::priv::get_file(const std::string &url, const fs::path &target_path) const +{ + std::cerr << "get_file(): " << url << " -> " << target_path << std::endl; + + // TODO: Proper caching + + bool res = false; + fs::path tmp_path = target_path; + tmp_path += TMP_EXTENSION; + + Http::get(url) + .on_progress([this](Http::Progress, bool &cancel) { + if (cancel) { cancel = true; } + }) + .on_complete([&](std::string body, unsigned http_status) { + fs::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc); + file.write(body.c_str(), body.size()); + fs::rename(tmp_path, target_path); + res = true; + }) + .perform_sync(); + + return res; +} + +void PresetUpdater::priv::prune_tmps() const +{ + for (fs::directory_iterator it(cache_path); it != fs::directory_iterator(); ++it) { + if (it->path().extension() == TMP_EXTENSION) { + fs::remove(it->path()); + } + } +} + +void PresetUpdater::priv::sync_version() const +{ + if (! enabled_version_check) { return; } + + Http::get(version_check_url) .size_limit(SLIC3R_VERSION_BODY_MAX) .on_progress([this](Http::Progress, bool &cancel) { cancel = this->cancel; @@ -107,27 +154,55 @@ void PresetUpdater::priv::download(const std::set vendors) const GUI::get_app()->QueueEvent(evt); }) .perform_sync(); +} - if (!preset_update) { return; } +void PresetUpdater::priv::sync_config(const std::set vendors) const +{ + std::cerr << "sync_config()" << std::endl; + + if (!enabled_config_update) { return; } // Donwload vendor preset bundles - for (const auto &vendor : vendors) { + for (const auto &index : index_db) { if (cancel) { return; } - // TODO: Proper caching + std::cerr << "Index: " << index.vendor() << std::endl; - auto target_path = cache_path / vendor.id; - target_path += ".ini"; + const auto vendor_it = vendors.find(VendorProfile(index.vendor())); + if (vendor_it == vendors.end()) { continue; } - Http::get(vendor.config_update_url) - .on_progress([this](Http::Progress, bool &cancel) { - cancel = this->cancel; - }) - .on_complete([&](std::string body, unsigned http_status) { - fs::fstream file(target_path, std::ios::out | std::ios::binary | std::ios::trunc); - file.write(body.c_str(), body.size()); - }) - .perform_sync(); + const VendorProfile &vendor = *vendor_it; + if (vendor.config_update_url.empty()) { continue; } + + // Download a fresh index + const auto idx_url = vendor.config_update_url + "/" + INDEX_FILENAME; + const auto idx_path = cache_path / (vendor.id + ".idx"); + if (! get_file(idx_url, idx_path)) { continue; } + if (cancel) { return; } + + std::cerr << "Got a new index: " << idx_path << std::endl; + + // Load the fresh index up + Index new_index; + new_index.load(idx_path); + + // See if a there's a new version to download + const auto recommended_it = new_index.recommended(); + if (recommended_it == new_index.end()) { continue; } + const auto recommended = recommended_it->config_version; + + std::cerr << "Current vendor version: " << vendor.config_version.to_string() << std::endl; + std::cerr << "Recommended version:\t" << recommended.to_string() << std::endl; + + if (vendor.config_version >= recommended) { continue; } + + // Download a fresh bundle + const auto bundle_url = (boost::format("%1%/%2%.ini") % vendor.config_update_url % recommended.to_string()).str(); + const auto bundle_path = cache_path / (vendor.id + ".ini"); + if (! get_file(bundle_url, bundle_path)) { continue; } + if (cancel) { return; } + + std::cerr << "Got a new bundle: " << bundle_path << std::endl; } } @@ -148,35 +223,11 @@ void PresetUpdater::priv::check_install_indices() const Updates PresetUpdater::priv::config_update() const { - priv::check_install_indices(); - const auto index_db = Index::load_db(); // TODO: Keep in Snapshots singleton? - Updates updates; for (const auto idx : index_db) { const auto bundle_path = vendor_path / (idx.vendor() + ".ini"); - // If the bundle doesn't exist at all, update from resources - // if (! fs::exists(bundle_path)) { - // auto path_in_rsrc = rsrc_path / (idx.vendor() + ".ini"); - - // // Otherwise load it and check for chached updates - // const auto rsrc_vp = VendorProfile::from_ini(path_in_rsrc, false); - - // const auto rsrc_ver = idx.find(rsrc_vp.config_version); - // if (rsrc_ver == idx.end()) { - // // TODO: throw - // } - - // if (fs::exists(path_in_rsrc)) { - // updates.emplace_back(bundle_path, std::move(path_in_rsrc), *rsrc_ver); - // } else { - // // XXX: ??? - // } - - // continue; - // } - if (! fs::exists(bundle_path)) { continue; } @@ -186,12 +237,12 @@ Updates PresetUpdater::priv::config_update() const const auto ver_current = idx.find(vp.config_version); if (ver_current == idx.end()) { - // TODO: throw + // TODO: throw / ignore ? } const auto recommended = idx.recommended(); if (recommended == idx.end()) { - // TODO: throw + throw std::runtime_error((boost::format("Invalid index: `%1%`") % idx.vendor()).str()); } if (! ver_current->is_current_slic3r_supported()) { @@ -202,50 +253,26 @@ Updates PresetUpdater::priv::config_update() const // Config bundle update situation auto path_in_cache = cache_path / (idx.vendor() + ".ini"); + if (! fs::exists(path_in_cache)) { + continue; + } + const auto cached_vp = VendorProfile::from_ini(path_in_cache, false); if (cached_vp.config_version == recommended->config_version) { - updates.emplace_back(bundle_path, std::move(path_in_cache), *ver_current); + updates.emplace_back(std::move(path_in_cache), bundle_path, *recommended); } else { - // XXX: ??? + // XXX: ? } } } - // Check for bundles that don't have an index - // for (fs::directory_iterator it(rsrc_path); it != fs::directory_iterator(); ++it) { - // if (it->path().extension() == ".ini") { - // const auto &path = it->path(); - // const auto vendor_id = path.stem().string(); - - // const auto needle = std::find_if(index_db.begin(), index_db.end(), [&vendor_id](const Index &idx) { - // return idx.vendor() == vendor_id; - // }); - // if (needle != index_db.end()) { - // continue; - // } - - // auto vp = VendorProfile::from_ini(path, false); - // auto path_in_data = vendor_path / path.filename(); - - // if (! fs::exists(path_in_data)) { - // Version version; - // version.config_version = vp.config_version; - // updates.emplace_back(path, std::move(path_in_data), version); - // } - // } - // } - return updates; } PresetUpdater::PresetUpdater(int version_online_event, AppConfig *app_config) : p(new priv(version_online_event, app_config)) -{ - p->preset_update = app_config->get("preset_update") == "1"; - // preset_update implies version_check: // XXX: not any more - p->version_check = p->preset_update || app_config->get("version_check") == "1"; -} +{} // Public @@ -258,8 +285,10 @@ PresetUpdater::~PresetUpdater() } } -void PresetUpdater::download(PresetBundle *preset_bundle) +void PresetUpdater::sync(AppConfig *app_config, PresetBundle *preset_bundle) { + p->set_download_prefs(app_config); + if (!p->enabled_version_check && !p->enabled_config_update) { return; } // Copy the whole vendors data for use in the background thread // Unfortunatelly as of C++11, it needs to be copied again @@ -267,12 +296,16 @@ void PresetUpdater::download(PresetBundle *preset_bundle) std::set vendors = preset_bundle->vendors; p->thread = std::move(std::thread([this, vendors]() { - this->p->download(std::move(vendors)); + this->p->prune_tmps(); + this->p->sync_version(); + this->p->sync_config(std::move(vendors)); })); } -void PresetUpdater::config_update() +void PresetUpdater::config_update(AppConfig *app_config) { + if (! p->enabled_config_update) { return; } + const auto updates = p->config_update(); if (updates.size() > 0) { const auto msg = _(L("Configuration update is available. Would you like to install it?")); @@ -298,12 +331,11 @@ void PresetUpdater::config_update() if (res == wxID_YES) { // User gave clearance, updates are go - // TODO: Comment? - SnapshotDB::singleton().take_snapshot(*p->app_config, Snapshot::SNAPSHOT_UPGRADE, ""); + SnapshotDB::singleton().take_snapshot(*app_config, Snapshot::SNAPSHOT_UPGRADE, ""); for (const auto &update : updates) { fs::copy_file(update.source, update.target, fs::copy_option::overwrite_if_exists); - + PresetBundle bundle; bundle.load_configbundle(update.target.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); diff --git a/xs/src/slic3r/Utils/PresetUpdater.hpp b/xs/src/slic3r/Utils/PresetUpdater.hpp index 8fd6e4528..966dd1464 100644 --- a/xs/src/slic3r/Utils/PresetUpdater.hpp +++ b/xs/src/slic3r/Utils/PresetUpdater.hpp @@ -19,9 +19,9 @@ public: PresetUpdater &operator=(const PresetUpdater &) = delete; ~PresetUpdater(); - void download(PresetBundle *preset_bundle); // XXX + void sync(AppConfig *app_config, PresetBundle *preset_bundle); - void config_update(); + void config_update(AppConfig *app_config); private: struct priv; std::unique_ptr p; diff --git a/xs/xsp/Utils_PresetUpdater.xsp b/xs/xsp/Utils_PresetUpdater.xsp index 4c1a637e4..3a4d55a01 100644 --- a/xs/xsp/Utils_PresetUpdater.xsp +++ b/xs/xsp/Utils_PresetUpdater.xsp @@ -7,6 +7,6 @@ %name{Slic3r::PresetUpdater} class PresetUpdater { PresetUpdater(int version_online_event, AppConfig *app_config); - void download(PresetBundle* preset_bundle); - void config_update(); + void sync(AppConfig *app_config, PresetBundle* preset_bundle); + void config_update(AppConfig *app_config); };