]> git.mxchange.org Git - flightgear.git/blob - src/Network/HTTPClient.cxx
Replace the NOAA METAR URL with the new, updated one
[flightgear.git] / src / Network / HTTPClient.cxx
1 // HTTPClient.cxx -- Singleton HTTP client object
2 //
3 // Written by James Turner, started April 2012.
4 //
5 // Copyright (C) 2012  James Turner
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
21 #include "HTTPClient.hxx"
22
23 #include <cassert>
24
25 #include <Main/fg_props.hxx>
26 #include <Include/version.h>
27
28 #include <simgear/sg_inlines.h>
29
30 #include <simgear/package/Root.hxx>
31 #include <simgear/package/Catalog.hxx>
32 #include <simgear/package/Delegate.hxx>
33 #include <simgear/package/Install.hxx>
34 #include <simgear/package/Package.hxx>
35
36 #include <simgear/nasal/cppbind/from_nasal.hxx>
37 #include <simgear/nasal/cppbind/to_nasal.hxx>
38 #include <simgear/nasal/cppbind/NasalHash.hxx>
39 #include <simgear/nasal/cppbind/Ghost.hxx>
40
41 #include <Scripting/NasalSys.hxx>
42
43 using namespace simgear;
44
45 typedef nasal::Ghost<pkg::RootRef> NasalPackageRoot;
46 typedef nasal::Ghost<pkg::PackageRef> NasalPackage;
47 typedef nasal::Ghost<pkg::CatalogRef> NasalCatalog;
48 typedef nasal::Ghost<pkg::InstallRef> NasalInstall;
49
50 const char* OFFICIAL_CATALOG_ID = "org.flightgear.official";
51
52 // fallback URL is used when looking up a version-specific catalog fails
53 const char* FALLBACK_CATALOG_URL = "http://fgfs.goneabitbursar.com/pkg/catalog.xml";
54
55 namespace {
56
57     std::string _getDefaultCatalogId()
58     {
59         return fgGetString("/sim/package-system/default-catalog/id",
60                            OFFICIAL_CATALOG_ID);
61     }
62
63     pkg::CatalogRef getDefaultCatalog()
64     {
65         if (!globals->packageRoot())
66             return pkg::CatalogRef();
67
68         return globals->packageRoot()->getCatalogById(_getDefaultCatalogId());
69     }
70
71     std::string _getDefaultCatalogUrl()
72     {
73         return fgGetString("/sim/package-system/default-catalog/url",
74                     "http://fgfs.goneabitbursar.com/pkg/" FLIGHTGEAR_VERSION "/catalog.xml");
75     }
76 } // of anonymous namespace
77
78
79 FGHTTPClient::FGHTTPClient() :
80     _inited(false)
81 {
82 }
83
84 FGHTTPClient::~FGHTTPClient()
85 {
86 }
87
88 void FGHTTPClient::init()
89 {
90     // launcher may need to setup HTTP access abnormally early, so
91     // guard against duplicate inits
92     if (_inited) {
93         return;
94     }
95
96   _http.reset(new simgear::HTTP::Client);
97   
98   std::string proxyHost(fgGetString("/sim/presets/proxy/host"));
99   int proxyPort(fgGetInt("/sim/presets/proxy/port"));
100   std::string proxyAuth(fgGetString("/sim/presets/proxy/auth"));
101   
102   if (!proxyHost.empty()) {
103     _http->setProxy(proxyHost, proxyPort, proxyAuth);
104   }
105   
106   pkg::Root* packageRoot = globals->packageRoot();
107   if (packageRoot) {
108     // package system needs access to the HTTP engine too
109     packageRoot->setHTTPClient(_http.get());
110
111     // start a refresh now
112     // setting 'force' true to work around the problem where a slightly stale
113     // catalog exists, but aircraft are modified - this causes an MD5 sum
114     // mismatch
115     packageRoot->refresh(true);
116   }
117
118     _inited = true;
119 }
120
121 bool FGHTTPClient::isDefaultCatalogInstalled() const
122 {
123     return getDefaultCatalog().valid();
124 }
125
126 void FGHTTPClient::addDefaultCatalog()
127 {
128     pkg::CatalogRef defaultCatalog = getDefaultCatalog();
129     if (!defaultCatalog.valid()) {
130       pkg::Catalog::createFromUrl(globals->packageRoot(), getDefaultCatalogUrl());
131     }
132 }
133
134 std::string FGHTTPClient::getDefaultCatalogId() const
135 {
136     return _getDefaultCatalogId();
137 }
138
139 std::string FGHTTPClient::getDefaultCatalogUrl() const
140 {
141     return _getDefaultCatalogUrl();
142 }
143
144 std::string FGHTTPClient::getDefaultCatalogFallbackUrl() const
145 {
146     return std::string(FALLBACK_CATALOG_URL);
147 }
148
149 static naRef f_package_existingInstall( pkg::Package& pkg,
150                                         const nasal::CallContext& ctx )
151 {
152   return ctx.to_nasal(
153     pkg.existingInstall( ctx.getArg<pkg::Package::InstallCallback>(0) )
154   );
155 }
156
157 static naRef f_package_uninstall(pkg::Package& pkg, const nasal::CallContext& ctx)
158 {
159     pkg::InstallRef ins = pkg.existingInstall();
160     if (ins) {
161         ins->uninstall();
162     }
163
164     return naNil();
165 }
166
167 static SGPropertyNode_ptr queryPropsFromHash(const nasal::Hash& h)
168 {
169     SGPropertyNode_ptr props(new SGPropertyNode);
170
171     for (nasal::Hash::const_iterator it = h.begin(); it != h.end(); ++it) {
172         std::string const key = it->getKey();
173         if ((key == "name") || (key == "description")) {
174             props->setStringValue(key, it->getValue<std::string>());
175         } else if (strutils::starts_with(key, "rating-")) {
176             props->setIntValue(key, it->getValue<int>());
177         } else if (key == "tags") {
178             string_list tags = it->getValue<string_list>();
179             string_list::const_iterator tagIt;
180             int tagCount = 0;
181             for (tagIt = tags.begin(); tagIt != tags.end(); ++tagIt) {
182                 SGPropertyNode_ptr tag = props->getChild("tag", tagCount++, true);
183                 tag->setStringValue(*tagIt);
184             }
185         } else if (key == "installed") {
186             props->setBoolValue(key, it->getValue<bool>());
187         } else {
188             SG_LOG(SG_GENERAL, SG_WARN, "unknown filter term in hash:" << key);
189         }
190     }
191
192     return props;
193 }
194
195 static naRef f_root_search(pkg::Root& root, const nasal::CallContext& ctx)
196 {
197     SGPropertyNode_ptr query = queryPropsFromHash(ctx.requireArg<nasal::Hash>(0));
198     pkg::PackageList result = root.packagesMatching(query);
199     return ctx.to_nasal(result);
200 }
201
202 static naRef f_catalog_search(pkg::Catalog& cat, const nasal::CallContext& ctx)
203 {
204     SGPropertyNode_ptr query = queryPropsFromHash(ctx.requireArg<nasal::Hash>(0));
205     pkg::PackageList result = cat.packagesMatching(query);
206     return ctx.to_nasal(result);
207 }
208
209 static naRef f_package_variants(pkg::Package& pack, naContext c)
210 {
211     nasal::Hash h(c);
212     string_list vars(pack.variants());
213     for (string_list_iterator it  = vars.begin(); it != vars.end(); ++it) {
214         h.set(*it, pack.nameForVariant(*it));
215     }
216
217     return h.get_naRef();
218 }
219
220 void FGHTTPClient::postinit()
221 {
222   NasalPackageRoot::init("PackageRoot")
223   .member("path", &pkg::Root::path)
224   .member("version", &pkg::Root::catalogVersion)
225   .method("refresh", &pkg::Root::refresh)
226   .method("catalogs", &pkg::Root::catalogs)
227   .method("packageById", &pkg::Root::getPackageById)
228   .method("catalogById", &pkg::Root::getCatalogById)
229   .method("search", &f_root_search);
230
231   NasalCatalog::init("Catalog")
232   .member("installRoot", &pkg::Catalog::installRoot)
233   .member("id", &pkg::Catalog::id)
234   .member("url", &pkg::Catalog::url)
235   .member("description", &pkg::Catalog::description)
236   .method("packages", &pkg::Catalog::packages)
237   .method("packageById", &pkg::Catalog::getPackageById)
238   .method("refresh", &pkg::Catalog::refresh)
239   .method("needingUpdate", &pkg::Catalog::packagesNeedingUpdate)
240   .member("installed", &pkg::Catalog::installedPackages)
241   .method("search", &f_catalog_search);
242   
243   NasalPackage::init("Package")
244   .member("id", &pkg::Package::id)
245   .member("name", &pkg::Package::name)
246   .member("description", &pkg::Package::description)
247   .member("installed", &pkg::Package::isInstalled)
248   .member("thumbnails", &pkg::Package::thumbnailUrls)
249   .member("variants", &f_package_variants)
250   .member("revision", &pkg::Package::revision)
251   .member("catalog", &pkg::Package::catalog)
252   .method("install", &pkg::Package::install)
253   .method("uninstall", &f_package_uninstall)
254   .method("existingInstall", &f_package_existingInstall)
255   .method("lprop", &pkg::Package::getLocalisedProp)
256   .member("fileSize", &pkg::Package::fileSizeBytes);
257   
258   typedef pkg::Install* (pkg::Install::*InstallCallback)
259                         (const pkg::Install::Callback&);
260   typedef pkg::Install* (pkg::Install::*ProgressCallback)
261                         (const pkg::Install::ProgressCallback&);
262   NasalInstall::init("Install")
263   .member("revision", &pkg::Install::revsion)
264   .member("pkg", &pkg::Install::package)
265   .member("path", &pkg::Install::path)
266   .member("hasUpdate", &pkg::Install::hasUpdate)
267   .method("startUpdate", &pkg::Install::startUpdate)
268   .method("uninstall", &pkg::Install::uninstall)
269   .method("done", static_cast<InstallCallback>(&pkg::Install::done))
270   .method("fail", static_cast<InstallCallback>(&pkg::Install::fail))
271   .method("always", static_cast<InstallCallback>(&pkg::Install::always))
272   .method("progress", static_cast<ProgressCallback>(&pkg::Install::progress));
273   
274   pkg::Root* packageRoot = globals->packageRoot();
275   if (packageRoot) {
276     FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
277     nasal::Hash nasalGlobals = nasalSys->getGlobals();
278     nasal::Hash nasalPkg = nasalGlobals.createHash("pkg"); // module
279     nasalPkg.set("root", packageRoot);
280   }
281 }
282
283 void FGHTTPClient::shutdown()
284 {
285     _http.reset();
286
287     _inited = false;
288 }
289
290 void FGHTTPClient::update(double)
291 {
292   _http->update();
293 }
294
295 void FGHTTPClient::makeRequest(const simgear::HTTP::Request_ptr& req)
296 {
297   _http->makeRequest(req);
298 }