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)
+ {
+ 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)
} // namespace
AddonManager::AddonManager(const std::string& addon_directory,
- std::vector<std::string>& ignored_addon_ids) :
+ std::vector<Config::Addon>& 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_install_request(),
+ m_install_status(),
+ 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;
+ }
}
}
}
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&
return true;
}
+bool
+AddonManager::has_been_updated() const
+{
+ return m_has_been_updated;
+}
+
void
AddonManager::check_online()
{
std::string addoninfos = m_downloader.download(m_repository_url);
m_repository_addons = parse_addon_infos(addoninfos);
+ 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>& 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<InstallRequest>();
+ 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_transfer_status->then(
+ [this]
+ {
+ // complete the addon install
+ 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());
+ }
+ }
+
+ // signal that the request is done and cleanup
+ if (m_install_status->callback)
+ {
+ m_install_status->callback();
+ }
+
+ m_install_request = {};
+ m_install_status = {};
+ m_transfer_status = {};
+ });
+
+ m_install_status = std::make_shared<InstallStatus>();
+
+ return m_install_status;
+ }
}
void
AddonManager::install_addon(const AddonId& addon_id)
{
- log_debug << "installing addon " << addon_id << std::endl;
+ { // 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>& 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);
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())
}
else
{
- add_installed_archive(install_filename);
+ add_installed_archive(install_filename, md5.hex_digest());
}
}
}
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);
}
else
{
- log_debug << "compare: " << realdir << " " << archive_os_path << std::endl;
if (realdir == archive_os_path)
{
return nfo_filename;
}
void
-AddonManager::add_installed_archive(const std::string& archive)
+AddonManager::add_installed_archive(const std::string& archive, const std::string& md5)
{
const char* realdir = PHYSFS_getRealDir(archive.c_str());
if (!realdir)
try
{
std::unique_ptr<Addon> addon = Addon::parse(nfo_filename);
- addon->set_install_filename(os_path);
+ addon->set_install_filename(os_path, md5);
m_installed_addons.push_back(std::move(addon));
}
catch (const std::runtime_error& e)
for(auto archive : archives)
{
- add_installed_archive(archive);
+ MD5 md5 = md5_from_file(archive);
+ add_installed_archive(archive, md5.hex_digest());
}
}
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;
+ }
+}
+
+void
+AddonManager::abort_install()
+{
+ log_info << "addon install aborted" << std::endl;
+
+ m_downloader.abort(m_transfer_status->id);
+
+ m_install_request = {};
+ m_install_status = {};
+ m_transfer_status = {};
+}
+
/* EOF */