Improve cxxopts usage to avoid segfaults

This commit is contained in:
2025-08-29 17:16:10 +02:00
parent 4166a05a7f
commit fffd611a52
2 changed files with 96 additions and 27 deletions

View File

@@ -10,7 +10,26 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
std::optional<cxxopts::ParseResult> ExtractArgs(int argc, char ** argv) struct CommandlineParameters
{
CommandlineParameters(std::string const & serialDevicePath, std::string const & databaseConnectionString)
: DeviceType(serialDevicePath), DatabaseConnectionString(databaseConnectionString) { };
std::string DeviceType;
std::string DatabaseConnectionString;
};
std::optional<std::string> TryGetStringArgument(cxxopts::ParseResult const & parseResult, std::string const & name)
{
if(!parseResult.contains(name))
{
return {};
}
return parseResult[name].as_optional<std::string>();
}
std::optional<CommandlineParameters> TryGetCommandlineArguments(int argc, char ** argv)
{ {
cxxopts::Options options( cxxopts::Options options(
"electricity-logger", "electricity-logger",
@@ -24,22 +43,25 @@ std::optional<cxxopts::ParseResult> ExtractArgs(int argc, char ** argv)
"Path to the sqlite3 database file", "Path to the sqlite3 database file",
cxxopts::value<std::string>()); cxxopts::value<std::string>());
if(argc == 1)
{
std::cout << options.help() << std::endl;
return {};
}
try try
{ {
auto const parsed = options.parse(argc, argv); auto const parseResult = options.parse(argc, argv);
return parsed; auto const serialDevicePath = TryGetStringArgument(parseResult, "serial-device");
auto const databaseConnectionString = TryGetStringArgument(parseResult, "connection-string");
if(serialDevicePath.has_value() && databaseConnectionString.has_value())
{
return CommandlineParameters(serialDevicePath.value(), databaseConnectionString.value());
}
} }
catch(cxxopts::exceptions::exception const & e) catch(cxxopts::exceptions::exception const & e)
{ {
spdlog::error(e.what()); spdlog::error(e.what());
return {}; return {};
} }
std::cout << options.help() << std::endl;
return {};
} }
DSMR::Data ReadData(std::string const & devicePath) DSMR::Data ReadData(std::string const & devicePath)
@@ -100,18 +122,15 @@ DSMR::Data ReadData(std::string const & devicePath)
int main(int argc, char ** argv) int main(int argc, char ** argv)
{ {
auto const maybeArgs = ExtractArgs(argc, argv); auto const parameters = TryGetCommandlineArguments(argc, argv);
if(!maybeArgs.has_value()) if(!parameters.has_value())
{ {
return 1; return 1;
} }
auto const & args = maybeArgs.value(); auto const data = ReadData(parameters->DeviceType);
auto const data = ReadData(args["serial-device"].as<std::string>()); Database db(parameters->DatabaseConnectionString);
auto const connectionStringValue = args["connection-string"].as<std::string>();
Database db(connectionStringValue);
db.Insert(data, std::time(nullptr)); db.Insert(data, std::time(nullptr));
return 0; return 0;

View File

@@ -21,7 +21,43 @@ namespace detail
} }
} }
std::optional<cxxopts::ParseResult> ExtractArgs(int argc, char ** argv) struct CommandlineParameters
{
CommandlineParameters(
std::string const & deviceType,
std::string const & deviceUrl,
unsigned const deviceFetchTimeOut,
std::string const & databaseConnectionString)
: DeviceType(deviceType), DeviceUrl(deviceUrl), DeviceFetchTimeOut(deviceFetchTimeOut),
DatabaseConnectionString(databaseConnectionString) { };
std::string DeviceType;
std::string DeviceUrl;
unsigned DeviceFetchTimeOut;
std::string DatabaseConnectionString;
};
std::optional<std::string> TryGetStringArgument(cxxopts::ParseResult const & parseResult, std::string const & name)
{
if(!parseResult.contains(name))
{
return {};
}
return parseResult[name].as_optional<std::string>();
}
std::optional<unsigned> TryGetUnsignedArgument(cxxopts::ParseResult const & parseResult, std::string const & name)
{
if(!parseResult.contains(name))
{
return {};
}
return parseResult[name].as_optional<unsigned>();
}
std::optional<CommandlineParameters> TryGetCommandlineArguments(int argc, char ** argv)
{ {
cxxopts::Options options( cxxopts::Options options(
"solar-logger", "solar-logger",
@@ -49,14 +85,30 @@ std::optional<cxxopts::ParseResult> ExtractArgs(int argc, char ** argv)
try try
{ {
auto const parsed = options.parse(argc, argv); auto const parseResult = options.parse(argc, argv);
return parsed; auto const deviceType = TryGetStringArgument(parseResult, "type");
auto const deviceUrl = TryGetStringArgument(parseResult, "url");
auto const deviceFetchTimeOut = TryGetUnsignedArgument(parseResult, "timeout");
auto const databaseConnectionString = TryGetStringArgument(parseResult, "connection-string");
if(deviceType.has_value() && deviceUrl.has_value() && deviceFetchTimeOut.has_value()
&& databaseConnectionString.has_value())
{
return CommandlineParameters(
deviceType.value(),
deviceUrl.value(),
deviceFetchTimeOut.value(),
databaseConnectionString.value());
}
} }
catch(cxxopts::exceptions::exception const & e) catch(cxxopts::exceptions::exception const & e)
{ {
spdlog::error(e.what()); spdlog::error(e.what());
return {}; return {};
} }
std::cout << options.help() << std::endl;
return {};
} }
std::optional<std::string> FetchDataFromURL(const std::string & url, const unsigned int timeout) std::optional<std::string> FetchDataFromURL(const std::string & url, const unsigned int timeout)
@@ -97,21 +149,19 @@ std::optional<std::string> FetchDataFromURL(const std::string & url, const unsig
int main(int argc, char ** argv) int main(int argc, char ** argv)
{ {
auto const maybeArgs = ExtractArgs(argc, argv); auto const parameters = TryGetCommandlineArguments(argc, argv);
if(!maybeArgs.has_value()) if(!parameters.has_value())
{ {
return 1; return 1;
} }
auto const & args = maybeArgs.value(); Database db(parameters->DatabaseConnectionString);
Database db(args["connection-string"].as<std::string>());
auto const now = std::time(nullptr); auto const now = std::time(nullptr);
auto const resourceType = args["type"].as<std::string>(); auto const resourceType = parameters->DeviceType;
if(resourceType == "Zeverlution") if(resourceType == "Zeverlution")
{ {
auto const webResource = FetchDataFromURL(args["url"].as<std::string>(), args["timeout"].as<unsigned>()); auto const webResource = FetchDataFromURL(parameters->DeviceUrl, parameters->DeviceFetchTimeOut);
if(!webResource.has_value()) if(!webResource.has_value())
{ {
return -1; return -1;
@@ -136,7 +186,7 @@ int main(int argc, char ** argv)
} }
else if(resourceType == "Envoy") else if(resourceType == "Envoy")
{ {
auto const webResource = FetchDataFromURL(args["url"].as<std::string>(), args["timeout"].as<unsigned>()); auto const webResource = FetchDataFromURL(parameters->DeviceUrl, parameters->DeviceFetchTimeOut);
if(!webResource.has_value()) if(!webResource.has_value())
{ {
return -1; return -1;