From: Ingo Ruhnke Date: Tue, 26 Aug 2014 04:22:13 +0000 (+0200) Subject: Added some async code to AddonManager X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=9a5a375c953da2f1c19f52f41c65aeac4c0f4158;p=supertux.git Added some async code to AddonManager --- diff --git a/src/addon/addon_manager.cpp b/src/addon/addon_manager.cpp index ab56662e8..866509302 100644 --- a/src/addon/addon_manager.cpp +++ b/src/addon/addon_manager.cpp @@ -79,7 +79,10 @@ AddonManager::AddonManager(const std::string& addon_directory, m_addon_config(addon_config), m_installed_addons(), m_repository_addons(), - m_has_been_updated(false) + m_has_been_updated(false), + m_install_request(), + m_install_status(), + m_transfer_status() { PHYSFS_mkdir(m_addon_directory.c_str()); @@ -199,6 +202,51 @@ AddonManager::check_online() m_has_been_updated = true; } +AddonManager::InstallStatusPtr +AddonManager::request_install_addon(const AddonId& addon_id) +{ + if (m_install_status) + { + throw std::runtime_error("only one addon install request allowed at a time"); + } + else + { + { // remove addon if it already exists + auto it = std::find_if(m_installed_addons.begin(), m_installed_addons.end(), + [&addon_id](const std::unique_ptr& addon) + { + return addon->get_id() == addon_id; + }); + if (it != m_installed_addons.end()) + { + log_debug << "reinstalling addon " << addon_id << std::endl; + if ((*it)->is_enabled()) + { + disable_addon((*it)->get_id()); + } + m_installed_addons.erase(it); + } + else + { + log_debug << "installing addon " << addon_id << std::endl; + } + } + + Addon& repository_addon = get_repository_addon(addon_id); + + m_install_request = std::make_shared(); + m_install_request->install_filename = FileSystem::join(m_addon_directory, repository_addon.get_filename()); + m_install_request->addon_id = addon_id; + + m_transfer_status = m_downloader.request_download(repository_addon.get_url(), + m_install_request->install_filename); + + m_install_status = std::make_shared(); + + return m_install_status; + } +} + void AddonManager::install_addon(const AddonId& addon_id) { @@ -472,4 +520,55 @@ AddonManager::parse_addon_infos(const std::string& addoninfos) const return m_addons; } +void +AddonManager::update() +{ + m_downloader.update(); + + if (m_install_status) + { + m_install_status->now = m_transfer_status->dlnow; + m_install_status->total = m_transfer_status->dltotal; + + if (m_transfer_status->status != TransferStatus::RUNNING) + { + if (m_transfer_status->status != TransferStatus::COMPLETED) + { + log_warning << "Some error" << std::endl; + } + else + { + Addon& repository_addon = get_repository_addon(m_install_request->addon_id); + + MD5 md5 = md5_from_file(m_install_request->install_filename); + if (repository_addon.get_md5() != md5.hex_digest()) + { + if (PHYSFS_delete(m_install_request->install_filename.c_str()) == 0) + { + log_warning << "PHYSFS_delete failed: " << PHYSFS_getLastError() << std::endl; + } + + throw std::runtime_error("Downloading Add-on failed: MD5 checksums differ"); + } + else + { + const char* realdir = PHYSFS_getRealDir(m_install_request->install_filename.c_str()); + if (!realdir) + { + throw std::runtime_error("PHYSFS_getRealDir failed: " + m_install_request->install_filename); + } + else + { + add_installed_archive(m_install_request->install_filename, md5.hex_digest()); + } + } + } + + m_install_request = {}; + m_install_status = {}; + m_transfer_status = {}; + } + } +} + /* EOF */ diff --git a/src/addon/addon_manager.hpp b/src/addon/addon_manager.hpp index b87d7ce28..c5e65f8f9 100644 --- a/src/addon/addon_manager.hpp +++ b/src/addon/addon_manager.hpp @@ -36,8 +36,36 @@ typedef std::string AddonId; /** Checks for, installs and removes Add-ons */ class AddonManager : public Currenton { +public: + struct InstallStatus + { + InstallStatus() : + now(0), + total(0), + done(false) + {} + + int now; + int total; + bool done; + }; + + struct InstallRequest + { + InstallRequest() : + addon_id(), + install_filename() + {} + + std::string addon_id; + std::string install_filename; + }; + + using InstallStatusPtr = std::shared_ptr; + using InstallRequestPtr = std::shared_ptr; + private: - typedef std::vector > AddonList; + using AddonList = std::vector >; Downloader m_downloader; std::string m_addon_directory; @@ -49,6 +77,10 @@ private: bool m_has_been_updated; + InstallRequestPtr m_install_request; + InstallStatusPtr m_install_status; + TransferStatusPtr m_transfer_status; + public: AddonManager(const std::string& addon_directory, std::vector& addon_config); @@ -64,12 +96,15 @@ public: Addon& get_repository_addon(const AddonId& addon); Addon& get_installed_addon(const AddonId& addon); + InstallStatusPtr request_install_addon(const AddonId& addon_id); void install_addon(const AddonId& addon_id); void uninstall_addon(const AddonId& addon_id); void enable_addon(const AddonId& addon_id); void disable_addon(const AddonId& addon_id); + void update(); + private: std::vector scan_for_archives() const; void add_installed_addons(); diff --git a/src/addon/downloader.hpp b/src/addon/downloader.hpp index 28f2313c4..814c4a2bb 100644 --- a/src/addon/downloader.hpp +++ b/src/addon/downloader.hpp @@ -30,7 +30,11 @@ typedef int TransferId; class TransferStatus { public: + enum Status { RUNNING, COMPLETED, ABORT, ERROR }; + +public: TransferId id; + Status status; int dltotal; int dlnow; int ultotal; @@ -38,6 +42,7 @@ public: TransferStatus(TransferId id_) : id(id_), + status(RUNNING), dltotal(0), dlnow(0), ultotal(0), @@ -51,8 +56,6 @@ class Transfer; class Downloader { -public: - private: CURLM* m_multi_handle; std::vector > m_transfers;