X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fpackage%2FRoot.cxx;h=785076530feed194e611c75e4edbe830d684decc;hb=32181a3956a8e7e1cb4bdb5338a260df7d343534;hp=8d3b52a86a8b8ec9f8f26234597b2ccfa66787f1;hpb=3bfd0c872a7807c2a648e4435047fed4a52e555b;p=simgear.git diff --git a/simgear/package/Root.cxx b/simgear/package/Root.cxx index 8d3b52a8..78507653 100644 --- a/simgear/package/Root.cxx +++ b/simgear/package/Root.cxx @@ -34,7 +34,7 @@ #include namespace simgear { - + namespace pkg { typedef std::map CatalogDict; @@ -50,20 +50,20 @@ public: m_owner(aOwner) { } - + protected: virtual void gotBodyData(const char* s, int n) { m_buffer += std::string(s, n); } - + virtual void onDone(); - + private: Root::RootPrivate* m_owner; std::string m_buffer; }; - + class Root::RootPrivate { public: @@ -72,7 +72,7 @@ public: maxAgeSeconds(60 * 60 * 24) { } - + void fireStartInstall(InstallRef install) { DelegateVec::const_iterator it; @@ -80,7 +80,7 @@ public: (*it)->startInstall(install); } } - + void fireInstallProgress(InstallRef install, unsigned int aBytes, unsigned int aTotal) { @@ -89,7 +89,7 @@ public: (*it)->installProgress(install, aBytes, aTotal); } } - + void fireFinishInstall(InstallRef install, Delegate::StatusCode status) { DelegateVec::const_iterator it; @@ -97,7 +97,7 @@ public: (*it)->finishInstall(install, status); } } - + void fireRefreshStatus(CatalogRef catalog, Delegate::StatusCode status) { DelegateVec::const_iterator it; @@ -105,8 +105,15 @@ public: (*it)->catalogRefreshed(catalog, status); } } - - + + void firePackagesChanged() + { + DelegateVec::const_iterator it; + for (it = delegates.begin(); it != delegates.end(); ++it) { + (*it)->availablePackagesChanged(); + } + } + void thumbnailDownloadComplete(HTTP::Request_ptr request, Delegate::StatusCode status, const std::string& bytes) { @@ -115,10 +122,10 @@ public: thumbnailCache[u] = bytes; fireDataForThumbnail(u, bytes); } - + downloadNextPendingThumbnail(); } - + void fireDataForThumbnail(const std::string& aUrl, const std::string& bytes) { DelegateVec::const_iterator it; @@ -127,48 +134,49 @@ public: (*it)->dataForThumbnail(aUrl, bytes.size(), data); } } - + void downloadNextPendingThumbnail() { thumbnailDownloadRequest.clear(); if (pendingThumbnails.empty()) { return; } - + std::string u = pendingThumbnails.front(); pendingThumbnails.pop_front(); thumbnailDownloadRequest = new Root::ThumbnailDownloader(this, u); - + if (http) { http->makeRequest(thumbnailDownloadRequest); } else { httpPendingRequests.push_back(thumbnailDownloadRequest); } } - + DelegateVec delegates; - + SGPath path; std::string locale; HTTP::Client* http; CatalogDict catalogs; + CatalogList disabledCatalogs; unsigned int maxAgeSeconds; std::string version; - + std::set refreshing; typedef std::deque UpdateDeque; UpdateDeque updateDeque; std::deque httpPendingRequests; - + HTTP::Request_ptr thumbnailDownloadRequest; StringDeque pendingThumbnails; MemThumbnailCache thumbnailCache; - + typedef std::map InstallCache; InstallCache m_installs; }; - - + + void Root::ThumbnailDownloader::onDone() { if (responseCode() != 200) { @@ -176,23 +184,23 @@ void Root::ThumbnailDownloader::onDone() m_owner->thumbnailDownloadComplete(this, Delegate::FAIL_DOWNLOAD, std::string()); return; } - + m_owner->thumbnailDownloadComplete(this, Delegate::STATUS_SUCCESS, m_buffer); //time(&m_owner->m_retrievedTime); //m_owner->writeTimestamp(); //m_owner->refreshComplete(Delegate::STATUS_REFRESHED); } - + SGPath Root::path() const { return d->path; } - + void Root::setMaxAgeSeconds(unsigned int seconds) { d->maxAgeSeconds = seconds; } - + unsigned int Root::maxAgeSeconds() const { return d->maxAgeSeconds; @@ -214,10 +222,24 @@ void Root::makeHTTPRequest(HTTP::Request *req) d->http->makeRequest(req); return; } - + d->httpPendingRequests.push_back(req); } - + +void Root::cancelHTTPRequest(HTTP::Request *req, const std::string &reason) +{ + if (d->http) { + d->http->cancelRequest(req, reason); + } + + std::deque::iterator it = std::find(d->httpPendingRequests.begin(), + d->httpPendingRequests.end(), + req); + if (it != d->httpPendingRequests.end()) { + d->httpPendingRequests.erase(it); + } +} + Root::Root(const SGPath& aPath, const std::string& aVersion) : d(new RootPrivate) { @@ -226,50 +248,56 @@ Root::Root(const SGPath& aPath, const std::string& aVersion) : if (getenv("LOCALE")) { d->locale = getenv("LOCALE"); } - + Dir dir(aPath); if (!dir.exists()) { dir.create(0755); return; } - - BOOST_FOREACH(SGPath c, dir.children(Dir::TYPE_DIR)) { + + BOOST_FOREACH(SGPath c, dir.children(Dir::TYPE_DIR | Dir::NO_DOT_OR_DOTDOT)) { CatalogRef cat = Catalog::createFromPath(this, c); if (cat) { - d->catalogs[cat->id()] = cat; + if (cat->status() == Delegate::STATUS_SUCCESS) { + d->catalogs[cat->id()] = cat; + } else { + // catalog has problems, such as needing an update + // keep it out of the main collection for now + d->disabledCatalogs.push_back(cat); + } } } // of child directories iteration } Root::~Root() { - + } int Root::catalogVersion() const { return 4; } - + std::string Root::applicationVersion() const { return d->version; } - + CatalogRef Root::getCatalogById(const std::string& aId) const { CatalogDict::const_iterator it = d->catalogs.find(aId); if (it == d->catalogs.end()) { return NULL; } - + return it->second; } PackageRef Root::getPackageById(const std::string& aName) const { size_t lastDot = aName.rfind('.'); - + PackageRef pkg = NULL; if (lastDot == std::string::npos) { // naked package ID @@ -280,17 +308,17 @@ PackageRef Root::getPackageById(const std::string& aName) const return pkg; } } - + return NULL; } - + std::string catalogId = aName.substr(0, lastDot); - std::string id = aName.substr(lastDot + 1); + std::string id = aName.substr(lastDot + 1); CatalogRef catalog = getCatalogById(catalogId); if (!catalog) { return NULL; } - + return catalog->getPackageById(id); } @@ -301,7 +329,7 @@ CatalogList Root::catalogs() const for (; it != d->catalogs.end(); ++it) { r.push_back(it->second); } - + return r; } @@ -309,27 +337,27 @@ PackageList Root::allPackages() const { PackageList r; - + CatalogDict::const_iterator it = d->catalogs.begin(); for (; it != d->catalogs.end(); ++it) { const PackageList& r2(it->second->packages()); r.insert(r.end(), r2.begin(), r2.end()); } - + return r; } - + PackageList Root::packagesMatching(const SGPropertyNode* aFilter) const { PackageList r; - + CatalogDict::const_iterator it = d->catalogs.begin(); for (; it != d->catalogs.end(); ++it) { PackageList r2(it->second->packagesMatching(aFilter)); r.insert(r.end(), r2.begin(), r2.end()); } - + return r; } @@ -337,27 +365,38 @@ PackageList Root::packagesNeedingUpdate() const { PackageList r; - + CatalogDict::const_iterator it = d->catalogs.begin(); for (; it != d->catalogs.end(); ++it) { PackageList r2(it->second->packagesNeedingUpdate()); r.insert(r.end(), r2.begin(), r2.end()); } - + return r; } void Root::refresh(bool aForce) { bool didStartAny = false; + + // copy all candidate ctalogs to a seperate list, since refreshing + // can modify both the main collection and/or the disabled list + CatalogList toRefresh; CatalogDict::iterator it = d->catalogs.begin(); for (; it != d->catalogs.end(); ++it) { - if (aForce || it->second->needsRefresh()) { - it->second->refresh(); - didStartAny = true; - } + toRefresh.push_back(it->second); + } + + toRefresh.insert(toRefresh.end(), d->disabledCatalogs.begin(), + d->disabledCatalogs.end()); + + + CatalogList::iterator j = toRefresh.begin(); + for (; j != toRefresh.end(); ++j) { + (*j)->refresh(); + didStartAny = true; } - + if (!didStartAny) { // signal refresh complete to the delegate already d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED); @@ -368,7 +407,7 @@ void Root::addDelegate(simgear::pkg::Delegate *aDelegate) { d->delegates.push_back(aDelegate); } - + void Root::removeDelegate(simgear::pkg::Delegate *aDelegate) { DelegateVec::iterator it = std::find(d->delegates.begin(), @@ -378,7 +417,7 @@ void Root::removeDelegate(simgear::pkg::Delegate *aDelegate) } d->delegates.erase(it); } - + void Root::setLocale(const std::string& aLocale) { d->locale = aLocale; @@ -394,7 +433,7 @@ void Root::scheduleToUpdate(InstallRef aInstall) if (!aInstall) { throw sg_exception("missing argument to scheduleToUpdate"); } - + PackageList deps = aInstall->package()->dependencies(); BOOST_FOREACH(Package* dep, deps) { // will internally schedule for update if required @@ -404,7 +443,7 @@ void Root::scheduleToUpdate(InstallRef aInstall) bool wasEmpty = d->updateDeque.empty(); d->updateDeque.push_back(aInstall); - + if (wasEmpty) { aInstall->startUpdate(); } @@ -416,7 +455,7 @@ bool Root::isInstallQueued(InstallRef aInstall) const std::find(d->updateDeque.begin(), d->updateDeque.end(), aInstall); return (it != d->updateDeque.end()); } - + void Root::startInstall(InstallRef aInstall) { d->fireStartInstall(aInstall); @@ -434,7 +473,7 @@ void Root::startNext(InstallRef aCurrent) } else { d->updateDeque.pop_front(); } - + if (!d->updateDeque.empty()) { d->updateDeque.front()->startUpdate(); } @@ -475,54 +514,88 @@ void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason) if (aReason == Delegate::STATUS_IN_PROGRESS) { d->refreshing.insert(aCat); - - if (catIt == d->catalogs.end()) { - // first fresh, add to our storage now - d->catalogs.insert(catIt, CatalogDict::value_type(aCat->id(), aCat)); - } } else { d->refreshing.erase(aCat); } - - if ((aReason != Delegate::STATUS_REFRESHED) && (aReason != Delegate::STATUS_IN_PROGRESS)) { - // if the failure is permanent, delete the catalog from our - // list (don't touch it on disk) - bool isPermanentFailure = (aReason == Delegate::FAIL_VERSION); - if (isPermanentFailure) { - SG_LOG(SG_GENERAL, SG_WARN, "permanent failure for catalog:" << aCat->id()); - if (catIt != d->catalogs.end()) { - d->catalogs.erase(catIt); - } + + if ((aReason == Delegate::STATUS_REFRESHED) && (catIt == d->catalogs.end())) { + assert(!aCat->id().empty()); + d->catalogs.insert(catIt, CatalogDict::value_type(aCat->id(), aCat)); + + // catalog might have been previously disabled, let's remove in that case + CatalogList::iterator j = std::find(d->disabledCatalogs.begin(), + d->disabledCatalogs.end(), + aCat); + if (j != d->disabledCatalogs.end()) { + SG_LOG(SG_GENERAL, SG_INFO, "re-enabling disabled catalog:" << aCat->id()); + d->disabledCatalogs.erase(j); } } - + + if ((aReason != Delegate::STATUS_REFRESHED) && + (aReason != Delegate::STATUS_IN_PROGRESS) && + (aReason != Delegate::STATUS_SUCCESS)) + { + // catalog has errors, disable it + CatalogList::iterator j = std::find(d->disabledCatalogs.begin(), + d->disabledCatalogs.end(), + aCat); + if (j == d->disabledCatalogs.end()) { + SG_LOG(SG_GENERAL, SG_INFO, "disabling catalog:" << aCat->id()); + d->disabledCatalogs.push_back(aCat); + } + + // and remove it from the active collection + if (catIt != d->catalogs.end()) { + d->catalogs.erase(catIt); + } + } // of catalog has errors case + if (d->refreshing.empty()) { d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED); + d->firePackagesChanged(); } } bool Root::removeCatalogById(const std::string& aId) { + CatalogRef cat; + CatalogDict::iterator catIt = d->catalogs.find(aId); if (catIt == d->catalogs.end()) { - SG_LOG(SG_GENERAL, SG_WARN, "removeCatalogById: unknown ID:" << aId); - return false; - } - - CatalogRef cat = catIt->second; - - // drop the reference - d->catalogs.erase(catIt); - + // check the disabled list + CatalogList::iterator j = d->disabledCatalogs.begin(); + for (; j != d->disabledCatalogs.end(); ++j) { + if ((*j)->id() == aId) { + break; + } + } + + if (j == d->disabledCatalogs.end()) { + SG_LOG(SG_GENERAL, SG_WARN, "removeCatalogById: no catalog with id:" << aId); + return false; + } + + cat = *j; + d->disabledCatalogs.erase(j); + } else { + cat = catIt->second; + // drop the reference + d->catalogs.erase(catIt); + } + bool ok = cat->uninstall(); if (!ok) { SG_LOG(SG_GENERAL, SG_WARN, "removeCatalogById: catalog :" << aId << "failed to uninstall"); } - + + // notify that a catalog is being removed + d->firePackagesChanged(); + return ok; } - + void Root::requestThumbnailData(const std::string& aUrl) { MemThumbnailCache::iterator it = d->thumbnailCache.find(aUrl); @@ -538,7 +611,7 @@ void Root::requestThumbnailData(const std::string& aUrl) // in cache but empty data, still fetching } } - + InstallRef Root::existingInstallForPackage(PackageRef p) const { RootPrivate::InstallCache::const_iterator it = @@ -556,16 +629,16 @@ InstallRef Root::existingInstallForPackage(PackageRef p) const d->m_installs[p] = InstallRef(); return InstallRef(); } - + return it->second; } - + void Root::registerInstall(InstallRef ins) { if (!ins.valid()) { return; } - + d->m_installs[ins->package()] = ins; } @@ -574,10 +647,10 @@ void Root::unregisterInstall(InstallRef ins) if (!ins .valid()) { return; } - + d->m_installs.erase(ins->package()); } - + } // of namespace pkg } // of namespace simgear