--- /dev/null
+// FlightHistoryUriHandler.cxx -- FlightHistory service
+//
+// Written by Torsten Dreyer, started February 2015.
+//
+// Copyright (C) 2015 Torsten Dreyer
+//
+// 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 "FlightHistoryUriHandler.hxx"
+#include "SimpleDOM.hxx"
+#include <3rdparty/cjson/cJSON.h>
+
+#include <Aircraft/FlightHistory.hxx>
+#include <Main/fg_props.hxx>
+#include <sstream>
+
+using std::string;
+using std::stringstream;
+
+namespace flightgear {
+namespace http {
+
+static cJSON * GeodToJson(const SGGeod & geod) {
+ cJSON * json = cJSON_CreateObject();
+
+ cJSON_AddItemToObject(json, "latitude",
+ cJSON_CreateNumber(geod.getLatitudeDeg()));
+ cJSON_AddItemToObject(json, "longitude",
+ cJSON_CreateNumber(geod.getLongitudeDeg()));
+ cJSON_AddItemToObject(json, "altitude",
+ cJSON_CreateNumber(geod.getElevationFt()));
+
+ return json;
+}
+
+static string FlightHistoryToJson(const SGGeodVec & history) {
+ cJSON * json = cJSON_CreateObject();
+
+ cJSON * jsonArray = cJSON_CreateArray();
+ for (SGGeodVec::const_iterator it = history.begin(); it != history.end();
+ ++it) {
+ cJSON_AddItemToArray(jsonArray, GeodToJson(*it));
+ }
+ cJSON_AddItemToObject(json, "flightHistory", jsonArray);
+
+ char * jsonString = cJSON_PrintUnformatted(json);
+ string reply(jsonString);
+ free(jsonString);
+ cJSON_Delete(json);
+ return reply;
+}
+
+static string AutoUpdateResponse(const HTTPRequest & request,
+ const string & base, const string & interval) {
+
+ string url = "http://";
+ url.append(request.HeaderVariables.get("Host")).append(base);
+
+ std::string reply("<?xml version='1.0' encoding='UTF-8'?>");
+ DOMNode * kml = new DOMNode("kml");
+ kml->setAttribute("xmlns", "http://www.opengis.net/kml/2.2");
+
+ DOMNode * document = kml->addChild(new DOMNode("Document"));
+
+ DOMNode * networkLink = document->addChild(new DOMNode("NetworkLink"));
+ DOMNode * link = networkLink->addChild(new DOMNode("Link"));
+ link->addChild(new DOMNode("href"))->addChild(new DOMTextElement(url));
+ link->addChild(new DOMNode("refreshMode"))->addChild(
+ new DOMTextElement("onInterval"));
+ link->addChild(new DOMNode("refreshInterval"))->addChild(
+ new DOMTextElement(interval.empty() ? "10" : interval));
+
+ reply.append(kml->render());
+ delete kml;
+ return reply;
+}
+
+static string FlightHistoryToKml(const SGGeodVec & history,
+ const HTTPRequest & request) {
+ string interval = request.RequestVariables.get("interval");
+ if (false == interval.empty()) {
+ return AutoUpdateResponse(request, "/flighthistory/track.kml", interval);
+ }
+
+ std::string reply("<?xml version='1.0' encoding='UTF-8'?>");
+ DOMNode * kml = new DOMNode("kml");
+ kml->setAttribute("xmlns", "http://www.opengis.net/kml/2.2");
+
+ DOMNode * document = kml->addChild(new DOMNode("Document"));
+
+ document->addChild(new DOMNode("name"))->addChild(
+ new DOMTextElement("FlightGear"));
+ document->addChild(new DOMNode("description"))->addChild(
+ new DOMTextElement("FlightGear Flight History"));
+
+ DOMNode * style = document->addChild(new DOMNode("Style"))->setAttribute(
+ "id", "flight-history");
+ DOMNode * lineStyle = style->addChild(new DOMNode("LineStyle"));
+
+ string lineColor = request.RequestVariables.get("LineColor");
+ string lineWidth = request.RequestVariables.get("LineWidth");
+ string polyColor = request.RequestVariables.get("PolyColor");
+
+ lineStyle->addChild(new DOMNode("color"))->addChild(
+ new DOMTextElement(lineColor.empty() ? "427ebfff" : lineColor));
+ lineStyle->addChild(new DOMNode("width"))->addChild(
+ new DOMTextElement(lineWidth.empty() ? "4" : lineWidth));
+
+ lineStyle = style->addChild(new DOMNode("PolyStyle"));
+ lineStyle->addChild(new DOMNode("color"))->addChild(
+ new DOMTextElement(polyColor.empty() ? "fbfc4600" : polyColor));
+
+ DOMNode * placemark = document->addChild(new DOMNode("Placemark"));
+ placemark->addChild(new DOMNode("name"))->addChild(
+ new DOMTextElement("Flight Path"));
+ placemark->addChild(new DOMNode("styleUrl"))->addChild(
+ new DOMTextElement("#flight-history"));
+
+ DOMNode * linestring = placemark->addChild(new DOMNode("LineString"));
+ linestring->addChild(new DOMNode("extrude"))->addChild(
+ new DOMTextElement("1"));
+ linestring->addChild(new DOMNode("tessalate"))->addChild(
+ new DOMTextElement("1"));
+ linestring->addChild(new DOMNode("altitudeMode"))->addChild(
+ new DOMTextElement("absolute"));
+
+ stringstream ss;
+
+ for (SGGeodVec::const_iterator it = history.begin(); it != history.end();
+ ++it) {
+ ss << (*it).getLongitudeDeg() << "," << (*it).getLatitudeDeg() << ","
+ << it->getElevationM() << " ";
+ }
+
+ linestring->addChild(new DOMNode("coordinates"))->addChild(
+ new DOMTextElement(ss.str()));
+
+ reply.append(kml->render());
+ delete kml;
+ return reply;
+}
+
+static bool GetJsonDouble(cJSON * json, const char * item, double & out) {
+ cJSON * cj = cJSON_GetObjectItem(json, item);
+ if (NULL == cj)
+ return false;
+
+ if (cj->type != cJSON_Number)
+ return false;
+
+ out = cj->valuedouble;
+
+ return true;
+}
+
+static bool GetJsonBool(cJSON * json, const char * item, bool & out) {
+ cJSON * cj = cJSON_GetObjectItem(json, item);
+ if (NULL == cj)
+ return false;
+
+ if (cj->type == cJSON_True) {
+ out = true;
+ return true;
+ }
+ if (cj->type == cJSON_False) {
+ out = true;
+ return true;
+
+ }
+ return false;
+}
+
+bool FlightHistoryUriHandler::handleRequest(const HTTPRequest & request,
+ HTTPResponse & response, Connection * connection) {
+ response.Header["Access-Control-Allow-Origin"] = "*";
+ response.Header["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST";
+ response.Header["Access-Control-Allow-Headers"] =
+ "Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token";
+
+ if (request.Method == "OPTIONS") {
+ return true; // OPTIONS only needs the headers
+ }
+
+ FGFlightHistory* history =
+ static_cast<FGFlightHistory*>(globals->get_subsystem("history"));
+
+ double minEdgeLengthM = 50;
+ string requestPath = request.Uri.substr(getUri().length());
+
+ if (request.Method == "GET") {
+ } else if (request.Method == "POST") {
+ /*
+ * {
+ * sampleIntervalSec: (number),
+ * maxMemoryUseBytes: (number),
+ * clearOnTakeoff: (bool),
+ * enabled: (bool),
+ * }
+ */
+ cJSON * json = cJSON_Parse(request.Content.c_str());
+ if ( NULL != json) {
+ double d = .0;
+ bool b = false;
+ bool doReinit = false;
+ if (GetJsonDouble(json, "sampleIntervalSec", d)) {
+ fgSetDouble("/sim/history/sample-interval-sec", d);
+ doReinit = true;
+ }
+ if (GetJsonDouble(json, "maxMemoryUseBytes", d)) {
+ fgSetDouble("/sim/history/max-memory-use-bytes", d);
+ doReinit = true;
+ }
+
+ if (GetJsonBool(json, "clearOnTakeoff", b)) {
+ fgSetBool("/sim/history/clear-on-takeoff", b);
+ doReinit = true;
+ }
+ if (GetJsonBool(json, "enabled", b)) {
+ fgSetBool("/sim/history/enabled", b);
+ }
+
+ if (doReinit) {
+ history->reinit();
+ }
+
+ cJSON_Delete(json);
+ }
+
+ response.Content = "{}";
+ return true;
+
+ } else {
+ SG_LOG(SG_NETWORK, SG_INFO,
+ "PkgUriHandler: invalid request method '" << request.Method << "'");
+ response.Header["Allow"] = "OPTIONS, GET, POST";
+ response.StatusCode = 405;
+ response.Content = "{}";
+ return true;
+ }
+
+ if (requestPath == "track.kml") {
+ response.Header["Content-Type"] =
+ "application/vnd.google-earth.kml+xml; charset=UTF-8";
+
+ response.Content = FlightHistoryToKml(
+ history->pathForHistory(minEdgeLengthM), request);
+
+ } else if (requestPath == "track.json") {
+ response.Header["Content-Type"] = "application/json; charset=UTF-8";
+ response.Content = FlightHistoryToJson(
+ history->pathForHistory(minEdgeLengthM));
+
+ } else {
+ response.StatusCode = 404;
+ response.Content = "{}";
+ }
+
+ return true;
+}
+
+} // namespace http
+} // namespace flightgear
+
#include "PropertyUriHandler.hxx"
+#include "SimpleDOM.hxx"
#include <Main/fg_props.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/strutils.hxx>
return reply;
}
-class DOMElement {
-public:
- virtual ~DOMElement() {}
- virtual std::string render() const = 0;
-};
-
-class DOMTextElement : public DOMElement {
-public:
- DOMTextElement( const string & text ) : _text(text) {}
- virtual std::string render() const { return _text; }
-
-private:
- string _text;
-};
-
-
-class DOMNode : public DOMElement {
-public:
- DOMNode( const string & name ) : _name(name) {}
- virtual ~DOMNode();
-
- virtual std::string render() const;
- virtual DOMNode * addChild( DOMElement * child );
- virtual DOMNode * setAttribute( const string & name, const string & value );
-protected:
- string _name;
- typedef vector<const DOMElement*> Children_t;
- typedef map<string,string> Attributes_t;
- Children_t _children;
- Attributes_t _attributes;
-};
-
-DOMNode::~DOMNode()
-{
- for( Children_t::const_iterator it = _children.begin(); it != _children.end(); ++it )
- delete *it;
-}
-
-string DOMNode::render() const
-{
- string reply;
- reply.append( "<" ).append( _name );
- for( Attributes_t::const_iterator it = _attributes.begin(); it != _attributes.end(); ++it ) {
- reply.append( " " );
- reply.append( it->first );
- reply.append( "=\"" );
- reply.append( it->second );
- reply.append( "\"" );
- }
-
- if( _children.empty() ) {
- reply.append( " />\r" );
- return reply;
- } else {
- reply.append( ">" );
- }
-
- for( Children_t::const_iterator it = _children.begin(); it != _children.end(); ++it ) {
- reply.append( (*it)->render() );
- }
-
- reply.append( "</" ).append( _name ).append( ">\r" );
-
- return reply;
-}
-
-DOMNode * DOMNode::addChild( DOMElement * child )
-{
- _children.push_back( child );
- return dynamic_cast<DOMNode*>(child);
-}
-
-DOMNode * DOMNode::setAttribute( const string & name, const string & value )
-{
- _attributes[name] = value;
- return this;
-}
-
class SortedChilds : public simgear::PropertyList {
public:
SortedChilds( SGPropertyNode_ptr node ) {
--- /dev/null
+// SimpleDOM.hxx -- poor man's DOM
+//
+// Written by Torsten Dreyer
+//
+// Copyright (C) 2014 Torsten Dreyer
+//
+// 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_SIMPLE_DOM_HXX
+#define __FG_SIMPLE_DOM_HXX
+
+#include <string>
+#include <map>
+#include <vector>
+
+namespace flightgear {
+namespace http {
+
+class DOMElement {
+public:
+ virtual ~DOMElement() {}
+ virtual std::string render() const = 0;
+};
+
+class DOMTextElement : public DOMElement {
+public:
+ DOMTextElement( const std::string & text ) : _text(text) {}
+ virtual std::string render() const { return _text; }
+
+private:
+ std::string _text;
+};
+
+class DOMNode : public DOMElement {
+public:
+ DOMNode( const std::string & name ) : _name(name) {}
+ virtual ~DOMNode();
+
+ virtual std::string render() const;
+ virtual DOMNode * addChild( DOMElement * child );
+ virtual DOMNode * setAttribute( const std::string & name, const std::string & value );
+protected:
+ std::string _name;
+ typedef std::vector<const DOMElement*> Children_t;
+ typedef std::map<std::string,std::string> Attributes_t;
+ Children_t _children;
+ Attributes_t _attributes;
+};
+
+}
+}
+#endif // __FG_SIMPLE_DOM_HXX