From 2218a44ed76def7dcbe9233cfd34488ad66b7752 Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 18 Apr 2012 10:25:27 +0100 Subject: [PATCH] Support loading PropertyList data remotely, as part of #450. Along the way, centralise the HTTPClient object so it can be used beyond the METAR download engine. --- src/Environment/realwx_ctrl.cxx | 45 +++-------------- src/Main/fg_commands.cxx | 90 +++++++++++++++++++++++++++++++++ src/Main/fg_io.cxx | 5 ++ src/Network/CMakeLists.txt | 2 + src/Network/HTTPClient.cxx | 50 ++++++++++++++++++ src/Network/HTTPClient.hxx | 37 ++++++++++++++ 6 files changed, 192 insertions(+), 37 deletions(-) create mode 100644 src/Network/HTTPClient.cxx create mode 100644 src/Network/HTTPClient.hxx diff --git a/src/Environment/realwx_ctrl.cxx b/src/Environment/realwx_ctrl.cxx index b93316490..0e38d9355 100644 --- a/src/Environment/realwx_ctrl.cxx +++ b/src/Environment/realwx_ctrl.cxx @@ -25,42 +25,25 @@ #endif #include "realwx_ctrl.hxx" -#include "metarproperties.hxx" -#include "metarairportfilter.hxx" -#include "fgmetar.hxx" - -#include
+#include #include #include #include #include -#include #include #include #include -#include +#include "metarproperties.hxx" +#include "metarairportfilter.hxx" +#include "fgmetar.hxx" +#include +#include
namespace Environment { -/* -------------------------------------------------------------------------------- */ -class FGHTTPClient : public simgear::HTTP::Client { -public: - FGHTTPClient(); -}; - -FGHTTPClient::FGHTTPClient() -{ - string proxyHost(fgGetString("/sim/presets/proxy/host")); - int proxyPort(fgGetInt("/sim/presets/proxy/port")); - string proxyAuth(fgGetString("/sim/presets/proxy/auth")); - - if (!proxyHost.empty()) { - setProxy(proxyHost, proxyPort, proxyAuth); - } -} /* -------------------------------------------------------------------------------- */ @@ -295,14 +278,12 @@ void BasicRealWxController::checkNearbyMetar() class NoaaMetarRealWxController : public BasicRealWxController, MetarRequester { public: NoaaMetarRealWxController( SGPropertyNode_ptr rootNode ); - virtual ~NoaaMetarRealWxController(); - virtual void update( double dt ); // implementation of MetarRequester virtual void requestMetar( MetarDataHandler * metarDataHandler, const std::string & id ); private: - FGHTTPClient _http; + }; NoaaMetarRealWxController::NoaaMetarRealWxController( SGPropertyNode_ptr rootNode ) : @@ -310,16 +291,6 @@ NoaaMetarRealWxController::NoaaMetarRealWxController( SGPropertyNode_ptr rootNod { } -NoaaMetarRealWxController::~NoaaMetarRealWxController() -{ -} - -void NoaaMetarRealWxController::update( double dt ) -{ - _http.update(); - BasicRealWxController::update( dt ); -} - void NoaaMetarRealWxController::requestMetar( MetarDataHandler * metarDataHandler, const std::string & id ) { class NoaaMetarGetRequest : public simgear::HTTP::Request @@ -384,7 +355,7 @@ void NoaaMetarRealWxController::requestMetar( MetarDataHandler * metarDataHandle SG_LOG(SG_ENVIRONMENT, SG_INFO, "NoaaMetarRealWxController::update(): spawning load request for station-id '" << id << "'" ); - _http.makeRequest(new NoaaMetarGetRequest(metarDataHandler, id)); + FGHTTPClient::instance()->makeRequest(new NoaaMetarGetRequest(metarDataHandler, id)); } /* -------------------------------------------------------------------------------- */ diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index bf7bbdede..cf36a7777 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include "fg_init.hxx" #include "fg_io.hxx" @@ -1316,6 +1318,93 @@ do_load_xml_to_proptree(const SGPropertyNode * arg) return true; } +class RemoteXMLRequest : public simgear::HTTP::Request +{ +public: + SGPropertyNode_ptr _complete; + SGPropertyNode_ptr _status; + SGPropertyNode_ptr _failed; + SGPropertyNode_ptr _target; + string propsData; + + RemoteXMLRequest(const std::string& url, SGPropertyNode* targetNode) : + simgear::HTTP::Request(url), + _target(targetNode) + { + } + + void setCompletionProp(SGPropertyNode_ptr p) + { + _complete = p; + } + + void setStatusProp(SGPropertyNode_ptr p) + { + _status = p; + } + + void setFailedProp(SGPropertyNode_ptr p) + { + _failed = p; + } +protected: + virtual void gotBodyData(const char* s, int n) + { + propsData += string(s, n); + } + + virtual void responseComplete() + { + int response = responseCode(); + bool failed = false; + if (response == 200) { + try { + const char* buffer = propsData.c_str(); + readProperties(buffer, propsData.size(), _target, true); + } catch (const sg_exception &e) { + SG_LOG(SG_IO, SG_WARN, "parsing XML from remote, failed: " << e.getFormattedMessage()); + failed = true; + response = 406; // 'not acceptable', anything better? + } + } else { + failed = true; + } + // now the response data is output, signal Nasal / listeners + if (_complete) _complete->setBoolValue(true); + if (_status) _status->setIntValue(response); + if (_failed) _failed->setBoolValue(failed); + } +}; + + +static bool +do_load_xml_from_url(const SGPropertyNode * arg) +{ + std::string url(arg->getStringValue("url")); + if (url.empty()) + return false; + + SGPropertyNode *targetnode; + if (arg->hasValue("targetnode")) + targetnode = fgGetNode(arg->getStringValue("targetnode"), true); + else + targetnode = const_cast(arg)->getNode("data", true); + + RemoteXMLRequest* req = new RemoteXMLRequest(url, targetnode); + +// connect up optional reporting properties + if (arg->hasValue("complete")) + req->setCompletionProp(fgGetNode(arg->getStringValue("complete"), true)); + if (arg->hasValue("failure")) + req->setFailedProp(fgGetNode(arg->getStringValue("failure"), true)); + if (arg->hasValue("status")) + req->setStatusProp(fgGetNode(arg->getStringValue("status"), true)); + + FGHTTPClient::instance()->makeRequest(req); + + return true; +} + /** * An fgcommand to allow saving of xml files via nasal, @@ -1531,6 +1620,7 @@ static struct { */ { "loadxml", do_load_xml_to_proptree}, { "savexml", do_save_xml_from_proptree }, + { "xmlhttprequest", do_load_xml_from_url }, { "press-cockpit-button", do_press_cockpit_button }, { "release-cockpit-button", do_release_cockpit_button }, { "dump-scenegraph", do_dump_scene_graph }, diff --git a/src/Main/fg_io.cxx b/src/Main/fg_io.cxx index 7c5f69652..2014212b5 100644 --- a/src/Main/fg_io.cxx +++ b/src/Main/fg_io.cxx @@ -65,6 +65,7 @@ #include #include #include +#include #ifdef FG_HAVE_HLA #include @@ -382,6 +383,10 @@ FGIO::reinit() void FGIO::update( double /* delta_time_sec */ ) { + if (FGHTTPClient::haveInstance()) { + FGHTTPClient::instance()->update(); + } + // use wall-clock, not simulation, delta time, so that network // protocols update when the simulation is paused // see http://code.google.com/p/flightgear-bugs/issues/detail?id=125 diff --git a/src/Network/CMakeLists.txt b/src/Network/CMakeLists.txt index f7947495d..2d2bc2c5b 100644 --- a/src/Network/CMakeLists.txt +++ b/src/Network/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES garmin.cxx generic.cxx httpd.cxx + HTTPClient.cxx joyclient.cxx jsclient.cxx lfsglass.cxx @@ -38,6 +39,7 @@ set(HEADERS garmin.hxx generic.hxx httpd.hxx + HTTPClient.hxx joyclient.hxx jsclient.hxx lfsglass.hxx diff --git a/src/Network/HTTPClient.cxx b/src/Network/HTTPClient.cxx new file mode 100644 index 000000000..ca293d83c --- /dev/null +++ b/src/Network/HTTPClient.cxx @@ -0,0 +1,50 @@ +// HTTPClient.cxx -- Singleton HTTP client object +// +// Written by James Turner, started April 2012. +// +// Copyright (C) 2012 James Turner +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program 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 +// 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 "HTTPClient.hxx" + +#include
+ +static FGHTTPClient* static_instance = NULL; + +FGHTTPClient* FGHTTPClient::instance() +{ + if (!static_instance) { + static_instance = new FGHTTPClient; + } + + return static_instance; +} + +bool FGHTTPClient::haveInstance() +{ + return (static_instance != NULL); +} + +FGHTTPClient::FGHTTPClient() +{ + std::string proxyHost(fgGetString("/sim/presets/proxy/host")); + int proxyPort(fgGetInt("/sim/presets/proxy/port")); + std::string proxyAuth(fgGetString("/sim/presets/proxy/auth")); + + if (!proxyHost.empty()) { + setProxy(proxyHost, proxyPort, proxyAuth); + } +} diff --git a/src/Network/HTTPClient.hxx b/src/Network/HTTPClient.hxx new file mode 100644 index 000000000..b36027e7f --- /dev/null +++ b/src/Network/HTTPClient.hxx @@ -0,0 +1,37 @@ +// HTTPClient.hxx -- Singleton HTTP client object +// +// Written by James Turner, started April 2012. +// +// Copyright (C) 2012 James Turner +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program 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 +// 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. + +#ifndef FG_HTTP_CLIENT_HXX +#define FG_HTTP_CLIENT_HXX + +#include + +class FGHTTPClient : public simgear::HTTP::Client { +public: + static FGHTTPClient* instance(); + + static bool haveInstance(); +private: + FGHTTPClient(); +}; + +#endif // FG_HTTP_CLIENT_HXX + + -- 2.39.5