]> git.mxchange.org Git - simgear.git/blobdiff - simgear/package/Catalog.cxx
HTTPRequest/pkg::Install: do not replace callbacks.
[simgear.git] / simgear / package / Catalog.cxx
index 92164fd125f510822114f46c4e47445e01b46b3a..9c36d2aabfd7a2ed3b49d2569098de0143ed63d3 100644 (file)
@@ -1,4 +1,19 @@
-
+// Copyright (C) 2013  James Turner - zakalawe@mac.com
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
 
 #include <simgear/package/Catalog.hxx>
 
@@ -28,28 +43,23 @@ CatalogList static_catalogs;
 class Catalog::Downloader : public HTTP::Request
 {
 public:
-    Downloader(Catalog* aOwner, const std::string& aUrl) :
+    Downloader(CatalogRef aOwner, const std::string& aUrl) :
         HTTP::Request(aUrl),
         m_owner(aOwner)
     {        
     }
     
 protected:
-    virtual void responseHeadersComplete()
-    {
-        
-    }
-    
     virtual void gotBodyData(const char* s, int n)
     {
         m_buffer += std::string(s, n);
     }
     
-    virtual void responseComplete()
+    virtual void onDone()
     {        
         if (responseCode() != 200) {
             SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url());
-            m_owner->refreshComplete(false);
+            m_owner->refreshComplete(Delegate::FAIL_DOWNLOAD);
             return;
         }
         
@@ -60,7 +70,15 @@ protected:
             m_owner->parseProps(props);
         } catch (sg_exception& e) {
             SG_LOG(SG_GENERAL, SG_ALERT, "catalog parse failure:" << m_owner->url());
-            m_owner->refreshComplete(false);
+            m_owner->refreshComplete(Delegate::FAIL_EXTRACT);
+            return;
+        }
+        
+        std::string ver(m_owner->root()->catalogVersion());
+        if (!checkVersion(ver, props)) {
+            SG_LOG(SG_GENERAL, SG_WARN, "downloaded catalog " << m_owner->url() << ", version mismatch:\n\t"
+                   << props->getStringValue("version") << " vs required " << ver);
+            m_owner->refreshComplete(Delegate::FAIL_VERSION);
             return;
         }
         
@@ -74,11 +92,21 @@ protected:
         
         time(&m_owner->m_retrievedTime);
         m_owner->writeTimestamp();
-        m_owner->refreshComplete(true);
+        m_owner->refreshComplete(Delegate::FAIL_SUCCESS);
     }
     
 private:
-    Catalog* m_owner;  
+    bool checkVersion(const std::string& aVersion, SGPropertyNode* aProps)
+    {
+        BOOST_FOREACH(SGPropertyNode* v, aProps->getChildren("version")) {
+            if (v->getStringValue() == aVersion) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    CatalogRef m_owner;
     std::string m_buffer;
 };
 
@@ -102,16 +130,17 @@ Catalog::~Catalog()
     static_catalogs.erase(it);
 }
 
-Catalog* Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
+CatalogRef Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
 {
-    Catalog* c = new Catalog(aRoot);
+    CatalogRef c = new Catalog(aRoot);
+    c->m_url = aUrl;
     Downloader* dl = new Downloader(c, aUrl);
-    aRoot->getHTTPClient()->makeRequest(dl);
+    aRoot->makeHTTPRequest(dl);
     
     return c;
 }
     
-Catalog* Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
+CatalogRef Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
 {
     SGPath xml = aPath;
     xml.append("catalog.xml");
@@ -127,7 +156,13 @@ Catalog* Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
         return NULL;    
     }
     
-    Catalog* c = new Catalog(aRoot);
+    if (props->getStringValue("version") != aRoot->catalogVersion()) {
+        SG_LOG(SG_GENERAL, SG_WARN, "skipping catalog at " << aPath << ", version mismatch:\n\t"
+               << props->getStringValue("version") << " vs required " << aRoot->catalogVersion());
+        return NULL;
+    }
+    
+    CatalogRef c = new Catalog(aRoot);
     c->m_installRoot = aPath;
     c->parseProps(props);
     c->parseTimestamp();
@@ -135,11 +170,17 @@ Catalog* Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
     return c;
 }
 
+PackageList const&
+Catalog::packages() const
+{
+  return m_packages;
+}
+
 PackageList
 Catalog::packagesMatching(const SGPropertyNode* aFilter) const
 {
     PackageList r;
-    BOOST_FOREACH(Package* p, m_packages) {
+    BOOST_FOREACH(PackageRef p, m_packages) {
         if (p->matches(aFilter)) {
             r.push_back(p);
         }
@@ -151,7 +192,7 @@ PackageList
 Catalog::packagesNeedingUpdate() const
 {
     PackageList r;
-    BOOST_FOREACH(Package* p, m_packages) {
+    BOOST_FOREACH(PackageRef p, m_packages) {
         if (!p->isInstalled()) {
             continue;
         }
@@ -163,10 +204,39 @@ Catalog::packagesNeedingUpdate() const
     return r;
 }
 
+PackageList
+Catalog::installedPackages() const
+{
+  PackageList r;
+  BOOST_FOREACH(PackageRef p, m_packages) {
+    if (p->isInstalled()) {
+      r.push_back(p);
+    }
+  }
+  return r;
+}
+  
+InstallRef Catalog::installForPackage(PackageRef pkg) const
+{
+    PackageInstallDict::const_iterator it = m_installed.find(pkg);
+    if (it == m_installed.end()) {
+        // check if it exists on disk, create
+
+        SGPath p(pkg->pathOnDisk());
+        if (p.exists()) {
+            return Install::createFromPath(p, CatalogRef(const_cast<Catalog*>(this)));
+        }
+      
+        return NULL;
+    }
+  
+    return it->second;
+}
+  
 void Catalog::refresh()
 {
     Downloader* dl = new Downloader(this, url());
-    m_root->getHTTPClient()->makeRequest(dl);
+    m_root->makeHTTPRequest(dl);
     m_root->catalogRefreshBegin(this);
 }
 
@@ -174,19 +244,59 @@ void Catalog::parseProps(const SGPropertyNode* aProps)
 {
     // copy everything except package children?
     m_props = new SGPropertyNode;
-    
+
+    m_variantDict.clear(); // will rebuild during parse
+    std::set<PackageRef> orphans;
+    orphans.insert(m_packages.begin(), m_packages.end());
+
     int nChildren = aProps->nChildren();
     for (int i = 0; i < nChildren; i++) {
         const SGPropertyNode* pkgProps = aProps->getChild(i);
         if (strcmp(pkgProps->getName(), "package") == 0) {
-            Package* p = new Package(pkgProps, this);
-            m_packages.push_back(p);   
+            PackageRef p = getPackageById(pkgProps->getStringValue("id"));
+            if (p) {
+                // existing package
+                p->updateFromProps(pkgProps);
+                orphans.erase(p); // not an orphan
+            } else {
+                // new package
+                p = new Package(pkgProps, this);
+                m_packages.push_back(p);
+            }
+
+            string_list vars(p->variants());
+            for (string_list::iterator it = vars.begin(); it != vars.end(); ++it) {
+                m_variantDict[*it] = p.ptr();
+            }
         } else {
             SGPropertyNode* c = m_props->getChild(pkgProps->getName(), pkgProps->getIndex(), true);
             copyProperties(pkgProps, c);
         }
     } // of children iteration
-    
+
+    if (!orphans.empty()) {
+        SG_LOG(SG_GENERAL, SG_WARN, "have orphan packages: will become inaccesible");
+        std::set<PackageRef>::iterator it;
+        for (it = orphans.begin(); it != orphans.end(); ++it) {
+            SG_LOG(SG_GENERAL, SG_WARN, "\torphan package:" << (*it)->qualifiedId());
+            PackageList::iterator pit = std::find(m_packages.begin(), m_packages.end(), *it);
+            assert(pit != m_packages.end());
+            m_packages.erase(pit);
+        }
+    }
+
+    if (!m_url.empty()) {
+        if (m_url != m_props->getStringValue("url")) {
+            // this effectively allows packages to migrate to new locations,
+            // although if we're going to rely on that feature we should
+            // maybe formalise it!
+            SG_LOG(SG_GENERAL, SG_WARN, "package downloaded from:" << m_url
+                   << " is now at: " << m_props->getStringValue("url"));
+        }
+    }
+  
+    m_url = m_props->getStringValue("url");
+
     if (m_installRoot.isNull()) {
         m_installRoot = m_root->path();
         m_installRoot.append(id());
@@ -196,15 +306,15 @@ void Catalog::parseProps(const SGPropertyNode* aProps)
     }
 }
 
-Package* Catalog::getPackageById(const std::string& aId) const
+PackageRef Catalog::getPackageById(const std::string& aId) const
 {
-    BOOST_FOREACH(Package* p, m_packages) {
-        if (p->id() == aId) {
-            return p;
-        }
-    }
-    
-    return NULL; // not found
+    // search the variant dict here, so looking up aircraft variants
+    // works as expected.
+    PackageWeakMap::const_iterator it = m_variantDict.find(aId);
+    if (it == m_variantDict.end())
+        return NULL;
+
+    return it->second;
 }
 
 std::string Catalog::id() const
@@ -214,13 +324,18 @@ std::string Catalog::id() const
 
 std::string Catalog::url() const
 {
-    return m_props->getStringValue("url");
+    return m_url;
 }
 
 std::string Catalog::description() const
 {
     return getLocalisedString(m_props, "description");
 }
+    
+SGPropertyNode* Catalog::properties() const
+{
+    return m_props.ptr();
+}
 
 void Catalog::parseTimestamp()
 {
@@ -246,6 +361,12 @@ unsigned int Catalog::ageInSeconds() const
     return (diff < 0) ? 0 : diff;
 }
 
+bool Catalog::needsRefresh() const
+{
+    unsigned int maxAge = m_props->getIntValue("max-age-sec", m_root->maxAgeSeconds());
+    return (ageInSeconds() > maxAge);
+}
+    
 std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
 {
     if (aRoot->hasChild(m_root->getLocale())) {
@@ -258,11 +379,28 @@ std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char*
     return aRoot->getStringValue(aName);
 }
 
-void Catalog::refreshComplete(bool aSuccess)
+void Catalog::refreshComplete(Delegate::FailureCode aReason)
 {
-    m_root->catalogRefreshComplete(this, aSuccess);
+    m_root->catalogRefreshComplete(this, aReason);
 }
 
+void Catalog::registerInstall(Install* ins)
+{
+  if (!ins || ins->package()->catalog() != this) {
+    return;
+  }
+  
+  m_installed[ins->package()] = ins;
+}
+
+void Catalog::unregisterInstall(Install* ins)
+{
+  if (!ins || ins->package()->catalog() != this) {
+    return;
+  }
+  
+  m_installed.erase(ins->package());
+}
 
 } // of namespace pkg