1 // PkgUriHandler.cxx -- service for the package system
2 //
3 // Written by Torsten Dreyer, started February 2015.
4 //
5 // Copyright (C) 2014  Torsten Dreyer
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 
22 #include "PkgUriHandler.hxx"
23 #include <3rdparty/cjson/cJSON.h>
24 
25 #include <simgear/package/Root.hxx>
26 #include <simgear/package/Catalog.hxx>
27 #include <simgear/package/Delegate.hxx>
28 #include <simgear/package/Install.hxx>
29 #include <simgear/package/Package.hxx>
30 
31 #include <Main/fg_props.hxx>
32 
33 using std::string;
34 
35 namespace flightgear {
36 namespace http {
37 
38 /*
39 url: /pkg/command/args
40 
41 Examples:
42 /pkg/path
43 
44 Input:
45 {
46   command: "command",
47   args: {
48   }
49 }
50 
51 Output:
52 {
53 }
54 */
55 
StringListToJson(const string_list & l)56 static cJSON * StringListToJson( const string_list & l )
57 {
58   cJSON * jsonArray = cJSON_CreateArray();
59   for( string_list::const_iterator it = l.begin(); it != l.end(); ++it )
60       cJSON_AddItemToArray(jsonArray, cJSON_CreateString((*it).c_str()) );
61   return jsonArray;
62 }
63 
PackageToJson(simgear::pkg::Package * p)64 static cJSON * PackageToJson( simgear::pkg::Package * p )
65 {
66   cJSON * json = cJSON_CreateObject();
67   if( p ) {
68     cJSON_AddItemToObject(json, "id", cJSON_CreateString( p->id().c_str() ));
69     cJSON_AddItemToObject(json, "name", cJSON_CreateString( p->name().c_str() ));
70     cJSON_AddItemToObject(json, "description", cJSON_CreateString( p->description().c_str() ));
71     cJSON_AddItemToObject(json, "installed", cJSON_CreateBool( p->isInstalled() ));
72     cJSON_AddItemToObject(json, "thumbnails", StringListToJson( p->thumbnailUrls() ));
73     cJSON_AddItemToObject(json, "variants", StringListToJson( p->variants() ));
74     cJSON_AddItemToObject(json, "revision", cJSON_CreateNumber( p->revision() ));
75     cJSON_AddItemToObject(json, "fileSize", cJSON_CreateNumber( p->fileSizeBytes() ));
76     cJSON_AddItemToObject(json, "author", cJSON_CreateString( p->getLocalisedProp("author").c_str() ));
77     cJSON_AddItemToObject(json, "ratingFdm", cJSON_CreateString( p->getLocalisedProp("rating/FDM").c_str() ));
78     cJSON_AddItemToObject(json, "ratingCockpit", cJSON_CreateString( p->getLocalisedProp("rating/cockpit").c_str() ));
79     cJSON_AddItemToObject(json, "ratingModel", cJSON_CreateString( p->getLocalisedProp("rating/model").c_str() ));
80     cJSON_AddItemToObject(json, "ratingSystems", cJSON_CreateString( p->getLocalisedProp("rating/systems").c_str() ));
81   }
82   return json;
83 }
84 
PackageListToJson(const simgear::pkg::PackageList & l)85 static cJSON * PackageListToJson( const simgear::pkg::PackageList & l )
86 {
87   cJSON * jsonArray = cJSON_CreateArray();
88   for( simgear::pkg::PackageList::const_iterator it = l.begin(); it != l.end(); ++it ) {
89     cJSON_AddItemToArray(jsonArray, PackageToJson(*it) );
90   }
91   return jsonArray;
92 }
93 
CatalogToJson(simgear::pkg::Catalog * c)94 static cJSON * CatalogToJson( simgear::pkg::Catalog * c )
95 {
96   cJSON * json = cJSON_CreateObject();
97   if( c ) {
98     cJSON_AddItemToObject(json, "id", cJSON_CreateString( c->id().c_str() ));
99     std::string s = c->installRoot().utf8Str();
100     cJSON_AddItemToObject(json, "installRoot", cJSON_CreateString( s.c_str() ));
101     cJSON_AddItemToObject(json, "url", cJSON_CreateString( c->url().c_str() ));
102     cJSON_AddItemToObject(json, "description", cJSON_CreateString( c->description().c_str() ));
103     cJSON_AddItemToObject(json, "packages", PackageListToJson(c->packages()) );
104     cJSON_AddItemToObject(json, "needingUpdate", PackageListToJson(c->packagesNeedingUpdate()) );
105     cJSON_AddItemToObject(json, "installed", PackageListToJson(c->installedPackages()) );
106   }
107   return json;
108 }
109 
110 
PackageRootCommand(simgear::pkg::Root * packageRoot,const string & command,const string & args)111 static string PackageRootCommand( simgear::pkg::Root* packageRoot, const string & command, const string & args )
112 {
113   cJSON * json = cJSON_CreateObject();
114 
115   if( command == "path" ) {
116     std::string p = packageRoot->path().utf8Str();
117     cJSON_AddItemToObject(json, "path", cJSON_CreateString( p.c_str() ));
118 
119   } else if( command == "version" ) {
120 
121     cJSON_AddItemToObject(json, "version", cJSON_CreateString( packageRoot->applicationVersion().c_str() ));
122 
123   } else if( command == "refresh" ) {
124     packageRoot->refresh(true);
125     cJSON_AddItemToObject(json, "refresh", cJSON_CreateString( "OK" ));
126 
127   } else if( command == "catalogs" ) {
128 
129     cJSON * jsonArray = cJSON_CreateArray();
130     simgear::pkg::CatalogList catalogList = packageRoot->catalogs();
131     for( simgear::pkg::CatalogList::iterator it = catalogList.begin(); it != catalogList.end(); ++it ) {
132       cJSON_AddItemToArray(jsonArray, CatalogToJson(*it) );
133     }
134     cJSON_AddItemToObject(json, "catalogs", jsonArray );
135 
136   } else if( command == "packageById" ) {
137 
138     simgear::pkg::PackageRef p = packageRoot->getPackageById(args);
139     cJSON_AddItemToObject(json, "package", PackageToJson( p ));
140 
141   } else if( command == "catalogById" ) {
142 
143     simgear::pkg::CatalogRef p = packageRoot->getCatalogById(args);
144     cJSON_AddItemToObject(json, "catalog", CatalogToJson( p ));
145 
146   } else if( command == "search" ) {
147 
148     SGPropertyNode_ptr query(new SGPropertyNode);
149     simgear::pkg::PackageList packageList = packageRoot->packagesMatching(query);
150     cJSON_AddItemToObject(json, "packages", PackageListToJson(packageList) );
151 
152   } else if( command == "install" ) {
153 
154 	  simgear::pkg::PackageRef package = packageRoot->getPackageById(args);
155 	  if( NULL == package ) {
156 		  SG_LOG(SG_NETWORK,SG_WARN,"Can't install package '" << args << "', package not found" );
157 		    cJSON_Delete( json );
158 		    return string("");
159 	  }
160 	  package->existingInstall();
161 
162   } else {
163     SG_LOG( SG_NETWORK,SG_WARN, "Unhandled pkg command : '" << command << "'" );
164     cJSON_Delete( json );
165     return string("");
166   }
167 
168   char * jsonString = cJSON_PrintUnformatted( json );
169   string reply(jsonString);
170   free( jsonString );
171   cJSON_Delete( json );
172   return reply;
173 }
174 
findCommand(const string & uri,string & outArgs)175 static  string findCommand( const string & uri, string & outArgs )
176 {
177   size_t n = uri.find_first_of('/');
178   if( n == string::npos ) outArgs = string("");
179   else outArgs = uri.substr( n+1 );
180   return uri.substr( 0, n );
181 }
182 
handleRequest(const HTTPRequest & request,HTTPResponse & response,Connection * connection)183 bool PkgUriHandler::handleRequest( const HTTPRequest & request, HTTPResponse & response, Connection * connection )
184 {
185   response.Header["Content-Type"] = "application/json; charset=UTF-8";
186   response.Header["Access-Control-Allow-Origin"] = "*";
187   response.Header["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST";
188   response.Header["Access-Control-Allow-Headers"] = "Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token";
189 
190   if( request.Method == "OPTIONS" ){
191       return true; // OPTIONS only needs the headers
192   }
193 
194   simgear::pkg::Root* packageRoot = globals->packageRoot();
195   if( NULL == packageRoot ) {
196     SG_LOG( SG_NETWORK,SG_WARN, "NO PackageRoot" );
197     response.StatusCode = 500;
198     response.Content = "{}";
199     return true;
200   }
201 
202   string argString;
203   string command = findCommand( string(request.Uri).substr(getUri().size()), argString );
204 
205 
206   SG_LOG(SG_NETWORK,SG_INFO, "Request is for command '"  << command << "' with arg='" << argString << "'" );
207 
208   if( request.Method == "GET" ){
209   } else if( request.Method == "POST" ) {
210   } else {
211     SG_LOG(SG_NETWORK,SG_INFO, "PkgUriHandler: invalid request method '" << request.Method << "'" );
212     response.Header["Allow"] = "OPTIONS, GET, POST";
213     response.StatusCode = 405;
214     response.Content = "{}";
215     return true;
216   }
217 
218   response.Content = PackageRootCommand( packageRoot, command, argString );
219   if( response.Content.empty() ) {
220     response.StatusCode = 404;
221     response.Content = "{}";
222   }
223   return true;
224 }
225 
226 } // namespace http
227 } // namespace flightgear
228 
229