34 #include <json/value.h>
35 #include <json/reader.h>
36 #include <boost/optional.hpp>
37 #include <boost/lexical_cast.hpp>
38 #include <boost/filesystem.hpp>
39 #include <boost/algorithm/string/predicate.hpp>
46 #undef OSVR_JSON_RESOLUTION_VERBOSE
52 printJsonReferenceResolutionAttempts(ResolveRefResult
const &refReturn) {
53 for (
auto &attempt : refReturn.fileAttempts) {
54 OSVR_DEV_VERBOSE(
"Tried loading "
55 << attempt.path <<
": "
56 << fileLoadStatusToString(attempt.status)
62 reportErrorInJsonReferenceParsing(
const char *description,
63 Json::Value
const &input,
64 ResolveRefResult
const &refReturn) {
65 OSVR_DEV_VERBOSE(
"ERROR: Could not load "
67 <<
" specified by: " << input.toStyledString());
68 printJsonReferenceResolutionAttempts(refReturn);
73 template <
typename T>
inline void parse(T &json) {
75 bool parsingSuccessful = reader.parse(json, root);
76 if (!parsingSuccessful) {
77 throw std::runtime_error(
"Error in parsing JSON: " +
78 reader.getFormattedErrorMessages());
82 Json::Value
const &getMember(
const char *memberName)
const {
83 return root[memberName];
102 static const char SERVER_KEY[] =
"server";
103 static const char INTERFACE_KEY[] =
"interface";
104 static const char LOCAL_KEY[] =
"local";
105 static const char PORT_KEY[] =
"port";
106 static const char SLEEP_KEY[] =
"sleep";
109 Json::Value
const &root(m_data->root);
112 boost::optional<int> port;
116 int sleepTime = 1000;
120 if (root.isMember(SERVER_KEY)) {
122 Json::Value jsonServer = root[SERVER_KEY];
123 Json::Value jsonInterface = jsonServer[INTERFACE_KEY];
124 Json::Value jsonLocal = jsonServer[LOCAL_KEY];
125 if (jsonInterface.isString()) {
127 iface = jsonInterface.asString();
128 }
else if (jsonLocal.isBool()) {
129 local = jsonLocal.asBool();
132 Json::Value jsonPort = jsonServer[PORT_KEY];
133 if (jsonPort.isInt()) {
134 int myPort = jsonPort.asInt();
136 throw std::out_of_range(
"Invalid port value: must be >= 1 "
137 "and for a non-admin execution, "
143 Json::Value jsonSleepTime = jsonServer[SLEEP_KEY];
144 if (jsonSleepTime.isDouble()) {
147 sleepTime =
static_cast<int>(jsonSleepTime.asDouble() * 1000.0);
153 if (local && !port) {
158 boost::optional<std::string> host;
159 if (!iface.empty()) {
165 if (sleepTime > 0.0) {
166 m_server->setSleepTime(sleepTime);
169 m_server->setHardwareDetectOnConnection();
174 static const char PLUGINS_KEY[] =
"plugins";
176 Json::Value
const &root(m_data->root);
177 const Json::Value plugins = root[PLUGINS_KEY];
179 for (Json::ArrayIndex i = 0, e = plugins.size(); i < e; ++i) {
180 if (!plugins[i].isString()) {
182 m_failedPlugins.push_back(std::make_pair(
183 "Plugin entry " + boost::lexical_cast<std::string>(i),
184 "Plugin name not string: " + plugins[i].toStyledString()));
189 const std::string plugin = plugins[i].asString();
191 m_server->loadPlugin(plugin);
192 m_successfulPlugins.push_back(plugin);
193 }
catch (std::exception &e) {
194 m_failedPlugins.push_back(std::make_pair(plugin, e.what()));
202 ConfigureServer::getSuccessfulPlugins()
const {
203 return m_successfulPlugins;
208 return m_failedPlugins;
211 static const char DRIVERS_KEY[] =
"drivers";
212 static const char DRIVER_KEY[] =
"driver";
213 static const char PLUGIN_KEY[] =
"plugin";
214 static const char PARAMS_KEY[] =
"params";
217 Json::Value
const &root(m_data->root);
218 Json::Value
const &drivers = root[DRIVERS_KEY];
219 for (
auto const &thisDriver : drivers) {
220 const bool hasPlugin = thisDriver[PLUGIN_KEY].isString();
221 const bool hasDriver = thisDriver[DRIVER_KEY].isString();
222 if (!hasPlugin && !hasDriver) {
224 m_failedInstances.push_back(std::make_pair(
225 "?",
"Entry present in drivers but lacking both a driver "
226 "name and a plugin name"));
232 m_failedInstances.push_back(
233 std::make_pair(
"?/" + thisDriver[DRIVER_KEY].asString(),
234 "Entry present in drivers with a driver "
235 "name but lacking a plugin name"));
240 const std::string plugin = thisDriver[PLUGIN_KEY].asString();
244 m_failedInstances.push_back(std::make_pair(
245 plugin +
"/?",
"Entry present in drivers with a plugin "
246 "name but lacking a driver name"));
251 const std::string driver = thisDriver[DRIVER_KEY].asString();
254 m_server->instantiateDriver(
255 plugin, driver, thisDriver[PARAMS_KEY].toStyledString());
257 m_successfulInstances.push_back(plugin +
"/" + driver);
258 }
catch (std::exception &e) {
259 m_failedInstances.push_back(
260 std::make_pair(plugin +
"/" + driver, e.what()));
268 ConfigureServer::getSuccessfulInstantiations()
const {
269 return m_successfulInstances;
274 return m_failedInstances;
277 static const char ROUTES_KEY[] =
"routes";
278 bool ConfigureServer::processRoutes() {
279 bool success =
false;
280 Json::Value
const &routes = m_data->getMember(ROUTES_KEY);
281 if (routes.isNull()) {
284 for (Json::ArrayIndex i = 0, e = routes.size(); i < e; ++i) {
285 const Json::Value thisRoute = routes[i];
286 m_server->addRoute(thisRoute.toStyledString());
292 static const char ALIASES_KEY[] =
"aliases";
293 bool ConfigureServer::processAliases() {
294 bool success =
false;
295 Json::Value
const &aliases = m_data->getMember(ALIASES_KEY);
296 if (aliases.isNull()) {
299 success = m_server->addAliases(aliases);
303 static const char EXTERNALDEVICES_KEY[] =
"externalDevices";
304 static const char DEVICENAME_KEY[] =
"deviceName";
305 static const char DESCRIPTOR_KEY[] =
"descriptor";
307 bool success =
false;
308 Json::Value
const &devices = m_data->getMember(EXTERNALDEVICES_KEY);
309 if (devices.isNull()) {
312 for (
auto const &devPath : devices.getMemberNames()) {
313 auto const &dev = devices[devPath];
314 auto const &devName = dev[DEVICENAME_KEY];
315 auto const &server = dev[SERVER_KEY];
317 if (devName.isNull()) {
319 "Missing 'deviceName' for external device entry of "
320 << devPath <<
" : " << dev.toStyledString());
323 if (server.isNull()) {
325 "Missing 'server' for external device entry of "
326 << devPath <<
" : " << dev.toStyledString());
330 if (descriptor.isNull()) {
331 OSVR_DEV_VERBOSE(
"Missing 'descriptor' file or object for "
332 "external device entry of "
333 << devPath <<
" : " << dev.toStyledString());
337 m_server->addExternalDevice(devPath, devName.asString(),
339 descriptor.toStyledString());
345 static const char DISPLAY_KEY[] =
"display";
346 static const char DISPLAY_PATH[] =
"/display";
348 bool success =
false;
349 Json::Value
const &display = m_data->getMember(DISPLAY_KEY);
350 if (display.isNull()) {
356 if (refReturn.result.isNull()) {
357 reportErrorInJsonReferenceParsing(
358 "an object or display descriptor file", display, refReturn);
362 #ifdef OSVR_JSON_RESOLUTION_VERBOSE
363 printJsonReferenceResolutionAttempts(refReturn);
368 success = m_server->addString(DISPLAY_PATH,
369 refReturn.result.toStyledString());
373 static const char RENDERMANAGER_KEY[] =
"renderManagerConfig";
374 static const char RENDERMANAGER_PATH[] =
"/renderManagerConfig";
376 bool success =
false;
377 Json::Value
const &renderManager = m_data->getMember(RENDERMANAGER_KEY);
378 if (renderManager.isNull()) {
384 if (refReturn.result.isNull()) {
385 reportErrorInJsonReferenceParsing(
386 "an object or RenderManager config file", renderManager,
391 #ifdef OSVR_JSON_RESOLUTION_VERBOSE
392 printJsonReferenceResolutionAttempts(refReturn);
397 success = m_server->addString(RENDERMANAGER_PATH,
398 refReturn.result.toStyledString());
static ConnectionPtr createSharedConnection(boost::optional< std::string const & > iface, boost::optional< int > port)
Factory method to create a shared connection.
shared_ptr< Connection > ConnectionPtr
How one must hold a Connection.
Header declaring osvr::server::Server.
static OSVR_SERVER_EXPORT ServerPtr create(connection::ConnectionPtr const &conn)
Create a server object with a provided connection.
Json::Value resolvePossibleRef(Json::Value const &input, bool stringAcceptableResult, std::vector< std::string > const &searchPath)
Given an input that might be a filename, might be a JSON Pointer-style $ref object, and might just directly be an object, return the object desired.
ResolveRefResult resolvePossibleRefWithDetails(Json::Value const &input, bool stringAcceptableResult, std::vector< std::string > const &searchPath)
shared_ptr< Server > ServerPtr
How one should hold a Server.
Internal, configured header file for verbosity macros.
static OSVR_SERVER_EXPORT ServerPtr createLocal()
Create a server object with a local-only (but still IP-based) connection.