Added some async code to AddonManager
authorIngo Ruhnke <grumbel@gmail.com>
Tue, 26 Aug 2014 04:22:13 +0000 (06:22 +0200)
committerIngo Ruhnke <grumbel@gmail.com>
Tue, 26 Aug 2014 22:57:44 +0000 (00:57 +0200)
src/addon/addon_manager.cpp
src/addon/addon_manager.hpp
src/addon/downloader.hpp

index ab56662..8665093 100644 (file)
@@ -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>& 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_install_status = std::make_shared<InstallStatus>();
+
+    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 */
index b87d7ce..c5e65f8 100644 (file)
@@ -36,8 +36,36 @@ typedef std::string AddonId;
 /** Checks for, installs and removes Add-ons */
 class AddonManager : public Currenton<AddonManager>
 {
+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<InstallStatus>;
+  using InstallRequestPtr = std::shared_ptr<InstallRequest>;
+
 private:
-  typedef std::vector<std::unique_ptr<Addon> > AddonList;
+  using AddonList = std::vector<std::unique_ptr<Addon> >;
 
   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<Config::Addon>& 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<std::string> scan_for_archives() const;
   void add_installed_addons();
index 28f2313..814c4a2 100644 (file)
@@ -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<std::unique_ptr<Transfer> > m_transfers;