Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User directory config files #534

Merged
merged 10 commits into from
May 1, 2017
19 changes: 12 additions & 7 deletions apps/osvr_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <osvr/Server/RegisterShutdownHandler.h>
#include <osvr/Util/Logger.h>
#include <osvr/Util/LogNames.h>
#include <osvr/Server/ConfigFilePaths.h>

// Library/third-party includes
// - none
Expand All @@ -36,6 +37,7 @@
#include <exception>
#include <fstream>
#include <iostream>
#include <vector>

static osvr::server::ServerPtr server;
using ::osvr::util::log::OSVR_SERVER_LOG;
Expand All @@ -49,17 +51,20 @@ void handleShutdown() {

int main(int argc, char *argv[]) {
auto log = ::osvr::util::log::make_logger(OSVR_SERVER_LOG);

std::string configName(osvr::server::getDefaultConfigFilename());
std::vector<std::string> configPaths;
if (argc > 1) {
configName = argv[1];
configPaths = {std::string(argv[1])};
} else {
log->info()
<< "Using default config file - pass a filename on the command "
"line to use a different one.";
log->info() << "Using default config files - pass a filename on the command "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the word "files" here a typo?

"line to use a different one.";
configPaths = osvr::server::getDefaultConfigFilePaths();
}

server = osvr::server::configureServerFromFile(configName);
server = osvr::server::configureServerFromFirstFileInList(configPaths);
if (!server) {
log->info() << "Using default config data.";
server = osvr::server::configureServerFromFile("");
}
if (!server) {
return -1;
}
Expand Down
44 changes: 44 additions & 0 deletions inc/osvr/Server/ConfigFilePaths.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/** @file
@brief Auto-generated configuration header - do not edit!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This header file isn't auto-generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the comment


@date 2015

@author
Sensics, Inc.
<http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, Inc.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this 2015 code?

//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef INCLUDED_ConfigFilePaths_h_GUID_241E9C9C_0E0E_46B0_9DED_8F8059306192
#define INCLUDED_ConfigFilePaths_h_GUID_241E9C9C_0E0E_46B0_9DED_8F8059306192

// Internal Includes
#include <osvr/Server/Export.h>

// Library/third-party includes
// - none

// Standard includes
#include <vector>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget #include <string>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

namespace osvr {
namespace server {

/// @brief this returns a vector of default server configuration file paths.
OSVR_SERVER_EXPORT std::vector<std::string> getDefaultConfigFilePaths();
}
}
#endif // INCLUDED_ConfigFilePaths_h_GUID_241E9C9C_0E0E_46B0_9DED_8F8059306192
114 changes: 12 additions & 102 deletions inc/osvr/Server/ConfigureServerFromFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,118 +38,28 @@
#include <exception>
#include <fstream>
#include <iostream>
#include <vector>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need #include <string>. And it looks like you can ditch iostream and fstream and exception (move 'em to the .cpp file). Same with the Log headers above.

namespace osvr {
namespace server {

inline const char *getDefaultConfigFilename() {
return "osvr_server_config.json";
}

/// @brief This is the basic common code of a server app's setup, ripped out
/// @brief This uses a file name to attempt to configure the server with
/// that config file.
/// Pass an empty string to use the default config.
/// This is the basic common code of a server app's setup, ripped out
/// of the main server app to make alternate server-acting apps simpler to
/// develop.
inline ServerPtr configureServerFromFile(std::string const &configName) {
auto log =
::osvr::util::log::make_logger(::osvr::util::log::OSVR_SERVER_LOG);

ServerPtr ret;
log->info() << "Using config file '" << configName << "'.";
std::ifstream config(configName);
if (!config.good()) {
log->error() << "Could not open config file!";
log->error() << "Searched in the current directory; file may be "
"misspelled, missing, or in a different directory.";
return nullptr;
}

osvr::server::ConfigureServer srvConfig;
log->info() << "Constructing server as configured...";
try {
srvConfig.loadConfig(config);
ret = srvConfig.constructServer();
} catch (std::exception &e) {
log->error()
<< "Caught exception constructing server from JSON config "
"file: "
<< e.what();
return nullptr;
}

{
log->info() << "Loading auto-loadable plugins...";
srvConfig.loadAutoPlugins();
}

{
log->info() << "Loading plugins...";
srvConfig.loadPlugins();
if (!srvConfig.getSuccessfulPlugins().empty()) {
log->info() << "Successfully loaded the following plugins:";
for (auto const &plugin : srvConfig.getSuccessfulPlugins()) {
log->info() << " - " << plugin;
}
}
if (!srvConfig.getFailedPlugins().empty()) {
log->warn() << "Failed to load the following plugins:";
for (auto const &pluginError : srvConfig.getFailedPlugins()) {
log->warn() << " - " << pluginError.first << "\t"
<< pluginError.second;
}
}
}

{
log->info() << "Instantiating configured drivers...";
bool success = srvConfig.instantiateDrivers();
if (!srvConfig.getSuccessfulInstantiations().empty()) {
log->info() << "Successes:";
for (auto const &driver :
srvConfig.getSuccessfulInstantiations()) {
log->info() << " - " << driver;
}
}
if (!srvConfig.getFailedInstantiations().empty()) {
log->error() << "Errors:";
for (auto const &error : srvConfig.getFailedInstantiations()) {
log->error() << " - " << error.first << "\t"
<< error.second;
}
}
}

if (srvConfig.processExternalDevices()) {
log->info()
<< "External devices found and parsed from config file.";
}
OSVR_SERVER_EXPORT ServerPtr configureServerFromFile(std::string const &configName);

if (srvConfig.processRoutes()) {
log->info() << "Routes found and parsed from config file.";
}

if (srvConfig.processAliases()) {
log->info() << "Aliases found and parsed from config file.";
}

if (srvConfig.processDisplay()) {
log->info()
<< "Display descriptor found and parsed from config file.";
} else {
log->info()
<< "Using OSVR HDK for display configuration. "
"Did not find an alternate valid 'display' object in config "
"file.";
}

if (srvConfig.processRenderManagerParameters()) {
log->info() << "RenderManager config found and parsed from the "
"config file.";
}

log->info() << "Triggering automatic hardware detection...";
ret->triggerHardwareDetect();

return ret;
}
/// @brief This iterates over a vector that contains a list of potential
/// config files, and uses the first working one to create the server
/// instance.
OSVR_SERVER_EXPORT ServerPtr configureServerFromFirstFileInList(
std::vector<std::string> const &configNames);

} // namespace server
} // namespace osvr
Expand Down
3 changes: 3 additions & 0 deletions src/osvr/Server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ osvr_setup_lib_vars(Server)

set(API
"${HEADER_LOCATION}/ConfigureServer.h"
"${HEADER_LOCATION}/ConfigFilePaths.h"
"${HEADER_LOCATION}/ConfigureServerFromFile.h"
"${HEADER_LOCATION}/Server.h"
"${HEADER_LOCATION}/ServerPtr.h"
Expand All @@ -11,6 +12,8 @@ set(API

set(SOURCE
ConfigureServer.cpp
ConfigFilePaths.cpp
ConfigureServerFromFile.cpp
JSONResolvePossibleRef.h
JSONResolvePossibleRef.cpp
Server.cpp
Expand Down
79 changes: 79 additions & 0 deletions src/osvr/Server/ConfigFilePaths.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Internal Includes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add standard copyright header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

date and indentation don't match but...

#include <osvr/Util/PlatformConfig.h>
#include <osvr/Server/ConfigFilePaths.h>
#include <osvr/Server/ConfigureServerFromFile.h>
#include <osvr/Util/GetEnvironmentVariable.h>

// Library/third-party includes
#include <boost/filesystem.hpp>

// Standard includes
#include <vector>

namespace osvr {
namespace server {

inline std::string getUserConfigDirectory() {
namespace fs = boost::filesystem;
using osvr::util::getEnvironmentVariable;

fs::path configDir;
std::string configSubpath = "config";

#if defined(OSVR_LINUX)
// There's currently no great location for storing log files in the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can delete the first paragraph of the comment and update the second para to reflect XDG_CONFIG_HOME.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

// XDG system. (See the STATE proposal by Debian
// <https://wiki.debian.org/XDGBaseDirectorySpecification#Proposal:_STATE_directory>.)
// So for now, we'll store our log files in the $XDG_CACHE_HOME
// directory.
//
// $XDG_CACHE_HOME defines the base directory relative to which user
// specific non-essential data files should be stored. If
// $XDG_CACHE_HOME is either not set or empty, a default equal to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/XDG_CACHE_HOME/XDG_CONFIG_HOME/

// $HOME/.cache should be used.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/cache/config/g throughout, I think.

auto xdg_cache_dir = getEnvironmentVariable("XDG_CONFIG_HOME");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Linux, if you're searching for an existing configuration file (as opposed to determining where to write a new one), then you will want to check the XDG_CONFIG_DIRS paths as well. From the XDG Base Directory Specification:

$XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for configuration files in addition to the $XDG_CONFIG_HOME base directory. The directories in $XDG_CONFIG_DIRS should be separated with a colon :.

If $XDG_CONFIG_DIRS is either not set or empty, a value equal to /etc/xdg should be used.

The order of base directories denotes their importance; the first directory listed is the most important. When the same information is defined in multiple places the information defined relative to the more important base directory takes precedent. [...] The base directory defined by $XDG_CONFIG_HOME is considered more important than any of the base directories defined by $XDG_CONFIG_DIRS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to put this as a TODO for now. The function this is in currently only returns one directory, and this change would require it to return multiple directories.

if (xdg_cache_dir) {
configDir = *xdg_cache_dir;
}
else {
auto home_dir = getEnvironmentVariable("HOME");
configDir = fs::path(*home_dir) / ".config";
}
configDir /= fs::path("osvr");
#elif defined(OSVR_MACOSX)
auto home_dir = getEnvironmentVariable("HOME");
if (home_dir) {
configDir = *home_dir;
}
configDir /= "Library" / fs::path("Application Support") / fs::path("OSVR") / configSubpath;
#elif defined(OSVR_WINDOWS)
/// @todo there's actually a win32 api call to get localappdata
/// that's preferred to the env var.
auto local_app_dir = getEnvironmentVariable("LocalAppData");
if (local_app_dir) {
configDir = *local_app_dir;
}
else {
configDir = "c:/";
}
configDir /= fs::path("OSVR") / configSubpath;
#endif

return configDir.string();
}

std::vector<std::string> getDefaultConfigFilePaths() {
namespace fs = boost::filesystem;
std::vector<std::string> names;
std::string configFileName = getDefaultConfigFilename();

fs::path userConfigDirectory(getUserConfigDirectory());
auto userConfig = userConfigDirectory / configFileName;

names.push_back(userConfig.string());
names.push_back(configFileName);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are more places worth checking, too.

On Linux:

  • $XDG_CONFIG_HOME/osvr/osvr_server_config.json
  • For each colon-separated dir in $XDG_CONFIG_DIRS: $prefix/osvr/osvr_server_config.json
  • /etc/xdg if $XDG_CONFIG_DIRS is not set or empty.
  • /etc/osvr_server_config.json for old-school paths
  • /usr/local/etc/osvr_server_config.json for old-school paths

On macOS:

  • $HOME/Library/Application Support/OSVR/config/osvr_server_config.json
  • /Library/Application Support/OSVR/config/osvr_server_config.json
  • wherever brew installs it by default (I think /usr/local/Cellar/osvr-core/bin/osvr_server_config.json, maybe)
  • /etc/osvr_server_config.json for old-school paths
  • /usr/local/etc/osvr_server_config.json for old-school paths

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to new issue: #537

return names;
}
}
}
17 changes: 0 additions & 17 deletions src/osvr/Server/ConfigureServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,6 @@

namespace osvr {
namespace server {
namespace detail {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, wow! This is ancient. I thought we killed it ages ago.

class StreamPrefixer {
public:
StreamPrefixer(const char *prefix, std::ostream &os)
: m_prefix(prefix), m_os(&os) {}
template <typename T> std::ostream &operator<<(T val) {
return (*m_os) << m_prefix << val;
}

private:
const char *m_prefix;
std::ostream *m_os;
};

static detail::StreamPrefixer out("[OSVR Server] ", std::cout);
static detail::StreamPrefixer err("[OSVR Server] ", std::cerr);
} // namespace detail

inline void
printJsonReferenceResolutionAttempts(ResolveRefResult const &refReturn) {
Expand Down
Loading