X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Faddon%2Faddon_manager.cpp;h=43e149012fd1c3d503a26a4900e1343639c4c74e;hb=394aff4351bc13e8118482621926e95328fbea71;hp=acd983fa20071267191a228381c9cfaa5b1d757c;hpb=417d2f8152e495270d3e1dc78be0a573d6bad20b;p=supertux.git diff --git a/src/addon/addon_manager.cpp b/src/addon/addon_manager.cpp index acd983fa2..43e149012 100644 --- a/src/addon/addon_manager.cpp +++ b/src/addon/addon_manager.cpp @@ -48,17 +48,26 @@ MD5 md5_from_file(const std::string& filename) MD5 md5; - unsigned char buffer[1024]; PHYSFS_file* file = PHYSFS_openRead(filename.c_str()); - while (true) + if (!file) { - PHYSFS_sint64 len = PHYSFS_read(file, buffer, 1, sizeof(buffer)); - if (len <= 0) break; - md5.update(buffer, len); + std::ostringstream out; + out << "PHYSFS_openRead() failed: " << PHYSFS_getLastError(); + throw std::runtime_error(out.str()); } - PHYSFS_close(file); + else + { + while (true) + { + unsigned char buffer[1024]; + PHYSFS_sint64 len = PHYSFS_read(file, buffer, 1, sizeof(buffer)); + if (len <= 0) break; + md5.update(buffer, len); + } + PHYSFS_close(file); - return md5; + return md5; + } } bool has_suffix(const std::string& str, const std::string& suffix) @@ -72,30 +81,54 @@ bool has_suffix(const std::string& str, const std::string& suffix) } // namespace AddonManager::AddonManager(const std::string& addon_directory, - std::vector& ignored_addon_ids) : + std::vector& addon_config) : m_downloader(), m_addon_directory(addon_directory), - //m_repository_url("http://addons.supertux.googlecode.com/git/index-0_3_5.nfo"), - m_repository_url("http://localhost:8000/index-0_4_0.nfo"), - m_ignored_addon_ids(ignored_addon_ids), + m_repository_url("http://addons.supertux.googlecode.com/git/index-0_4_0.nfo"), + m_addon_config(addon_config), m_installed_addons(), - m_repository_addons() + m_repository_addons(), + m_has_been_updated(false), + m_transfer_status() { PHYSFS_mkdir(m_addon_directory.c_str()); add_installed_addons(); - for(auto& addon : m_installed_addons) + + // FIXME: We should also restore the order here + for(auto& addon : m_addon_config) { - if (std::find(m_ignored_addon_ids.begin(), m_ignored_addon_ids.end(), - addon->get_id()) != m_ignored_addon_ids.end()) + if (addon.enabled) { - enable_addon(addon->get_id()); + try + { + enable_addon(addon.id); + } + catch(const std::exception& err) + { + log_warning << "failed to enable addon from config: " << err.what() << std::endl; + } } } + + try + { + m_repository_addons = parse_addon_infos("/addons/repository.nfo"); + } + catch(const std::exception& err) + { + log_warning << "parsing repository.nfo failed: " << err.what() << std::endl; + } } AddonManager::~AddonManager() { + // sync enabled/disabled addons into the config for saving + m_addon_config.clear(); + for(auto& addon : m_installed_addons) + { + m_addon_config.push_back({addon->get_id(), addon->is_enabled()}); + } } Addon& @@ -171,11 +204,120 @@ AddonManager::has_online_support() const return true; } +bool +AddonManager::has_been_updated() const +{ + return m_has_been_updated; +} + +TransferStatusPtr +AddonManager::request_check_online() +{ + if (m_transfer_status) + { + throw std::runtime_error("only async request can be made to AddonManager at a time"); + } + else + { + m_transfer_status = m_downloader.request_download(m_repository_url, "/addons/repository.nfo"); + + m_transfer_status->then( + [this](bool success) + { + m_transfer_status = {}; + + if (success) + { + m_repository_addons = parse_addon_infos("/addons/repository.nfo"); + m_has_been_updated = true; + } + }); + + return m_transfer_status; + } +} + void AddonManager::check_online() { - std::string addoninfos = m_downloader.download(m_repository_url); - m_repository_addons = parse_addon_infos(addoninfos); + m_downloader.download(m_repository_url, "/addons/repository.nfo"); + m_repository_addons = parse_addon_infos("/addons/repository.nfo"); + m_has_been_updated = true; +} + +TransferStatusPtr +AddonManager::request_install_addon(const AddonId& addon_id) +{ + if (m_transfer_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& addon = get_repository_addon(addon_id); + + std::string install_filename = FileSystem::join(m_addon_directory, addon.get_filename()); + + m_transfer_status = m_downloader.request_download(addon.get_url(), install_filename); + + m_transfer_status->then( + [this, install_filename, addon_id](bool success) + { + m_transfer_status = {}; + + if (success) + { + // complete the addon install + Addon& repository_addon = get_repository_addon(addon_id); + + MD5 md5 = md5_from_file(install_filename); + if (repository_addon.get_md5() != md5.hex_digest()) + { + if (PHYSFS_delete(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(install_filename.c_str()); + if (!realdir) + { + throw std::runtime_error("PHYSFS_getRealDir failed: " + install_filename); + } + else + { + add_installed_archive(install_filename, md5.hex_digest()); + } + } + } + }); + + return m_transfer_status; + } } void @@ -206,7 +348,7 @@ AddonManager::install_addon(const AddonId& addon_id) std::string install_filename = FileSystem::join(m_addon_directory, repository_addon.get_filename()); - m_downloader.download(repository_addon.get_http_url(), install_filename); + m_downloader.download(repository_addon.get_url(), install_filename); MD5 md5 = md5_from_file(install_filename); if (repository_addon.get_md5() != md5.hex_digest()) @@ -332,7 +474,6 @@ AddonManager::scan_for_info(const std::string& archive_os_path) const PHYSFS_freeList); for(char** j = rc2.get(); *j != 0; ++j) { - log_debug << "enumerating: " << std::string(*j) << std::endl; if (has_suffix(*j, ".nfo")) { std::string nfo_filename = FileSystem::join("/", *j); @@ -345,7 +486,6 @@ AddonManager::scan_for_info(const std::string& archive_os_path) const } else { - log_debug << "compare: " << realdir << " " << archive_os_path << std::endl; if (realdir == archive_os_path) { return nfo_filename; @@ -409,15 +549,14 @@ AddonManager::add_installed_addons() } AddonManager::AddonList -AddonManager::parse_addon_infos(const std::string& addoninfos) const +AddonManager::parse_addon_infos(const std::string& filename) const { AddonList m_addons; try { lisp::Parser parser; - std::stringstream addoninfos_stream(addoninfos); - const lisp::Lisp* root = parser.parse(addoninfos_stream, "supertux-addons"); + const lisp::Lisp* root = parser.parse(filename); const lisp::Lisp* addons_lisp = root->get_lisp("supertux-addons"); if(!addons_lisp) { @@ -453,4 +592,10 @@ AddonManager::parse_addon_infos(const std::string& addoninfos) const return m_addons; } +void +AddonManager::update() +{ + m_downloader.update(); +} + /* EOF */