SNode.C
Loading...
Searching...
No Matches
utils::Config Class Reference

#include <Config.h>

Collaboration diagram for utils::Config:

Public Member Functions

 Config ()=delete
 Config (const Config &)=delete
 ~Config ()=delete
Configoperator= (const Config &)=delete

Static Public Member Functions

static bool init (int argc, char *argv[])
static bool bootstrap ()
static void terminate ()
static CLI::App * addInstance (const std::string &name, const std::string &description, const std::string &group, bool final=false)
static CLI::App * getInstance (const std::string &name)
static bool removeInstance (CLI::App *instance)
static void required (CLI::App *instance, bool required=true)
static void disabled (CLI::App *instance, bool disabled=true)
static CLI::App * addStandardFlags (CLI::App *app)
static CLI::App * addSimpleHelp (CLI::App *app)
static CLI::App * addHelp (CLI::App *app)
static std::string getApplicationName ()
static int getLogLevel ()
static int getVerboseLevel ()
static CLI::Option * addStringOption (const std::string &name, const std::string &description, const std::string &typeName)
static CLI::Option * addStringOption (const std::string &name, const std::string &description, const std::string &typeName, bool configurable)
static CLI::Option * addStringOption (const std::string &name, const std::string &description, const std::string &typeName, const std::string &defaultValue)
static CLI::Option * addStringOption (const std::string &name, const std::string &description, const std::string &typeName, const std::string &defaultValue, bool configurable)
static CLI::Option * addStringOption (const std::string &name, const std::string &description, const std::string &typeName, const char *defaultValue)
static CLI::Option * addStringOption (const std::string &name, const std::string &description, const std::string &typeName, const char *defaultValue, bool configurable)
static std::string getStringOptionValue (const std::string &name)
static void addFlag (const std::string &name, bool &variable, const std::string &description, bool required, bool configurable=true, const std::string &groupName="Application Options")

Static Public Attributes

static std::shared_ptr< CLI::App > app = makeApp()
static int argc = 0
static char ** argv = nullptr
static CLI::App * helpTriggerApp = nullptr
static CLI::App * showConfigTriggerApp = nullptr

Static Private Member Functions

static bool parse1 ()
static bool parse2 ()

Static Private Attributes

static std::shared_ptr< CLI::Formatter > sectionFormatter = makeSectionFormatter()
static bool subParse
static std::string applicationName
static std::string configDirectory
static std::string logDirectory
static std::string pidDirectory
static CLI::Option * daemonizeOpt = nullptr
static CLI::Option * logFileOpt = nullptr
static CLI::Option * userNameOpt = nullptr
static CLI::Option * groupNameOpt = nullptr
static CLI::Option * enforceLogFileOpt = nullptr
static CLI::Option * logLevelOpt = nullptr
static CLI::Option * verboseLevelOpt = nullptr
static CLI::Option * quietOpt = nullptr
static std::map< std::string, std::string > aliases
static std::map< std::string, CLI::Option * > applicationOptions

Detailed Description

Definition at line 61 of file Config.h.

Constructor & Destructor Documentation

◆ Config() [1/2]

utils::Config::Config ( )
delete

◆ Config() [2/2]

utils::Config::Config ( const Config & )
delete

◆ ~Config()

utils::Config::~Config ( )
delete

Member Function Documentation

◆ addFlag()

void Config::addFlag ( const std::string & name,
bool & variable,
const std::string & description,
bool required,
bool configurable = true,
const std::string & groupName = "Application Options" )
static

Definition at line 988 of file Config.cpp.

993 {
994 app->add_flag(name, variable, description) //
995 ->required(required) //
996 ->configurable(configurable) //
997 ->group(groupName);
998 }
static std::shared_ptr< CLI::App > app
Definition Config.h:123
static void required(CLI::App *instance, bool required=true)
Definition Config.cpp:866

References app.

◆ addHelp()

CLI::App * Config::addHelp ( CLI::App * app)
static

Definition at line 835 of file Config.cpp.

835 {
836 app->set_help_flag(
837 "-h{exact},--help{exact}",
838 [app](std::size_t) {
840 },
841 "Print help message and exit\n"
842 "* standard: display help for the last command processed\n"
843 "* exact: display help for the command directly preceding --help\n"
844 "* expanded: print help including all descendant command options")
845 ->group(app->get_formatter()->get_label("Nonpersistent Options"))
846 ->check(CLI::IsMember({"standard", "exact", "expanded"}));
847
848 return app;
849 }
static CLI::App * helpTriggerApp
Definition Config.h:153

References helpTriggerApp.

Referenced by addInstance(), and init().

Here is the caller graph for this function:

◆ addInstance()

CLI::App * Config::addInstance ( const std::string & name,
const std::string & description,
const std::string & group,
bool final = false )
static

Definition at line 736 of file Config.cpp.

736 {
737 CLI::App* instanceSc = app->add_subcommand(name, description) //
738 ->group(group)
739 ->fallthrough()
740 ->formatter(sectionFormatter)
741 ->configurable(false)
742 ->allow_extras(false)
743 ->disabled(name.empty());
744
745 instanceSc //
746 ->option_defaults()
747 ->configurable(!instanceSc->get_disabled());
748
749 if (!instanceSc->get_disabled()) {
750 if (aliases.contains(name)) {
751 instanceSc //
752 ->alias(aliases[name]);
753 }
754 }
755
757
758 if (!final) {
759 utils::Config::addHelp(instanceSc);
760 } else {
762 }
763
764 return instanceSc;
765 }
static std::map< std::string, std::string > aliases
Definition Config.h:157
static CLI::App * addHelp(CLI::App *app)
Definition Config.cpp:835
static std::shared_ptr< CLI::Formatter > sectionFormatter
Definition Config.h:129
static CLI::App * addSimpleHelp(CLI::App *app)
Definition Config.cpp:851
static CLI::App * addStandardFlags(CLI::App *app)
Definition Config.cpp:771

References addHelp(), addSimpleHelp(), addStandardFlags(), aliases, app, and sectionFormatter.

Referenced by net::config::ConfigInstance::ConfigInstance().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ addSimpleHelp()

CLI::App * Config::addSimpleHelp ( CLI::App * app)
static

Definition at line 851 of file Config.cpp.

851 {
852 app->set_help_flag(
853 "--help{exact},-h{exact}",
854 [app](std::size_t) {
856 },
857 "Print help message and exit\n"
858 "* standard: display help for the last command processed\n"
859 "* exact: display help for the command directly preceding --help\n")
860 ->group(app->get_formatter()->get_label("Nonpersistent Options"))
861 ->check(CLI::IsMember({"standard", "exact"}));
862
863 return app;
864 }

References helpTriggerApp.

Referenced by addInstance(), and net::config::ConfigInstance::addSection().

Here is the caller graph for this function:

◆ addStandardFlags()

CLI::App * Config::addStandardFlags ( CLI::App * app)
static

Definition at line 771 of file Config.cpp.

771 {
772 app //
773 ->add_flag_function(
774 "-s,--show-config",
775 [app](std::size_t) {
777 },
778 "Show current configuration and exit") //
779 ->configurable(false)
780 ->disable_flag_override();
781
782 app //
783 ->add_flag(
784 "--command-line{standard}",
785 [app]([[maybe_unused]] std::int64_t count) {
786 const std::string& result = app->get_option("--command-line")->as<std::string>();
787 if (result == "standard") {
788 throw CLI::CallForCommandline( //
789 app,
790 "Below is a command line viewing all non-default and required options:\n"
791 "* Options show their configured value\n"
792 "* Required but not yet configured options show <REQUIRED> as value\n"
793 "* Options marked as <REQUIRED> need to be configured for a successful bootstrap",
795 }
796 if (result == "active") {
797 throw CLI::CallForCommandline( //
798 app,
799 "Below is a command line viewing the active set of options with their default or configured values:\n"
800 "* Options show either their configured or default value\n"
801 "* Required but not yet configured options show <REQUIRED> as value\n"
802 "* Options marked as <REQUIRED> need to be configured for a successful bootstrap",
804 }
805 if (result == "complete") {
806 throw CLI::CallForCommandline( //
807 app,
808 "Below is a command line viewing the complete set of options with their default values\n"
809 "* Options show their default value\n"
810 "* Required but not yet configured options show <REQUIRED> as value\n"
811 "* Options marked as <REQUIRED> need to be configured for a successful bootstrap",
813 }
814 if (result == "required") {
815 throw CLI::CallForCommandline( //
816 app,
817 "Below is a command line viewing required options only:\n"
818 "* Options show either their configured or default value\n"
819 "* Required but not yet configured options show <REQUIRED> as value\n"
820 "* Options marked as <REQUIRED> need to be configured for a successful bootstrap",
822 }
823 },
824 "Print command-line\n"
825 "* standard (default): Show all non-default and required options\n"
826 "* active: Show all active options\n"
827 "* complete: Show the complete option set with default values\n"
828 "* required: Show only required options")
829 ->configurable(false)
830 ->check(CLI::IsMember({"standard", "active", "complete", "required"}));
831
832 return app;
833 }
static CLI::App * showConfigTriggerApp
Definition Config.h:154

References CLI::CallForCommandline::CallForCommandline(), CLI::CallForCommandline::DEFAULT, CLI::CallForCommandline::FULL, CLI::CallForCommandline::REQUIRED, showConfigTriggerApp, and CLI::CallForCommandline::STANDARD.

Referenced by addInstance(), net::config::ConfigInstance::addSection(), and init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ addStringOption() [1/6]

CLI::Option * Config::addStringOption ( const std::string & name,
const std::string & description,
const std::string & typeName )
static

Definition at line 923 of file Config.cpp.

923 {
924 applicationOptions[name] = app //
925 ->add_option(name, description)
926 ->type_name(typeName)
927 ->configurable()
928 ->required()
929 ->group("Application Options");
930
931 app->needs(applicationOptions[name]);
932
933 return applicationOptions[name];
934 }
static std::map< std::string, CLI::Option * > applicationOptions
Definition Config.h:158

References app, and applicationOptions.

Referenced by addStringOption(), addStringOption(), and main().

Here is the caller graph for this function:

◆ addStringOption() [2/6]

CLI::Option * Config::addStringOption ( const std::string & name,
const std::string & description,
const std::string & typeName,
bool configurable )
static

Definition at line 937 of file Config.cpp.

937 {
938 addStringOption(name, description, typeName);
939 return applicationOptions[name] //
940 ->configurable(configurable);
941 }
static CLI::Option * addStringOption(const std::string &name, const std::string &description, const std::string &typeName)
Definition Config.cpp:923

References addStringOption(), and applicationOptions.

Here is the call graph for this function:

◆ addStringOption() [3/6]

CLI::Option * Config::addStringOption ( const std::string & name,
const std::string & description,
const std::string & typeName,
const char * defaultValue )
static

Definition at line 968 of file Config.cpp.

971 {
972 return addStringOption(name, description, typeName, std::string(defaultValue));
973 }

References addStringOption().

Here is the call graph for this function:

◆ addStringOption() [4/6]

CLI::Option * Config::addStringOption ( const std::string & name,
const std::string & description,
const std::string & typeName,
const char * defaultValue,
bool configurable )
static

Definition at line 975 of file Config.cpp.

976 {
977 return addStringOption(name, description, typeName, std::string(defaultValue), configurable);
978 }

References addStringOption().

Here is the call graph for this function:

◆ addStringOption() [5/6]

CLI::Option * Config::addStringOption ( const std::string & name,
const std::string & description,
const std::string & typeName,
const std::string & defaultValue )
static

Definition at line 943 of file Config.cpp.

946 {
947 addStringOption(name, description, typeName);
948
949 applicationOptions[name] //
950 ->required(false)
951 ->default_str(defaultValue);
952
953 app->remove_needs(applicationOptions[name]);
954
955 return applicationOptions[name];
956 }

References addStringOption(), app, and applicationOptions.

Referenced by addStringOption(), and addStringOption().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ addStringOption() [6/6]

CLI::Option * Config::addStringOption ( const std::string & name,
const std::string & description,
const std::string & typeName,
const std::string & defaultValue,
bool configurable )
static

Definition at line 958 of file Config.cpp.

962 {
963 addStringOption(name, description, typeName, defaultValue);
964 return applicationOptions[name] //
965 ->configurable(configurable);
966 }

References addStringOption(), and applicationOptions.

Referenced by addStringOption().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ bootstrap()

bool Config::bootstrap ( )
static

Definition at line 368 of file Config.cpp.

368 {
369 aliases.clear();
370
371 app->final_callback([]() {
372 if (daemonizeOpt->as<bool>() && helpTriggerApp == nullptr && showConfigTriggerApp == nullptr &&
373 (*app)["--write-config"]->count() == 0 && (*app)["--command-line"]->count() == 0) {
374 std::cout << "Running as daemon (double fork)" << std::endl;
375
377 pidDirectory + "/" + applicationName + ".pid", userNameOpt->as<std::string>(), groupNameOpt->as<std::string>());
378
380
381 const std::string logFile = logFileOpt->as<std::string>();
382 if (!logFile.empty()) {
384 }
385 } else if ((*app)["--enforce-log-file"]->as<bool>()) {
386 const std::string logFile = logFileOpt->as<std::string>();
387 if (!logFile.empty()) {
388 std::cout << "Writing logs to file " << logFile << std::endl;
389
391 }
392 }
393 });
394
395 return parse2();
396 }
static void logToFile(const std::string &logFile)
Definition Logger.cpp:127
static void setQuiet(bool quiet=true)
Definition Logger.cpp:136
static CLI::Option * groupNameOpt
Definition Config.h:146
static std::string applicationName
Definition Config.h:137
static CLI::Option * logFileOpt
Definition Config.h:144
static std::string pidDirectory
Definition Config.h:141
static CLI::Option * userNameOpt
Definition Config.h:145
static CLI::Option * daemonizeOpt
Definition Config.h:143
static bool parse2()
Definition Config.cpp:583
static void startDaemon(const std::string &pidFileName, const std::string &userName, const std::string &groupName)
Definition Daemon.cpp:75

References aliases, app, applicationName, daemonizeOpt, groupNameOpt, helpTriggerApp, logFileOpt, parse2(), pidDirectory, logger::Logger::setQuiet(), showConfigTriggerApp, utils::Daemon::startDaemon(), and userNameOpt.

Referenced by core::EventLoop::start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ disabled()

void Config::disabled ( CLI::App * instance,
bool disabled = true )
static

Definition at line 889 of file Config.cpp.

889 {
890 if (disabled) {
891 if (instance->get_ignore_case()) {
892 app->remove_needs(instance);
893 }
894
895 for (const auto& sub : instance->get_subcommands({})) {
896 if (sub->get_ignore_case()) {
897 instance->remove_needs(sub);
898 sub->required(false); // ### must be stored in ConfigInstance
899 }
900 }
901 } else {
902 if (instance->get_ignore_case()) {
903 app->needs(instance);
904 }
905
906 for (const auto& sub : instance->get_subcommands({})) {
907 if (sub->get_ignore_case()) { // ### must be recalled from ConfigInstance
908 instance->needs(sub);
909 sub->required();
910 }
911 }
912 }
913
914 instance->required(disabled ? false : instance->get_ignore_case());
915 }
static void disabled(CLI::App *instance, bool disabled=true)
Definition Config.cpp:889

References app.

Referenced by net::config::ConfigInstance::ConfigInstance(), and net::config::ConfigInstance::setDisabled().

Here is the caller graph for this function:

◆ getApplicationName()

std::string Config::getApplicationName ( )
static

Definition at line 1000 of file Config.cpp.

1000 {
1001 return applicationName;
1002 }

References applicationName.

Referenced by utils::createCommandLineTemplate(), web::websocket::client::SubProtocolFactorySelector::load(), and web::websocket::server::SubProtocolFactorySelector::load().

Here is the caller graph for this function:

◆ getInstance()

CLI::App * Config::getInstance ( const std::string & name)
static

Definition at line 767 of file Config.cpp.

767 {
768 return app->get_subcommand(name);
769 }

References app.

◆ getLogLevel()

int Config::getLogLevel ( )
static

Definition at line 1004 of file Config.cpp.

1004 {
1005 return logLevelOpt->as<int>();
1006 }
static CLI::Option * logLevelOpt
Definition Config.h:148

References logLevelOpt.

◆ getStringOptionValue()

std::string Config::getStringOptionValue ( const std::string & name)
static

Definition at line 980 of file Config.cpp.

980 {
981 if (app->get_option(name) == nullptr) {
982 throw CLI::OptionNotFound(name);
983 }
984
985 return (*app)[name]->as<std::string>();
986 }

References app.

Referenced by main().

Here is the caller graph for this function:

◆ getVerboseLevel()

int Config::getVerboseLevel ( )
static

Definition at line 1008 of file Config.cpp.

1008 {
1009 return verboseLevelOpt->as<int>();
1010 }
static CLI::Option * verboseLevelOpt
Definition Config.h:149

References verboseLevelOpt.

◆ init()

bool Config::init ( int argc,
char * argv[] )
static

Definition at line 136 of file Config.cpp.

136 {
137 bool proceed = true;
138
141
142 applicationName = std::filesystem::path(argv[0]).filename();
143
144 uid_t euid = 0;
145 struct passwd* pw = nullptr;
146 struct group* gr = nullptr;
147
148 if ((pw = getpwuid(getuid())) == nullptr) {
149 proceed = false;
150 } else if ((gr = getgrgid(pw->pw_gid)) == nullptr) {
151 proceed = false;
152 } else if ((euid = geteuid()) == 0) {
153 configDirectory = "/etc/snode.c";
154 logDirectory = "/var/log/snode.c";
155 pidDirectory = "/var/run/snode.c";
156 } else {
157 const char* homedir = nullptr;
158 if ((homedir = std::getenv("XDG_CONFIG_HOME")) == nullptr) {
159 if ((homedir = std::getenv("HOME")) == nullptr) {
160 homedir = pw->pw_dir;
161 }
162 }
163
164 if (homedir != nullptr) {
165 configDirectory = std::string(homedir) + "/.config/snode.c";
166 logDirectory = std::string(homedir) + "/.local/log/snode.c";
167 pidDirectory = std::string(homedir) + "/.local/run/snode.c";
168 } else {
169 proceed = false;
170 }
171 }
172
173 if (proceed && !std::filesystem::exists(configDirectory)) {
174 if (std::filesystem::create_directories(configDirectory)) {
175 std::filesystem::permissions(
177 (std::filesystem::perms::owner_all | std::filesystem::perms::group_read | std::filesystem::perms::group_exec) &
178 ~std::filesystem::perms::others_all);
179 if (geteuid() == 0) {
180 struct group* gr = nullptr;
181 if ((gr = getgrnam(XSTR(GROUP_NAME))) != nullptr) {
182 if (chown(configDirectory.c_str(), euid, gr->gr_gid) < 0) {
183 std::cout << "Warning: Can not set group ownership of '" << configDirectory
184 << "' to 'snodec':" << strerror(errno) << std::endl;
185 }
186 } else {
187 std::cout << "Error: Can not find group 'snodec'. Add it using groupadd or addgroup" << std::endl;
188 std::cout << " and add the current user to this group." << std::endl;
189 std::filesystem::remove(configDirectory);
190 proceed = false;
191 }
192 }
193 } else {
194 std::cout << "Error: Can not create directory '" << configDirectory << "'" << std::endl;
195 proceed = false;
196 }
197 }
198
199 if (proceed && !std::filesystem::exists(logDirectory)) {
200 if (std::filesystem::create_directories(logDirectory)) {
201 std::filesystem::permissions(logDirectory,
202 (std::filesystem::perms::owner_all | std::filesystem::perms::group_all) &
203 ~std::filesystem::perms::others_all);
204 if (geteuid() == 0) {
205 struct group* gr = nullptr;
206 if ((gr = getgrnam(XSTR(GROUP_NAME))) != nullptr) {
207 if (chown(logDirectory.c_str(), euid, gr->gr_gid) < 0) {
208 std::cout << "Warning: Can not set group ownership of '" << logDirectory << "' to 'snodec':" << strerror(errno)
209 << std::endl;
210 }
211 } else {
212 std::cout << "Error: Can not find group 'snodec'. Add it using groupadd or addgroup" << std::endl;
213 std::cout << " and add the current user to this group." << std::endl;
214 std::filesystem::remove(configDirectory);
215 proceed = false;
216 }
217 }
218 } else {
219 std::cout << "Error: Can not create directory '" << logDirectory << "'" << std::endl;
220 proceed = false;
221 }
222 }
223
224 if (proceed && !std::filesystem::exists(pidDirectory)) {
225 if (std::filesystem::create_directories(pidDirectory)) {
226 std::filesystem::permissions(pidDirectory,
227 (std::filesystem::perms::owner_all | std::filesystem::perms::group_all) &
228 ~std::filesystem::perms::others_all);
229 if (geteuid() == 0) {
230 struct group* gr = nullptr;
231 if ((gr = getgrnam(XSTR(GROUP_NAME))) != nullptr) {
232 if (chown(pidDirectory.c_str(), euid, gr->gr_gid) < 0) {
233 std::cout << "Warning: Can not set group ownership of '" << pidDirectory << "' to 'snodec':" << strerror(errno)
234 << std::endl;
235 }
236 } else {
237 std::cout << "Error: Can not find group 'snodec'. Add it using groupadd or addgroup." << std::endl;
238 std::cout << " and add the current user to this group." << std::endl;
239 std::filesystem::remove(configDirectory);
240 proceed = false;
241 }
242 }
243 } else {
244 std::cout << "Error: Can not create directory '" << pidDirectory << "'" << std::endl;
245 proceed = false;
246 }
247 }
248
249 if (proceed) {
250 app->description("Configuration for Application '" + applicationName + "'");
251
252 app->footer("Application '" + applicationName +
253 "' powered by SNode.C\n"
254 "(C) 2020-2025 Volker Christian <me@vchrist.at>\n"
255 "https://github.com/SNodeC/snode.c");
256
257 app->set_config( //
258 "-c,--config-file",
259 configDirectory + "/" + applicationName + ".conf",
260 "Read a config file",
261 false) //
262 ->take_all()
263 ->type_name("configfile")
264 ->check(!CLI::ExistingDirectory);
265
266 app->add_option("-w,--write-config", "Write config file and exit")
267 ->configurable(false)
268 ->default_val(configDirectory + "/" + applicationName + ".conf")
269 ->type_name("configfile")
270 ->check(!CLI::ExistingDirectory)
271 ->expected(0, 1);
272
273 app->add_flag( //
274 "-k,--kill",
275 "Kill running daemon") //
276 ->configurable(false)
277 ->disable_flag_override();
278
279 app->add_option( //
280 "-i,--instance-alias",
281 "Make an instance also known as an alias in configuration files")
282 ->configurable(false)
283 ->type_name("instance=instance_alias [instance=instance_alias [...]]")
284 ->each([](const std::string& item) {
285 const auto it = item.find('=');
286 if (it != std::string::npos) {
287 aliases[item.substr(0, it)] = item.substr(it + 1);
288 } else {
289 throw CLI::ConversionError("Can not convert '" + item + "' to a 'instance=instance_alias' pair");
290 }
291 });
292
293 addStandardFlags(app.get());
294
295 logLevelOpt = app->add_option( //
296 "-l,--log-level",
297 "Log level") //
298 ->default_val(4)
299 ->type_name("level")
300 ->check(CLI::Range(0, 6))
301 ->group(app->get_formatter()->get_label("Persistent Options"));
302
303 verboseLevelOpt = app->add_option( //
304 "-v,--verbose-level",
305 "Verbose level") //
306 ->default_val(2)
307 ->type_name("level")
308 ->check(CLI::Range(0, 10))
309 ->group(app->get_formatter()->get_label("Persistent Options"));
310
311 quietOpt = app->add_flag( //
312 "-q{true},!-u,--quiet{true}",
313 "Quiet mode") //
314 ->default_val("false")
315 ->type_name("bool")
316 ->check(CLI::IsMember({"true", "false"}))
317 ->group(app->get_formatter()->get_label("Persistent Options"));
318
319 logFileOpt = app->add_option( //
320 "--log-file",
321 "Log file path") //
322 ->default_val(logDirectory + "/" + applicationName + ".log")
323 ->type_name("logfile")
324 ->check(!CLI::ExistingDirectory)
325 ->group(app->get_formatter()->get_label("Persistent Options"));
326
327 enforceLogFileOpt = app->add_flag( //
328 "-e{true},!-n,--enforce-log-file{true}",
329 "Enforce writing of logs to file for foreground applications") //
330 ->default_val("false")
331 ->type_name("bool")
332 ->check(CLI::IsMember({"true", "false"}))
333 ->group(app->get_formatter()->get_label("Persistent Options"));
334
335 daemonizeOpt = app->add_flag( //
336 "-d{true},!-f,--daemonize{true}",
337 "Start application as daemon") //
338 ->default_val("false")
339 ->type_name("bool")
340 ->check(CLI::IsMember({"true", "false"}))
341 ->group(app->get_formatter()->get_label("Persistent Options"));
342
343 userNameOpt = app->add_option( //
344 "--user-name",
345 "Run daemon under specific user permissions") //
346 ->default_val(pw->pw_name)
347 ->type_name("username")
348 ->needs(daemonizeOpt)
349 ->group(app->get_formatter()->get_label("Persistent Options"));
350
351 groupNameOpt = app->add_option( //
352 "--group-name",
353 "Run daemon under specific group permissions")
354 ->default_val(gr->gr_name)
355 ->type_name("groupname")
356 ->needs(daemonizeOpt)
357 ->group(app->get_formatter()->get_label("Persistent Options"));
358
359 proceed = parse1(); // for stopDaemon and pre init application options
360
361 app->set_version_flag("--version", "1.0-rc1", "Framework version");
362 addHelp(app.get());
363 }
364
365 return proceed;
366 }
#define XSTR(s)
static CLI::Option * enforceLogFileOpt
Definition Config.h:147
static bool parse1()
Definition Config.cpp:398
static std::string configDirectory
Definition Config.h:139
static int argc
Definition Config.h:132
static std::string logDirectory
Definition Config.h:140
static CLI::Option * quietOpt
Definition Config.h:150
static char ** argv
Definition Config.h:133

References addHelp(), addStandardFlags(), aliases, app, applicationName, argc, argv, configDirectory, daemonizeOpt, enforceLogFileOpt, groupNameOpt, logDirectory, logFileOpt, logLevelOpt, parse1(), pidDirectory, quietOpt, userNameOpt, and verboseLevelOpt.

Referenced by core::EventLoop::init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator=()

Config & utils::Config::operator= ( const Config & )
delete

◆ parse1()

bool Config::parse1 ( )
staticprivate

Definition at line 398 of file Config.cpp.

398 {
399 bool proceed = true;
400
401 try {
402 app->parse(argc, argv);
403 } catch (const CLI::ParseError&) {
404 // Do not process ParseError here but on second parse pass
405 }
406
407 if ((*app)["--kill"]->count() > 0) {
408 try {
409 const pid_t daemonPid = utils::Daemon::stopDaemon(pidDirectory + "/" + applicationName + ".pid");
410 std::cout << "Daemon terminated: Pid = " << daemonPid << std::endl;
411 } catch (const DaemonError& e) {
412 std::cout << "DaemonError: " << e.what() << std::endl;
413 } catch (const DaemonFailure& e) {
414 std::cout << "DaemonFailure: " << e.what() << std::endl;
415 }
416
417 proceed = false;
418 } else {
419 app->allow_extras((*app)["--show-config"]->count() != 0);
420
421 if (!quietOpt->as<bool>()) {
424 }
425
427 }
428
429 return proceed;
430 }
static void setVerboseLevel(int level)
Definition Logger.cpp:121
static void setLogLevel(int level)
Definition Logger.cpp:84
static pid_t stopDaemon(const std::string &pidFileName)
Definition Daemon.cpp:158

References app, applicationName, argc, argv, logLevelOpt, pidDirectory, quietOpt, logger::Logger::setLogLevel(), logger::Logger::setQuiet(), logger::Logger::setVerboseLevel(), utils::Daemon::stopDaemon(), and verboseLevelOpt.

Referenced by init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse2()

bool Config::parse2 ( )
staticprivate

Definition at line 583 of file Config.cpp.

583 {
584 bool success = false;
585
586 try {
587 try {
588 try {
589 app->parse(argc, argv);
590 success = true;
591 } catch (const CLI::ParseError&) {
592 if (helpTriggerApp == nullptr) {
593 if (showConfigTriggerApp != nullptr) {
594 success = false;
595 throw CLI::CallForShowConfig(showConfigTriggerApp);
596 }
597 if ((*app)["--write-config"]->count() > 0) {
598 success = false;
599 throw CLI::CallForWriteConfig((*app)["--write-config"]->as<std::string>());
600 }
601 }
602
603 throw;
604 }
605 if (helpTriggerApp == nullptr) {
606 if (showConfigTriggerApp != nullptr) {
607 success = false;
608 throw CLI::CallForShowConfig(showConfigTriggerApp);
609 }
610 if ((*app)["--write-config"]->count() > 0) {
611 success = false;
612 throw CLI::CallForWriteConfig((*app)["--write-config"]->as<std::string>());
613 }
614 }
615 } catch (const DaemonError& e) {
616 std::cout << "[" << Color::Code::FG_RED << "Error" << Color::Code::FG_DEFAULT << "] Daemonize: " << e.what()
617 << " ... exiting" << std::endl;
618 } catch (const DaemonFailure& e) {
619 std::cout << "[" << Color::Code::FG_RED << "Failure" << Color::Code::FG_DEFAULT << "] Daemonize: " << e.what()
620 << " ... exiting" << std::endl;
621 } catch (const DaemonSignaled& e) {
622 std::cout << "Pid: " << getpid() << ", child pid: " << e.getPid() << ": " << e.what() << std::endl;
623 } catch (const CLI::CallForHelp&) {
624 const std::string helpMode = helpTriggerApp->get_option("--help")->as<std::string>();
625 const CLI::App* helpApp = nullptr;
626 CLI::AppFormatMode mode = CLI::AppFormatMode::Normal;
627 if (helpMode == "exact") {
629 } else if (helpMode == "expanded") {
631 mode = CLI::AppFormatMode::All;
632 }
633 std::cout << app->help(helpApp, "", mode) << std::endl;
634 } catch (const CLI::CallForVersion&) {
635 std::cout << app->version() << std::endl << std::endl;
636 } catch (const CLI::CallForCommandline& e) {
637 std::cout << e.what() << std::endl;
638 std::cout << std::endl
639 << Color::Code::FG_GREEN << "command@line" << Color::Code::FG_DEFAULT << ":" << Color::Code::FG_BLUE << "~/> "
641 << std::endl;
642 } catch (const CLI::CallForShowConfig& e) {
643 try {
644 std::cout << e.getApp()->config_to_str(true, true);
645 } catch (const CLI::ParseError& e1) {
646 std::cout << "[" << Color::Code::FG_RED << "Error" << Color::Code::FG_DEFAULT << "] Showing config file: " << e.getApp()
647 << " " << e1.get_name() << " " << e1.what() << std::endl;
648 throw;
649 }
650 } catch (const CLI::CallForWriteConfig& e) {
651 std::cout << e.what() << std::endl;
652 std::ofstream confFile(e.getConfigFile());
653 if (confFile.is_open()) {
654 try {
655 confFile << app->config_to_str(true, true);
656 confFile.close();
657 } catch (const CLI::ParseError& e1) {
658 confFile.close();
659 std::cout << "Error writing config file: " << e1.get_name() << " " << e1.what() << std::endl;
660 throw;
661 }
662 } else {
663 std::cout << "[" << Color::Code::FG_RED << "Error" << Color::Code::FG_DEFAULT
664 << "] Writing config file: " << std::strerror(errno) << std::endl;
665 }
666 } catch (const CLI::ConversionError& e) {
667 std::cout << "[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT << "] " << e.what() << std::endl;
668 throw;
669 } catch (const CLI::ArgumentMismatch& e) {
670 std::cout << "[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT << "] " << e.what() << std::endl;
671 throw;
672 } catch (const CLI::ConfigError& e) {
673 std::cout << "[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT << "] " << e.what() << std::endl;
674 std::cout << " Adding '-w' on the command line may solve this problem" << std::endl;
675 throw;
676 } catch (const CLI::ParseError& e) {
677 const std::string what = e.what();
678 if (what.find("[Option Group: ") != std::string::npos) { // If CLI11 throws that error it means for us there are
679 // unconfigured anonymous instances
680 std::cout << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT
681 << " Anonymous instance(s) not configured in source code " << std::endl;
682 } else {
683 std::cout << "[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT << "] " << what << std::endl;
684 }
685 throw;
686 }
687 } catch ([[maybe_unused]] const CLI::ParseError& e) {
688 std::cout << std::endl << "Append -h or --help to your command line for more information." << std::endl;
689 } catch (const CLI::Error& e) {
690 std::cout << "[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT << "] " << e.what() << std::endl;
691
692 std::cout << std::endl << "Append -h or --help to your command line for more information." << std::endl;
693 }
694
695 return success;
696 }
CLI::App * getApp() const
CLI::App * getApp() const
std::string getConfigFile() const
@ FG_DEFAULT
Definition Logger.h:69
static void createCommandLineTemplate(std::stringstream &out, CLI::App *app, CLI::CallForCommandline::Mode mode)
Definition Config.cpp:548

References app, argc, argv, CLI::CallForShowConfig::CallForShowConfig(), CLI::CallForWriteConfig::CallForWriteConfig(), utils::createCommandLineTemplate(), Color::FG_BLUE, Color::FG_DEFAULT, Color::FG_GREEN, Color::FG_RED, CLI::CallForCommandline::getApp(), CLI::CallForShowConfig::getApp(), CLI::CallForWriteConfig::getConfigFile(), CLI::CallForCommandline::getMode(), utils::DaemonSignaled::getPid(), helpTriggerApp, and showConfigTriggerApp.

Referenced by bootstrap().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ removeInstance()

bool Config::removeInstance ( CLI::App * instance)
static

Definition at line 917 of file Config.cpp.

917 {
918 Config::required(instance, false);
919
920 return app->remove_subcommand(instance);
921 }

References app, and required().

Referenced by net::config::ConfigInstance::~ConfigInstance().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ required()

void Config::required ( CLI::App * instance,
bool required = true )
static

Definition at line 866 of file Config.cpp.

866 {
867 if (required) {
868 app->needs(instance);
869
870 for (const auto& sub : instance->get_subcommands([](const CLI::App* sc) -> bool {
871 return sc->get_required();
872 })) {
873 instance->needs(sub);
874 }
875 } else {
876 app->remove_needs(instance);
877
878 for (const auto& sub : instance->get_subcommands([](const CLI::App* sc) -> bool {
879 return sc->get_required();
880 })) {
881 instance->remove_needs(sub);
882 }
883 }
884
885 instance->required(required);
886 instance->ignore_case(required);
887 }

References app.

Referenced by removeInstance(), and net::config::ConfigInstance::required().

Here is the caller graph for this function:

◆ terminate()

void Config::terminate ( )
static

Definition at line 698 of file Config.cpp.

698 {
699 if ((*app)["--daemonize"]->as<bool>()) {
700 std::ifstream pidFile(pidDirectory + "/" + applicationName + ".pid", std::ifstream::in);
701
702 if (pidFile.good()) {
703 pid_t pid = 0;
704 pidFile >> pid;
705
706 if (getpid() == pid) {
708 }
709 }
710 } else if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) >= 0) {
711 char buf[1024];
712 while (read(STDIN_FILENO, buf, 1024) > 0) {
713 }
714 }
715 }
static void erasePidFile(const std::string &pidFileName)
Definition Daemon.cpp:200
ssize_t read(int fd, void *buf, std::size_t count)
Definition unistd.cpp:57

References app, applicationName, utils::Daemon::erasePidFile(), and pidDirectory.

Referenced by core::EventLoop::free().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ aliases

std::map< std::string, std::string > Config::aliases
staticprivate

Definition at line 157 of file Config.h.

Referenced by addInstance(), bootstrap(), and init().

◆ app

std::shared_ptr< CLI::App > Config::app = makeApp()
static

◆ applicationName

std::string Config::applicationName
staticprivate

Definition at line 137 of file Config.h.

Referenced by bootstrap(), getApplicationName(), init(), parse1(), and terminate().

◆ applicationOptions

std::map< std::string, CLI::Option * > Config::applicationOptions
staticprivate

Definition at line 158 of file Config.h.

Referenced by addStringOption(), addStringOption(), addStringOption(), and addStringOption().

◆ argc

int Config::argc = 0
static

Definition at line 132 of file Config.h.

Referenced by init(), parse1(), and parse2().

◆ argv

char ** Config::argv = nullptr
static

Definition at line 133 of file Config.h.

Referenced by init(), parse1(), and parse2().

◆ configDirectory

std::string Config::configDirectory
staticprivate

Definition at line 139 of file Config.h.

Referenced by init().

◆ daemonizeOpt

CLI::Option * Config::daemonizeOpt = nullptr
staticprivate

Definition at line 143 of file Config.h.

Referenced by bootstrap(), and init().

◆ enforceLogFileOpt

CLI::Option * Config::enforceLogFileOpt = nullptr
staticprivate

Definition at line 147 of file Config.h.

Referenced by init().

◆ groupNameOpt

CLI::Option * Config::groupNameOpt = nullptr
staticprivate

Definition at line 146 of file Config.h.

Referenced by bootstrap(), and init().

◆ helpTriggerApp

CLI::App * Config::helpTriggerApp = nullptr
static

Definition at line 153 of file Config.h.

Referenced by addHelp(), addSimpleHelp(), bootstrap(), and parse2().

◆ logDirectory

std::string Config::logDirectory
staticprivate

Definition at line 140 of file Config.h.

Referenced by init().

◆ logFileOpt

CLI::Option * Config::logFileOpt = nullptr
staticprivate

Definition at line 144 of file Config.h.

Referenced by bootstrap(), and init().

◆ logLevelOpt

CLI::Option * Config::logLevelOpt = nullptr
staticprivate

Definition at line 148 of file Config.h.

Referenced by getLogLevel(), init(), and parse1().

◆ pidDirectory

std::string Config::pidDirectory
staticprivate

Definition at line 141 of file Config.h.

Referenced by bootstrap(), init(), parse1(), and terminate().

◆ quietOpt

CLI::Option * Config::quietOpt = nullptr
staticprivate

Definition at line 150 of file Config.h.

Referenced by init(), and parse1().

◆ sectionFormatter

std::shared_ptr< CLI::Formatter > Config::sectionFormatter = makeSectionFormatter()
staticprivate

Definition at line 129 of file Config.h.

Referenced by addInstance().

◆ showConfigTriggerApp

CLI::App * Config::showConfigTriggerApp = nullptr
static

Definition at line 154 of file Config.h.

Referenced by addStandardFlags(), bootstrap(), and parse2().

◆ subParse

bool utils::Config::subParse
staticprivate

Definition at line 136 of file Config.h.

◆ userNameOpt

CLI::Option * Config::userNameOpt = nullptr
staticprivate

Definition at line 145 of file Config.h.

Referenced by bootstrap(), and init().

◆ verboseLevelOpt

CLI::Option * Config::verboseLevelOpt = nullptr
staticprivate

Definition at line 149 of file Config.h.

Referenced by getVerboseLevel(), init(), and parse1().


The documentation for this class was generated from the following files: