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>
109#include < loguru.hpp>
1110#include < mutex>
1211#include < stdexcept>
12+ #include < sstream>
1313
1414using namespace lsl ;
1515
@@ -52,9 +52,36 @@ bool file_is_readable(const std::string &filename) {
5252}
5353
5454api_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-
86112void 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
283324static std::once_flag api_config_once_flag;
0 commit comments