Skip to content

Commit 6ddb89b

Browse files
committed
Merge branch 'feature/apple_framework' into feature/arm-runnersd
2 parents 93ebdb7 + 433ef82 commit 6ddb89b

File tree

4 files changed

+143
-19
lines changed

4 files changed

+143
-19
lines changed

include/lsl/common.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,23 @@ extern LIBLSL_C_API double lsl_local_clock();
227227
* no free() method is available (e.g., in some scripting languages).
228228
*/
229229
extern LIBLSL_C_API void lsl_destroy_string(char *s);
230+
231+
/**
232+
* Set the name of the configuration file to be used.
233+
*
234+
* This is a global setting that will be used by all LSL
235+
* after this function is called. If, and only if, this function
236+
* is called before the first call to any other LSL function.
237+
*/
238+
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: 57 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,9 +52,36 @@ 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

75+
// NOLINTNEXTLINE(concurrency-mt-unsafe)
76+
if (!api_config_filename_.empty()) {
77+
// if a config file name was set, use it if it is readable
78+
if (file_is_readable(api_config_filename_)) {
79+
filenames.insert(filenames.begin(), api_config_filename_);
80+
} else {
81+
LOG_F(ERROR, "Config file %s not found", api_config_filename_.c_str());
82+
}
83+
}
84+
5885
// NOLINTNEXTLINE(concurrency-mt-unsafe)
5986
if (auto *cfgpath = getenv("LSLAPICFG")) {
6087
std::string envcfg(cfgpath);
@@ -82,7 +109,6 @@ api_config::api_config() {
82109
load_from_file();
83110
}
84111

85-
86112
void api_config::load_from_file(const std::string &filename) {
87113
try {
88114
INI pt;
@@ -92,7 +118,35 @@ void api_config::load_from_file(const std::string &filename) {
92118
pt.load(infile);
93119
}
94120
}
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+
}
95137

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+
}
148+
149+
void api_config::load(INI &pt) {
96150
// read the [log] settings
97151
int log_level = pt.get("log.level", (int)loguru::Verbosity_INFO);
98152
if (log_level < -3 || log_level > 9)
@@ -264,20 +318,7 @@ void api_config::load_from_file(const std::string &filename) {
264318
smoothing_halftime_ = pt.get("tuning.SmoothingHalftime", 90.0F);
265319
force_default_timestamps_ = pt.get("tuning.ForceDefaultTimestamps", false);
266320

267-
// log config filename only after setting the verbosity level and all config has been read
268-
if (!filename.empty())
269-
LOG_F(INFO, "Configuration loaded from %s", filename.c_str());
270-
else
271-
LOG_F(INFO, "Loaded default config");
272-
273-
} catch (std::exception &e) {
274-
LOG_F(ERROR, "Error parsing config file '%s': '%s', rolling back to defaults",
275-
filename.c_str(), e.what());
276-
// any error: assign defaults
277-
load_from_file();
278-
// and rethrow
279-
throw e;
280-
}
321+
281322
}
282323

283324
static std::once_flag api_config_once_flag;

src/api_config.h

Lines changed: 54 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,33 @@ 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+
94+
/**
95+
* @brief An additional settings path to load configuration from.
96+
*/
97+
const std::string &api_config_filename() const { return api_config_filename_; }
98+
99+
/**
100+
* @brief Set the config file name used to load the settings.
101+
*
102+
* This MUST be called before the first call to get_instance() to have any effect.
103+
*/
104+
static void set_api_config_filename(const std::string &filename) {
105+
api_config_filename_ = filename;
106+
}
107+
108+
79109
/**
80110
* @brief The range or scope of stream lookup when using multicast-based discovery
81111
*
@@ -221,6 +251,22 @@ class api_config {
221251
*/
222252
void load_from_file(const std::string &filename = std::string());
223253

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
267+
static std::string api_config_filename_;
268+
static std::string api_config_content_;
269+
224270
// core parameters
225271
bool allow_ipv6_, allow_ipv4_;
226272
uint16_t base_port_;
@@ -258,6 +304,11 @@ class api_config {
258304
float smoothing_halftime_;
259305
bool force_default_timestamps_;
260306
};
307+
308+
// initialize configuration file name
309+
inline std::string api_config::api_config_filename_ = "";
310+
inline std::string api_config::api_config_content_ = "";
311+
261312
} // namespace lsl
262313

263314
#endif

src/common.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ LIBLSL_C_API int32_t lsl_protocol_version() {
2626
return lsl::api_config::get_instance()->use_protocol_version();
2727
}
2828

29+
LIBLSL_C_API void lsl_set_config_filename(const char *filename) {
30+
if (filename) {
31+
lsl::api_config::set_api_config_filename(filename);
32+
}
33+
}
34+
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+
2941
LIBLSL_C_API int32_t lsl_library_version() { return LSL_LIBRARY_VERSION; }
3042

3143
LIBLSL_C_API double lsl_local_clock() {

0 commit comments

Comments
 (0)