3 #include <simgear/package/Catalog.hxx>
5 #include <boost/foreach.hpp>
9 #include <simgear/debug/logstream.hxx>
10 #include <simgear/props/props_io.hxx>
11 #include <simgear/io/HTTPRequest.hxx>
12 #include <simgear/io/HTTPClient.hxx>
13 #include <simgear/misc/sg_dir.hxx>
14 #include <simgear/structure/exception.hxx>
15 #include <simgear/package/Package.hxx>
16 #include <simgear/package/Root.hxx>
17 #include <simgear/package/Install.hxx>
23 CatalogList static_catalogs;
25 //////////////////////////////////////////////////////////////////////////////
27 class Catalog::Downloader : public HTTP::Request
30 Downloader(Catalog* aOwner, const std::string& aUrl) :
37 virtual void responseHeadersComplete()
42 virtual void gotBodyData(const char* s, int n)
44 m_buffer += std::string(s, n);
47 virtual void responseComplete()
49 if (responseCode() != 200) {
50 SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url());
51 m_owner->refreshComplete(false);
55 SGPropertyNode* props = new SGPropertyNode;
58 readProperties(m_buffer.data(), m_buffer.size(), props);
59 m_owner->parseProps(props);
60 } catch (sg_exception& e) {
61 SG_LOG(SG_GENERAL, SG_ALERT, "catalog parse failure:" << m_owner->url());
62 m_owner->refreshComplete(false);
66 // cache the catalog data, now we have a valid install root
67 Dir d(m_owner->installRoot());
68 SGPath p = d.file("catalog.xml");
70 std::ofstream f(p.c_str(), std::ios::out | std::ios::trunc);
71 f.write(m_buffer.data(), m_buffer.size());
74 time(&m_owner->m_retrievedTime);
75 m_owner->writeTimestamp();
76 m_owner->refreshComplete(true);
84 //////////////////////////////////////////////////////////////////////////////
86 CatalogList Catalog::allCatalogs()
88 return static_catalogs;
91 Catalog::Catalog(Root *aRoot) :
95 static_catalogs.push_back(this);
100 CatalogList::iterator it = std::find(static_catalogs.begin(), static_catalogs.end(), this);
101 static_catalogs.erase(it);
104 Catalog* Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
106 Catalog* c = new Catalog(aRoot);
107 Downloader* dl = new Downloader(c, aUrl);
108 aRoot->getHTTPClient()->makeRequest(dl);
113 Catalog* Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
116 xml.append("catalog.xml");
121 SGPropertyNode_ptr props;
123 props = new SGPropertyNode;
124 readProperties(xml.str(), props);
125 } catch (sg_exception& e) {
129 Catalog* c = new Catalog(aRoot);
130 c->m_installRoot = aPath;
131 c->parseProps(props);
138 Catalog::packagesMatching(const SGPropertyNode* aFilter) const
141 BOOST_FOREACH(Package* p, m_packages) {
142 if (p->matches(aFilter)) {
150 Catalog::packagesNeedingUpdate() const
153 BOOST_FOREACH(Package* p, m_packages) {
154 if (!p->isInstalled()) {
158 if (p->install()->hasUpdate()) {
165 void Catalog::refresh()
167 Downloader* dl = new Downloader(this, url());
168 m_root->getHTTPClient()->makeRequest(dl);
169 m_root->catalogRefreshBegin(this);
172 void Catalog::parseProps(const SGPropertyNode* aProps)
174 // copy everything except package children?
175 m_props = new SGPropertyNode;
177 int nChildren = aProps->nChildren();
178 for (int i = 0; i < nChildren; i++) {
179 const SGPropertyNode* pkgProps = aProps->getChild(i);
180 if (strcmp(pkgProps->getName(), "package") == 0) {
181 Package* p = new Package(pkgProps, this);
182 m_packages.push_back(p);
184 SGPropertyNode* c = m_props->getChild(pkgProps->getName(), pkgProps->getIndex(), true);
185 copyProperties(pkgProps, c);
187 } // of children iteration
189 if (m_installRoot.isNull()) {
190 m_installRoot = m_root->path();
191 m_installRoot.append(id());
193 Dir d(m_installRoot);
198 Package* Catalog::getPackageById(const std::string& aId) const
200 BOOST_FOREACH(Package* p, m_packages) {
201 if (p->id() == aId) {
206 return NULL; // not found
209 std::string Catalog::id() const
211 return m_props->getStringValue("id");
214 std::string Catalog::url() const
216 return m_props->getStringValue("url");
219 std::string Catalog::description() const
221 return getLocalisedString(m_props, "description");
224 void Catalog::parseTimestamp()
226 SGPath timestampFile = m_installRoot;
227 timestampFile.append(".timestamp");
228 std::ifstream f(timestampFile.c_str(), std::ios::in);
229 f >> m_retrievedTime;
232 void Catalog::writeTimestamp()
234 SGPath timestampFile = m_installRoot;
235 timestampFile.append(".timestamp");
236 std::ofstream f(timestampFile.c_str(), std::ios::out | std::ios::trunc);
237 f << m_retrievedTime << std::endl;
240 int Catalog::ageInSeconds() const
244 return ::difftime(now, m_retrievedTime);
247 std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
249 if (aRoot->hasChild(m_root->getLocale())) {
250 const SGPropertyNode* localeRoot = aRoot->getChild(m_root->getLocale().c_str());
251 if (localeRoot->hasChild(aName)) {
252 return localeRoot->getStringValue(aName);
256 return aRoot->getStringValue(aName);
259 void Catalog::refreshComplete(bool aSuccess)
261 m_root->catalogRefreshComplete(this, aSuccess);
265 } // of namespace pkg
267 } // of namespace simgear