diff --git a/src/Network/HTTPClient.cxx b/src/Network/HTTPClient.cxx index de6a3d11f..cda73102f 100644 --- a/src/Network/HTTPClient.cxx +++ b/src/Network/HTTPClient.cxx @@ -146,7 +146,7 @@ void FGHTTPClient::init() // always show this message SG_LOG(SG_GENERAL, SG_ALERT, "default catalog not found, installing..."); pkg::Catalog::createFromUrl(packageRoot, - "http://fgfs.goneabitbursar.com/pkg/" FLIGHTGEAR_VERSION "/default-catalog.xml"); + "http://localhost:8080/default-catalog.xml"); } // start a refresh now diff --git a/src/Network/http/CMakeLists.txt b/src/Network/http/CMakeLists.txt index c2e02f865..44078faf1 100644 --- a/src/Network/http/CMakeLists.txt +++ b/src/Network/http/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES ScreenshotUriHandler.cxx PropertyUriHandler.cxx JsonUriHandler.cxx + PkgUriHandler.cxx RunUriHandler.cxx NavdbUriHandler.cxx PropertyChangeWebsocket.cxx @@ -18,6 +19,7 @@ set(HEADERS ScreenshotUriHandler.hxx PropertyUriHandler.hxx JsonUriHandler.hxx + PkgUriHandler.hxx RunUriHandler.hxx NavdbUriHandler.hxx HTTPRequest.hxx diff --git a/src/Network/http/PkgUriHandler.cxx b/src/Network/http/PkgUriHandler.cxx new file mode 100644 index 000000000..7488a7c36 --- /dev/null +++ b/src/Network/http/PkgUriHandler.cxx @@ -0,0 +1,227 @@ +// PkgUriHandler.cxx -- service for the package system +// +// Written by Torsten Dreyer, started February 2015. +// +// 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. + + +#include "PkgUriHandler.hxx" +#include <3rdparty/cjson/cJSON.h> + +#include +#include +#include +#include +#include + +#include
+ +using std::string; + +namespace flightgear { +namespace http { + +/* +url: /pkg/command/args + +Examples: +/pkg/path + +Input: +{ + command: "command", + args: { + } +} + +Output: +{ +} +*/ + +static cJSON * StringListToJson( const string_list & l ) +{ + cJSON * jsonArray = cJSON_CreateArray(); + for( string_list::const_iterator it = l.begin(); it != l.end(); ++it ) + cJSON_AddItemToArray(jsonArray, cJSON_CreateString((*it).c_str()) ); + return jsonArray; +} + +static cJSON * PackageToJson( simgear::pkg::Package * p ) +{ + cJSON * json = cJSON_CreateObject(); + if( p ) { + cJSON_AddItemToObject(json, "id", cJSON_CreateString( p->id().c_str() )); + cJSON_AddItemToObject(json, "name", cJSON_CreateString( p->name().c_str() )); + cJSON_AddItemToObject(json, "description", cJSON_CreateString( p->description().c_str() )); + cJSON_AddItemToObject(json, "installed", cJSON_CreateBool( p->isInstalled() )); + cJSON_AddItemToObject(json, "thumbnails", StringListToJson( p->thumbnailUrls() )); + cJSON_AddItemToObject(json, "variants", StringListToJson( p->variants() )); + cJSON_AddItemToObject(json, "revision", cJSON_CreateNumber( p->revision() )); + cJSON_AddItemToObject(json, "fileSize", cJSON_CreateNumber( p->fileSizeBytes() )); + cJSON_AddItemToObject(json, "author", cJSON_CreateString( p->getLocalisedProp("author").c_str() )); + cJSON_AddItemToObject(json, "ratingFdm", cJSON_CreateString( p->getLocalisedProp("rating/FDM").c_str() )); + cJSON_AddItemToObject(json, "ratingCockpit", cJSON_CreateString( p->getLocalisedProp("rating/cockpit").c_str() )); + cJSON_AddItemToObject(json, "ratingModel", cJSON_CreateString( p->getLocalisedProp("rating/model").c_str() )); + cJSON_AddItemToObject(json, "ratingSystems", cJSON_CreateString( p->getLocalisedProp("rating/systems").c_str() )); + } + return json; +} + +static cJSON * PackageListToJson( const simgear::pkg::PackageList & l ) +{ + cJSON * jsonArray = cJSON_CreateArray(); + for( simgear::pkg::PackageList::const_iterator it = l.begin(); it != l.end(); ++it ) { + cJSON_AddItemToArray(jsonArray, PackageToJson(*it) ); + } + return jsonArray; +} + +static cJSON * CatalogToJson( simgear::pkg::Catalog * c ) +{ + cJSON * json = cJSON_CreateObject(); + if( c ) { + cJSON_AddItemToObject(json, "id", cJSON_CreateString( c->id().c_str() )); + cJSON_AddItemToObject(json, "installRoot", cJSON_CreateString( c->installRoot().str().c_str() )); + cJSON_AddItemToObject(json, "url", cJSON_CreateString( c->url().c_str() )); + cJSON_AddItemToObject(json, "description", cJSON_CreateString( c->description().c_str() )); + cJSON_AddItemToObject(json, "packages", PackageListToJson(c->packages()) ); + cJSON_AddItemToObject(json, "needingUpdate", PackageListToJson(c->packagesNeedingUpdate()) ); + cJSON_AddItemToObject(json, "installed", PackageListToJson(c->installedPackages()) ); + } + return json; +} + + +static string PackageRootCommand( simgear::pkg::Root* packageRoot, const string & command, const string & args ) +{ + cJSON * json = cJSON_CreateObject(); + + if( command == "path" ) { + + cJSON_AddItemToObject(json, "path", cJSON_CreateString( packageRoot->path().str().c_str() )); + + } else if( command == "version" ) { + + cJSON_AddItemToObject(json, "version", cJSON_CreateString( packageRoot->catalogVersion().c_str() )); + + } else if( command == "refresh" ) { + packageRoot->refresh(true); + cJSON_AddItemToObject(json, "refresh", cJSON_CreateString( "OK" )); + + } else if( command == "catalogs" ) { + + cJSON * jsonArray = cJSON_CreateArray(); + simgear::pkg::CatalogList catalogList = packageRoot->catalogs(); + for( simgear::pkg::CatalogList::iterator it = catalogList.begin(); it != catalogList.end(); ++it ) { + cJSON_AddItemToArray(jsonArray, CatalogToJson(*it) ); + } + cJSON_AddItemToObject(json, "catalogs", jsonArray ); + + } else if( command == "packageById" ) { + + simgear::pkg::PackageRef p = packageRoot->getPackageById(args); + cJSON_AddItemToObject(json, "package", PackageToJson( p )); + + } else if( command == "catalogById" ) { + + simgear::pkg::CatalogRef p = packageRoot->getCatalogById(args); + cJSON_AddItemToObject(json, "catalog", CatalogToJson( p )); + + } else if( command == "search" ) { + + SGPropertyNode_ptr query(new SGPropertyNode); + simgear::pkg::PackageList packageList = packageRoot->packagesMatching(query); + cJSON_AddItemToObject(json, "packages", PackageListToJson(packageList) ); + + } else if( command == "install" ) { + + simgear::pkg::PackageRef package = packageRoot->getPackageById(args); + if( NULL == package ) { + SG_LOG(SG_NETWORK,SG_WARN,"Can't install package '" << args << "', package not found" ); + cJSON_Delete( json ); + return string(""); + } + package->existingInstall(); + + } else { + SG_LOG( SG_NETWORK,SG_WARN, "Unhandled pkg command : '" << command << "'" ); + cJSON_Delete( json ); + return string(""); + } + + char * jsonString = cJSON_PrintUnformatted( json ); + string reply(jsonString); + free( jsonString ); + cJSON_Delete( json ); + return reply; +} + +static string findCommand( const string & uri, string & outArgs ) +{ + size_t n = uri.find_first_of('/'); + if( n == string::npos ) outArgs = string(""); + else outArgs = uri.substr( n+1 ); + return uri.substr( 0, n ); +} + +bool PkgUriHandler::handleRequest( const HTTPRequest & request, HTTPResponse & response, Connection * connection ) +{ + response.Header["Content-Type"] = "application/json; charset=UTF-8"; + 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 + } + + simgear::pkg::Root* packageRoot = globals->packageRoot(); + if( NULL == packageRoot ) { + SG_LOG( SG_NETWORK,SG_WARN, "NO PackageRoot" ); + response.StatusCode = 500; + response.Content = "{}"; + return true; + } + + string argString; + string command = findCommand( string(request.Uri).substr(getUri().size()), argString ); + + + SG_LOG(SG_NETWORK,SG_INFO, "Request is for command '" << command << "' with arg='" << argString << "'" ); + + if( request.Method == "GET" ){ + } else if( request.Method == "POST" ) { + } 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; + } + + response.Content = PackageRootCommand( packageRoot, command, argString ); + if( response.Content.empty() ) { + response.StatusCode = 404; + response.Content = "{}"; + } + return true; +} + +} // namespace http +} // namespace flightgear + diff --git a/src/Network/http/PkgUriHandler.hxx b/src/Network/http/PkgUriHandler.hxx new file mode 100644 index 000000000..05d58be8c --- /dev/null +++ b/src/Network/http/PkgUriHandler.hxx @@ -0,0 +1,40 @@ +// PkgUriHandler.hxx -- service for the package system +// +// Written by Torsten Dreyer, started February 2015. +// +// 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_PKG_URI_HANDLER_HXX +#define __FG_PKG_URI_HANDLER_HXX + +#include "urihandler.hxx" +#include + +namespace flightgear { +namespace http { + +class PkgUriHandler : public URIHandler { +public: + PkgUriHandler( const char * uri = "/pkg/" ) : URIHandler( uri ) {} + virtual bool handleRequest( const HTTPRequest & request, HTTPResponse & response, Connection * connection ); +private: +}; + +} // namespace http +} // namespace flightgear + +#endif //#define __FG_PKG_URI_HANDLER_HXX diff --git a/src/Network/http/httpd.cxx b/src/Network/http/httpd.cxx index 38860930d..829acf69a 100644 --- a/src/Network/http/httpd.cxx +++ b/src/Network/http/httpd.cxx @@ -24,6 +24,7 @@ #include "ScreenshotUriHandler.hxx" #include "PropertyUriHandler.hxx" #include "JsonUriHandler.hxx" +#include "PkgUriHandler.hxx" #include "RunUriHandler.hxx" #include "NavdbUriHandler.hxx" #include "PropertyChangeObserver.hxx" @@ -451,6 +452,13 @@ void MongooseHttpd::init() _uriHandler.push_back(new flightgear::http::JsonUriHandler(uri)); } +//#ifdef ENABLE_PACKAGE_SYSTEM + if ((uri = n->getStringValue("pkg"))[0] != 0) { + SG_LOG(SG_NETWORK, SG_INFO, "httpd: adding pkg uri handler at " << uri); + _uriHandler.push_back(new flightgear::http::PkgUriHandler(uri)); + } +//#endif + if ((uri = n->getStringValue("run"))[0] != 0) { SG_LOG(SG_NETWORK, SG_INFO, "httpd: adding run uri handler at " << uri); _uriHandler.push_back(new flightgear::http::RunUriHandler(uri));