Skip to content

Commit 9e3823b

Browse files
committed
Added content based config (string).
1 parent b87173c commit 9e3823b

File tree

4 files changed

+97
-19
lines changed

4 files changed

+97
-19
lines changed

include/lsl/common.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,14 @@ extern LIBLSL_C_API void lsl_destroy_string(char *s);
236236
* is called before the first call to any other LSL function.
237237
*/
238238
extern LIBLSL_C_API void lsl_set_config_filename(const char *filename);
239+
240+
/**
241+
* Set the content of the configuration file to be used.
242+
*
243+
* This is a global setting that will be used by all LSL
244+
* after this function is called. If, and only if, this function
245+
* is called before the first call to any other LSL function.
246+
*
247+
* @note the configuration content is wiped after LSL has initialized.
248+
*/
249+
extern LIBLSL_C_API void lsl_set_config_content(const char *content);

src/api_config.cpp

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "api_config.h"
22
#include "common.h"
33
#include "util/cast.hpp"
4-
#include "util/inireader.hpp"
54
#include "util/strfuns.hpp"
65
#include <algorithm>
76
#include <cstdlib>
@@ -10,6 +9,7 @@
109
#include <loguru.hpp>
1110
#include <mutex>
1211
#include <stdexcept>
12+
#include <sstream>
1313

1414
using namespace lsl;
1515

@@ -52,6 +52,23 @@ bool file_is_readable(const std::string &filename) {
5252
}
5353

5454
api_config::api_config() {
55+
// first check to see if a config content was provided
56+
if (!api_config_content_.empty()) {
57+
try {
58+
// if so, load it from the content
59+
load_from_content(api_config_content_);
60+
// free the content this can only be called once
61+
api_config_content_.clear();
62+
// config loaded successfully, so return
63+
return;
64+
} catch (std::exception &e) {
65+
LOG_F(ERROR, "Error parsing config content: '%s', rolling back to defaults", e.what());
66+
// clear the content, it was invalid anyway
67+
api_config_content_.clear();
68+
}
69+
}
70+
// otherwise, load the config from a file
71+
5572
// for each config file location under consideration...
5673
std::vector<std::string> filenames;
5774

@@ -92,7 +109,6 @@ api_config::api_config() {
92109
load_from_file();
93110
}
94111

95-
96112
void api_config::load_from_file(const std::string &filename) {
97113
try {
98114
INI pt;
@@ -102,7 +118,35 @@ void api_config::load_from_file(const std::string &filename) {
102118
pt.load(infile);
103119
}
104120
}
121+
api_config::load(pt);
122+
// log config filename only after setting the verbosity level and all config has been read
123+
if (!filename.empty())
124+
LOG_F(INFO, "Configuration loaded from %s", filename.c_str());
125+
else
126+
LOG_F(INFO, "Loaded default config");
127+
128+
} catch (std::exception &e) {
129+
LOG_F(ERROR, "Error parsing config file '%s': '%s', rolling back to defaults",
130+
filename.c_str(), e.what());
131+
// any error: assign defaults
132+
load_from_file();
133+
// and rethrow
134+
throw e;
135+
}
136+
}
137+
138+
void api_config::load_from_content(const std::string &content) {
139+
// load the content into an INI object
140+
INI pt;
141+
if (!content.empty()) {
142+
std::istringstream content_stream(content);
143+
pt.load(content_stream);
144+
}
145+
api_config::load(pt);
146+
LOG_F(INFO, "Configuration loaded from content");
147+
}
105148

149+
void api_config::load(INI &pt) {
106150
// read the [log] settings
107151
int log_level = pt.get("log.level", (int)loguru::Verbosity_INFO);
108152
if (log_level < -3 || log_level > 9)
@@ -274,20 +318,7 @@ void api_config::load_from_file(const std::string &filename) {
274318
smoothing_halftime_ = pt.get("tuning.SmoothingHalftime", 90.0F);
275319
force_default_timestamps_ = pt.get("tuning.ForceDefaultTimestamps", false);
276320

277-
// log config filename only after setting the verbosity level and all config has been read
278-
if (!filename.empty())
279-
LOG_F(INFO, "Configuration loaded from %s", filename.c_str());
280-
else
281-
LOG_F(INFO, "Loaded default config");
282-
283-
} catch (std::exception &e) {
284-
LOG_F(ERROR, "Error parsing config file '%s': '%s', rolling back to defaults",
285-
filename.c_str(), e.what());
286-
// any error: assign defaults
287-
load_from_file();
288-
// and rethrow
289-
throw e;
290-
}
321+
291322
}
292323

293324
static std::once_flag api_config_once_flag;

src/api_config.h

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define API_CONFIG_H
33

44
#include "netinterfaces.h"
5+
#include "util/inireader.hpp"
56
#include <cstdint>
67
#include <loguru.hpp>
78
#include <string>
@@ -14,9 +15,11 @@ namespace lsl {
1415
* A configuration object: holds all the configurable settings of liblsl.
1516
* These settings can be set via a configuration file that is automatically searched
1617
* by stream providers and recipients in a series of locations:
17-
* - lsl_api.cfg
18-
* - ~/lsl_api/lsl_api.cfg
19-
* - /etc/lsl_api/lsl_api.cfg
18+
* - First, the content set via `lsl_set_config_content()`
19+
* - Second, the file set via `lsl_set_config_filename()`
20+
* - Third, the file `lsl_api.cfg` in the current working directory
21+
* - Fourth, the file `lsl_api.cfg` in the home directory (e.g., `~/lsl_api/lsl_api.cfg`)
22+
* - Fifth, the file `lsl_api.cfg` in the system configuration directory (e.g., `/etc/lsl_api/lsl_api.cfg`)
2023
*
2124
* Note that, while in some cases it might seem sufficient to override configurations
2225
* only for a subset of machines involved in a recording session (e.g., the servers),
@@ -76,6 +79,18 @@ class api_config {
7679
bool allow_ipv6() const { return allow_ipv6_; }
7780
bool allow_ipv4() const { return allow_ipv4_; }
7881

82+
83+
84+
/**
85+
* @brief Set the configuration directly from a string.
86+
*
87+
* This allows passing in configuration content directly rather than from a file.
88+
* This MUST be called before the first call to get_instance() to have any effect.
89+
*/
90+
static void set_api_config_content(const std::string &content) {
91+
api_config_content_ = content;
92+
}
93+
7994
/**
8095
* @brief An additional settings path to load configuration from.
8196
*/
@@ -236,7 +251,21 @@ class api_config {
236251
*/
237252
void load_from_file(const std::string &filename = std::string());
238253

254+
/**
255+
* @brief Load a configuration from a string.
256+
* @param content The configuration content to parse
257+
*/
258+
void load_from_content(const std::string &content);
259+
260+
/**
261+
* @brief Load the configuration from an INI object.
262+
* @param pt The INI object to load the configuration from
263+
*/
264+
void load(INI &pt);
265+
266+
// config overrides
239267
static std::string api_config_filename_;
268+
static std::string api_config_content_;
240269

241270
// core parameters
242271
bool allow_ipv6_, allow_ipv4_;
@@ -278,6 +307,7 @@ class api_config {
278307

279308
// initialize configuration file name
280309
inline std::string api_config::api_config_filename_ = "";
310+
inline std::string api_config::api_config_content_ = "";
281311

282312
} // namespace lsl
283313

src/common.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ LIBLSL_C_API void lsl_set_config_filename(const char *filename) {
3232
}
3333
}
3434

35+
LIBLSL_C_API void lsl_set_config_content(const char *content) {
36+
if (content) {
37+
lsl::api_config::set_api_config_content(content);
38+
}
39+
}
40+
3541
LIBLSL_C_API int32_t lsl_library_version() { return LSL_LIBRARY_VERSION; }
3642

3743
LIBLSL_C_API double lsl_local_clock() {

0 commit comments

Comments
 (0)