3 #include <simgear/package/Catalog.hxx>
5 #include <boost/foreach.hpp>
10 #include <simgear/debug/logstream.hxx>
11 #include <simgear/props/props_io.hxx>
12 #include <simgear/io/HTTPRequest.hxx>
13 #include <simgear/io/HTTPClient.hxx>
14 #include <simgear/misc/sg_dir.hxx>
15 #include <simgear/structure/exception.hxx>
16 #include <simgear/package/Package.hxx>
17 #include <simgear/package/Root.hxx>
18 #include <simgear/package/Install.hxx>
24 CatalogList static_catalogs;
26 //////////////////////////////////////////////////////////////////////////////
28 class Catalog::Downloader : public HTTP::Request
31 Downloader(Catalog* aOwner, const std::string& aUrl) :
38 virtual void responseHeadersComplete()
43 virtual void gotBodyData(const char* s, int n)
45 m_buffer += std::string(s, n);
48 virtual void responseComplete()
50 if (responseCode() != 200) {
51 SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url());
52 m_owner->refreshComplete(false);
56 SGPropertyNode* props = new SGPropertyNode;
59 readProperties(m_buffer.data(), m_buffer.size(), props);
60 m_owner->parseProps(props);
61 } catch (sg_exception& e) {
62 SG_LOG(SG_GENERAL, SG_ALERT, "catalog parse failure:" << m_owner->url());
63 m_owner->refreshComplete(false);
67 // cache the catalog data, now we have a valid install root
68 Dir d(m_owner->installRoot());
69 SGPath p = d.file("catalog.xml");
71 std::ofstream f(p.c_str(), std::ios::out | std::ios::trunc);
72 f.write(m_buffer.data(), m_buffer.size());
75 time(&m_owner->m_retrievedTime);
76 m_owner->writeTimestamp();
77 m_owner->refreshComplete(true);
85 //////////////////////////////////////////////////////////////////////////////
87 CatalogList Catalog::allCatalogs()
89 return static_catalogs;
92 Catalog::Catalog(Root *aRoot) :
96 static_catalogs.push_back(this);
101 CatalogList::iterator it = std::find(static_catalogs.begin(), static_catalogs.end(), this);
102 static_catalogs.erase(it);
105 Catalog* Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
107 Catalog* c = new Catalog(aRoot);
108 Downloader* dl = new Downloader(c, aUrl);
109 aRoot->getHTTPClient()->makeRequest(dl);
114 Catalog* Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
117 xml.append("catalog.xml");
122 SGPropertyNode_ptr props;
124 props = new SGPropertyNode;
125 readProperties(xml.str(), props);
126 } catch (sg_exception& e) {
130 Catalog* c = new Catalog(aRoot);
131 c->m_installRoot = aPath;
132 c->parseProps(props);
139 Catalog::packagesMatching(const SGPropertyNode* aFilter) const
142 BOOST_FOREACH(Package* p, m_packages) {
143 if (p->matches(aFilter)) {
151 Catalog::packagesNeedingUpdate() const
154 BOOST_FOREACH(Package* p, m_packages) {
155 if (!p->isInstalled()) {
159 if (p->install()->hasUpdate()) {
166 void Catalog::refresh()
168 Downloader* dl = new Downloader(this, url());
169 m_root->getHTTPClient()->makeRequest(dl);
170 m_root->catalogRefreshBegin(this);
173 void Catalog::parseProps(const SGPropertyNode* aProps)
175 // copy everything except package children?
176 m_props = new SGPropertyNode;
178 int nChildren = aProps->nChildren();
179 for (int i = 0; i < nChildren; i++) {
180 const SGPropertyNode* pkgProps = aProps->getChild(i);
181 if (strcmp(pkgProps->getName(), "package") == 0) {
182 Package* p = new Package(pkgProps, this);
183 m_packages.push_back(p);
185 SGPropertyNode* c = m_props->getChild(pkgProps->getName(), pkgProps->getIndex(), true);
186 copyProperties(pkgProps, c);
188 } // of children iteration
190 if (m_installRoot.isNull()) {
191 m_installRoot = m_root->path();
192 m_installRoot.append(id());
194 Dir d(m_installRoot);
199 Package* Catalog::getPackageById(const std::string& aId) const
201 BOOST_FOREACH(Package* p, m_packages) {
202 if (p->id() == aId) {
207 return NULL; // not found
210 std::string Catalog::id() const
212 return m_props->getStringValue("id");
215 std::string Catalog::url() const
217 return m_props->getStringValue("url");
220 std::string Catalog::description() const
222 return getLocalisedString(m_props, "description");
225 void Catalog::parseTimestamp()
227 SGPath timestampFile = m_installRoot;
228 timestampFile.append(".timestamp");
229 std::ifstream f(timestampFile.c_str(), std::ios::in);
230 f >> m_retrievedTime;
233 void Catalog::writeTimestamp()
235 SGPath timestampFile = m_installRoot;
236 timestampFile.append(".timestamp");
237 std::ofstream f(timestampFile.c_str(), std::ios::out | std::ios::trunc);
238 f << m_retrievedTime << std::endl;
241 int Catalog::ageInSeconds() const
245 return ::difftime(now, m_retrievedTime);
248 std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
250 if (aRoot->hasChild(m_root->getLocale())) {
251 const SGPropertyNode* localeRoot = aRoot->getChild(m_root->getLocale().c_str());
252 if (localeRoot->hasChild(aName)) {
253 return localeRoot->getStringValue(aName);
257 return aRoot->getStringValue(aName);
260 void Catalog::refreshComplete(bool aSuccess)
262 m_root->catalogRefreshComplete(this, aSuccess);
266 } // of namespace pkg
268 } // of namespace simgear