From b5aa78a59f7d143bee59e758f91d991e61fdcb01 Mon Sep 17 00:00:00 2001 From: lukas Date: Mon, 15 Mar 2021 17:33:20 +0100 Subject: [PATCH] drop dependency of libconfig and write own simple parser --- .gitlab-ci.yml | 2 - CMakeLists.txt | 5 +- conanfile.txt | 1 - config/dynuiprefresher.cfg | 10 +- inc/CMDParser.h | 23 ++++ inc/Config.h | 3 + src/CMDParser.cpp | 42 +++++++ src/Config.cpp | 239 ++++++++++++++++++++----------------- src/main.cpp | 61 +++------- 9 files changed, 223 insertions(+), 163 deletions(-) create mode 100644 inc/CMDParser.h create mode 100644 src/CMDParser.cpp diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1bee0a8..886853e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,8 +16,6 @@ conan: script: - conan profile new default --detect --force # Generates default profile detecting GCC and sets old ABI - conan profile update settings.compiler.libcxx=libstdc++11 default # Sets libcxx to C++11 ABI - - conan remote add bintray https://api.bintray.com/conan/lheili/LibConfig --force - - conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan --force - mkdir -p build # create build folder - CONAN_SYSREQUIRES_MODE=disabled conan install . --build=missing -g cmake -if build - cmake -S . -B build -D WinBuild=OFF -D GUI=OFF #cmake project diff --git a/CMakeLists.txt b/CMakeLists.txt index e4166fc..7f826fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,12 +141,13 @@ add_library(libdynuiprefresher ${LIB_METHOD} src/IpHelper.cpp src/FileLogger.cpp src/Logger.cpp - src/Config.cpp) + src/Config.cpp + src/CMDParser.cpp) add_executable(${Application_Name} src/main.cpp) # LINK generated LIBS # -target_link_libraries(${Application_Name} libdynuiprefresher api CONAN_PKG::libcurl CONAN_PKG::LibConfig) +target_link_libraries(${Application_Name} libdynuiprefresher api CONAN_PKG::libcurl) # setting install targets IF (NOT ${WinBuild}) diff --git a/conanfile.txt b/conanfile.txt index 81620f8..438ac93 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -1,7 +1,6 @@ [requires] libcurl/7.72.0 openssl/1.1.1i -LibConfig/1.7.2@LibConfig/stable [generators] cmake diff --git a/config/dynuiprefresher.cfg b/config/dynuiprefresher.cfg index e8a0dc5..5ce60aa 100644 --- a/config/dynuiprefresher.cfg +++ b/config/dynuiprefresher.cfg @@ -3,10 +3,10 @@ # Lukas Heiligenbrunner ## DYNU API Config -dynuapikey = "" -domainid = "" -domainname = "" +dynuapikey= +domainid= +domainname= ## Telegram API Config (optional) -#telegramApiKey = "" -#chatId = "" +#telegramApiKey= +#chatId= diff --git a/inc/CMDParser.h b/inc/CMDParser.h new file mode 100644 index 0000000..ec8e6ca --- /dev/null +++ b/inc/CMDParser.h @@ -0,0 +1,23 @@ +// +// Created by lukas on 15.03.21. +// + +#pragma once + +class CMDParser { +public: + class Arguments { + public: + // enable loop mode + bool loop = false; + bool force = false; + // enable currentIP mode + bool currentIP = false; + }; + + Arguments* parseArguments(int argc, char *argv[]); +private: + Arguments args; + + void processParameter(char *arg); +}; diff --git a/inc/Config.h b/inc/Config.h index db806e7..b478ddc 100644 --- a/inc/Config.h +++ b/inc/Config.h @@ -97,6 +97,9 @@ private: */ Config() = default; + static void writeDefaultConfig(); + static void setParam(const std::string key, const std::string value); + /** * helper variable for managing telegram Support */ diff --git a/src/CMDParser.cpp b/src/CMDParser.cpp new file mode 100644 index 0000000..ec4443d --- /dev/null +++ b/src/CMDParser.cpp @@ -0,0 +1,42 @@ +// +// Created by lukas on 15.03.21. +// + +#include +#include +#include +#include +#include "CMDParser.h" + +CMDParser::Arguments* CMDParser::parseArguments(int argc, char **argv) { + for (int i = 1; i < argc; i++) { + this->processParameter(argv[i]); + } + return &args; +} + +void CMDParser::processParameter(char *arg) { + const std::string param = std::string(arg); + + if (param == "-h" || param == "--help") { + std::cout << "help page: " << std::endl << "[-h] [--help] print this help page" << std::endl + << "[-v] [--version] print the software version" << std::endl + << "[-f] [--force] force refresh of ip" << std::endl + << "[-l] [--loop] infinite loop to refresh ip every five minutes" << std::endl + << "[-c] [--checkconfig] validate configuration" << std::endl + << "[-ip] [--currentip] get current global ip" << std::endl + << "[no argument] normal ip check and refresh" << std::endl; + exit(0); + } else if (param == "-v" || param == "--version") { + std::cout << "Version " << StaticData::VERSION << std::endl; + exit(0); + } else if (param == "-f" || param == "--force") { + args.force = true; + } else if (param == "-l" || param == "--loop") { + args.loop = true; + } else if (param == "-ip" || param == "--currentip") { + args.currentIP = true; + } else { + Logger::message("unknown argument: " + param + "! -h for help"); + } +} diff --git a/src/Config.cpp b/src/Config.cpp index e51d84e..b76736a 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include std::string Config::dynuapikey; std::string Config::domainid; //id of the dynu domain @@ -18,75 +18,34 @@ std::string Config::chatId; bool Config::telegramSupport; bool Config::readConfig() { - libconfig::Config cfg; - try { - cfg.readFile(std::string(StaticData::ConfigDir + StaticData::ConfName).c_str()); - } - catch (const libconfig::FileIOException &fioex) { - std::cout << "I/O error while reading config file." << std::endl << "creating new config file!" << std::endl; - - // check if config folder exists - struct stat info{}; - - if (stat(StaticData::ConfigDir.c_str(), &info) != 0) { - Logger::warning("The config folder doesn't exist. Trying to create it."); - -// mkdir command is different defined for windows -#ifdef __unix - int check = mkdir(StaticData::ConfigDir.c_str(), 777); -#else - int check = mkdir(StaticData::ConfigDir.c_str()); -#endif - - // check if directory is created or not - if (!check) - Logger::message("config directory successfully created. "); - else - Logger::error("unable to create config directory."); - - } else if (info.st_mode & S_IFDIR) { - Logger::debug("config directory exists already"); - } else { - Logger::error("A file exists with the same name as the config dir should be"); - } - - - std::ofstream myfile; - myfile.open(StaticData::ConfigDir + StaticData::ConfName); - if (myfile.is_open()) { - myfile << StaticData::SAMPLECONFIG; - myfile.close(); - } else { - Logger::error("error creating file"); - } - - return false; - } - catch (const libconfig::ParseException &pex) { - std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine() - << " - " << pex.getError() << std::endl; + // Read from the text file + std::ifstream MyReadFile; + MyReadFile.open(std::string(StaticData::ConfigDir + StaticData::ConfName)); + if (!MyReadFile) { + // file does not exist + writeDefaultConfig(); return false; } - try { - // needed parameters - dynuapikey = (std::string) cfg.lookup("dynuapikey"); - domainid = (std::string) cfg.lookup("domainid"); - domainname = (std::string) cfg.lookup("domainname"); - // optional parameters - telegramApiKey = (std::string) cfg.lookup("telegramApiKey"); - chatId = (std::string) cfg.lookup("chatId"); - telegramSupport = true; - } - catch (const libconfig::SettingNotFoundException &nfex) { - // triggered if setting is missing in config - if (!(std::strcmp("telegramApiKey", nfex.getPath()) == 0 || std::strcmp("chatId", nfex.getPath()) == 0)) { - std::cerr << "No '" << nfex.getPath() << "' setting in configuration file." << std::endl; - } else { - Logger::message("no Telegram support - fields in config not set"); - telegramSupport = false; + std::string line; + while (getline(MyReadFile, line)) { + // ignore line if it starts with # + if(line.rfind('#', 0) == 0 || line.empty()){ + continue; + } + + std::istringstream is_line(line); + std::string key; + if (std::getline(is_line, key, '=')) { + std::string value; + if (std::getline(is_line, value)) + setParam(key, value); } } + + // Close the file + MyReadFile.close(); + // check if needed values aren't empty return !(Config::dynuapikey.empty() || Config::domainid.empty() || Config::domainname.empty()); } @@ -97,51 +56,51 @@ bool Config::saveConfig() { } bool Config::validateConfig() { - libconfig::Config cfg; - try { - Logger::message("reading config file: " + std::string(StaticData::ConfigDir + StaticData::ConfName)); - cfg.readFile(std::string(StaticData::ConfigDir + StaticData::ConfName).c_str()); - } - catch (const libconfig::FileIOException &fioex) { - Logger::warning("config file doesn't exist or permission denied!"); - return false; - } - catch (const libconfig::ParseException &pex) { - std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine() - << " - " << pex.getError() << std::endl; - return false; - } - Logger::message("Syntax and Permission is OK"); - - try { - // needed parameters - if (((std::string) cfg.lookup("dynuapikey")).empty()) { - Logger::warning("required parameter \"dynuapikey\" seems to be empty."); - return false; - } - if (((std::string) cfg.lookup("domainid")).empty()) { - Logger::warning("required parameter \"domainid\" seems to be empty."); - return false; - } - if (((std::string) cfg.lookup("domainname")).empty()) { - Logger::warning("required parameter \"domainname\" seems to be empty."); - return false; - } - // optional parameters - cfg.lookup("telegramApiKey"); - cfg.lookup("chatId"); - telegramSupport = true; - } - catch (const libconfig::SettingNotFoundException &nfex) { - // triggered if setting is missing in config - if (!(std::strcmp("telegramApiKey", nfex.getPath()) == 0 || std::strcmp("chatId", nfex.getPath()) == 0)) { - std::cerr << "No '" << nfex.getPath() << "' setting in configuration file." << std::endl; - return false; - } else { - Logger::message("no Telegram support - fields in config not set"); - telegramSupport = false; - } - } +// libconfig::Config cfg; +// try { +// Logger::message("reading config file: " + std::string(StaticData::ConfigDir + StaticData::ConfName)); +// cfg.readFile(std::string(StaticData::ConfigDir + StaticData::ConfName).c_str()); +// } +// catch (const libconfig::FileIOException &fioex) { +// Logger::warning("config file doesn't exist or permission denied!"); +// return false; +// } +// catch (const libconfig::ParseException &pex) { +// std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine() +// << " - " << pex.getError() << std::endl; +// return false; +// } +// Logger::message("Syntax and Permission is OK"); +// +// try { +// // needed parameters +// if (((std::string) cfg.lookup("dynuapikey")).empty()) { +// Logger::warning("required parameter \"dynuapikey\" seems to be empty."); +// return false; +// } +// if (((std::string) cfg.lookup("domainid")).empty()) { +// Logger::warning("required parameter \"domainid\" seems to be empty."); +// return false; +// } +// if (((std::string) cfg.lookup("domainname")).empty()) { +// Logger::warning("required parameter \"domainname\" seems to be empty."); +// return false; +// } +// // optional parameters +// cfg.lookup("telegramApiKey"); +// cfg.lookup("chatId"); +// telegramSupport = true; +// } +// catch (const libconfig::SettingNotFoundException &nfex) { +// // triggered if setting is missing in config +// if (!(std::strcmp("telegramApiKey", nfex.getPath()) == 0 || std::strcmp("chatId", nfex.getPath()) == 0)) { +// std::cerr << "No '" << nfex.getPath() << "' setting in configuration file." << std::endl; +// return false; +// } else { +// Logger::message("no Telegram support - fields in config not set"); +// telegramSupport = false; +// } +// } return true; } @@ -175,8 +134,66 @@ void Config::setValues(const std::string &domainname, const std::string &dynuapi Config::domainid = domainid; } -void Config::setValues(const std::string &domainname, const std::string &dynuapikey, const std::string &domainid, const std::string &telegramApiKey, const std::string &chatId) { +void Config::setValues(const std::string &domainname, const std::string &dynuapikey, const std::string &domainid, + const std::string &telegramApiKey, const std::string &chatId) { setValues(domainname, dynuapikey, domainid); Config::telegramApiKey = telegramApiKey; Config::chatId = chatId; } + +void Config::writeDefaultConfig() { + std::cout << "I/O error while reading config file." << std::endl << "creating new config file!" << std::endl; + + // check if config folder exists + struct stat info{}; + + if (stat(StaticData::ConfigDir.c_str(), &info) != 0) { + Logger::warning("The config folder doesn't exist. Trying to create it."); + +// mkdir command is different defined for windows +#ifdef __unix + int check = mkdir(StaticData::ConfigDir.c_str(), 777); +#else + int check = mkdir(StaticData::ConfigDir.c_str()); +#endif + + // check if directory is created or not + if (!check) + Logger::message("config directory successfully created. "); + else + Logger::error("unable to create config directory."); + + } else if (info.st_mode & S_IFDIR) { + Logger::debug("config directory exists already"); + } else { + Logger::error("A file exists with the same name as the config dir should be"); + } + + + std::ofstream myfile; + myfile.open(StaticData::ConfigDir + StaticData::ConfName); + if (myfile.is_open()) { + myfile << StaticData::SAMPLECONFIG; + myfile.close(); + } else { + Logger::error("error creating file"); + } +} + +void Config::setParam(const std::string key, const std::string value) { + if (key == "dynuapikey") + dynuapikey = value; + else if (key == "domainid") + domainid = value; + else if (key == "domainname") + domainname = value; + else if (key == "telegramApiKey") + telegramApiKey = value; + else if (key == "chatId") + chatId = value; + else + Logger::warning("unkown key in config file: " + key); + + if (!telegramApiKey.empty()) + telegramSupport = true; +} diff --git a/src/main.cpp b/src/main.cpp index 3070c4e..82bb5ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ -#include "StaticData.h" +#include +#include #include "IPRefresher.h" -#include "Logger.h" #include "Config.h" #include "api/IPAPI.h" @@ -8,49 +8,26 @@ * application entry point */ int main(int argc, char *argv[]) { - if (argc > 1) { - std::string firstarg(argv[1]); - if (firstarg == "-h" || firstarg == "--help") { - std::cout << "help page: " << std::endl << "[-h] [--help] print this help page" << std::endl - << "[-v] [--version] print the software version" << std::endl - << "[-f] [--force] force refresh of ip" << std::endl - << "[-l] [--loop] infinite loop to refresh ip every five minutes" << std::endl - << "[-c] [--checkconfig] validate configuration" << std::endl - << "[-ip] [--currentip] get current global ip" << std::endl - << "[no argument] normal ip check and refresh" << std::endl; - } else if (firstarg == "-v" || firstarg == "--version") { - std::cout << "Version " << StaticData::VERSION << std::endl; - } else if (firstarg == "-f" || firstarg == "--force") { - if (Config::readConfig()) { - IPRefresher::checkIPAdress(true); - } else { - std::cout << "incorrect credentials!" << std::endl; - } + CMDParser parser; + CMDParser::Arguments *args = parser.parseArguments(argc, argv); - } else if (firstarg == "-l" || firstarg == "--loop") { - IPRefresher::startUpService(true); - } else if (firstarg == "-c" || firstarg == "--checkconfig") { - if (Config::validateConfig()) { - Logger::message("Config file is OK"); - } else { - Logger::error("There are errors in config file!"); - return -1; - } - } else if (firstarg == "-ip" || firstarg == "--currentip") { - IPAPI ipapi; - const std::string ip = ipapi.getGlobalIp(); + if (args->currentIP) { + IPAPI ipapi; + const std::string ip = ipapi.getGlobalIp(); - std::cout << "Current global IP: " << ip << std::endl; - } else { - Logger::message("wrong arguments! -h for help"); - } + std::cout << "Current global IP: " << ip << std::endl; + return 0; + } + + // loop mode + if (args->loop) + IPRefresher::startUpService(true); + + // default mode + if (Config::readConfig()) { + IPRefresher::checkIPAdress(args->force); } else { - Logger::message("starting check"); - if (Config::readConfig()) { - IPRefresher::checkIPAdress(false); - } else { - std::cout << "incorrect credentials!" << std::endl; - } + Logger::error("incorrect credentials!"); } return 0;