diff --git a/src/api/cpp/GravityConfigParser.cpp b/src/api/cpp/GravityConfigParser.cpp index 5da067f71..bc0e4a151 100644 --- a/src/api/cpp/GravityConfigParser.cpp +++ b/src/api/cpp/GravityConfigParser.cpp @@ -37,9 +37,15 @@ int GravityConfigParser::CONFIG_REQUEST_TIMEOUT = 4000; bool GravityConfigParser::hasKey(std::string key) { return key_value_map.count(StringCopyToLowerCase(key)) > 0; } +// may be useless... +void GravityConfigParser::setDirectory(std::string dir) { config_dir = dir; } + +void GravityConfigParser::setComponentID(std::string componentID) { this->componentID = componentID; } + GravityConfigParser::GravityConfigParser(std::string componentID) { this->componentID = componentID; } -void GravityConfigParser::ParseConfigFile(const char *config_filename) +// filename includes full file path +void GravityConfigParser::parseConfigFile(std::string config_filename) { std::vector sections; @@ -47,7 +53,7 @@ void GravityConfigParser::ParseConfigFile(const char *config_filename) sections.push_back("general"); sections.push_back(NULL); - KeyValueConfigParser parser(config_filename, sections); + KeyValueConfigParser parser(config_filename.c_str(), sections); std::vector keys = parser.GetKeys(); @@ -57,10 +63,17 @@ void GravityConfigParser::ParseConfigFile(const char *config_filename) std::string key_lower = StringCopyToLowerCase(*i); key_value_map[key_lower] = value; } - return; } -void GravityConfigParser::ParseConfigService(GravityNode &gn) +void GravityConfigParser::parseComponentConfigFile() +{ + if (this->componentID != "") + { + parseConfigFile(this->componentID + ".ini"); + } +} + +void GravityConfigParser::parseConfigService(GravityNode &gn) { //Prepare request GravityDataProduct dataproduct("ConfigRequestPB"); diff --git a/src/api/cpp/GravityConfigParser.h b/src/api/cpp/GravityConfigParser.h index 94a80b234..168a5d004 100644 --- a/src/api/cpp/GravityConfigParser.h +++ b/src/api/cpp/GravityConfigParser.h @@ -38,16 +38,21 @@ class GravityConfigParser GravityConfigParser(std::string componentID); bool hasKey(std::string key); + void setDirectory(std::string dir); + void setComponentID(std::string componentID); /** Update configuration based on .ini file */ - void ParseConfigFile(const char* config_filename); + void parseConfigFile(std::string config_filename); + /** Update configuration based on .ini file, if componentID is non-empty */ + void parseComponentConfigFile(); /** Update configuration based on Config Service */ - void ParseConfigService(GravityNode& gn); + void parseConfigService(GravityNode& gn); std::string getString(std::string key, std::string default_value = ""); private: std::string componentID; + std::string config_dir; std::map key_value_map; static int CONFIG_REQUEST_TIMEOUT; diff --git a/src/api/cpp/GravityNode.cpp b/src/api/cpp/GravityNode.cpp index a446a894e..4f9ae98a6 100644 --- a/src/api/cpp/GravityNode.cpp +++ b/src/api/cpp/GravityNode.cpp @@ -431,8 +431,6 @@ GravityNode::GravityNode() logInitialized = false; listenerEnabled = false; heartbeatStarted = false; - - parser = NULL; } GravityNode::GravityNode(std::string componentID) @@ -454,8 +452,6 @@ GravityNode::GravityNode(std::string componentID) logInitialized = false; heartbeatStarted = false; - parser = NULL; - init(componentID); } @@ -552,11 +548,6 @@ GravityNode::~GravityNode() zmq_term(context); } - if (parser) - { - delete parser; - } - //Do not destroy object until sub manager thread is joined if (subscriptionManagerThread.joinable()) { @@ -663,48 +654,57 @@ void GravityNode::configSpdLoggers() } } -GravityReturnCode GravityNode::init() +GravityReturnCode GravityNode::init(std::string componentID, std::string configFilepath) { - //////////////////////////////////////////////////////// - //get gravity configuration. - parser = new GravityConfigParser(""); + static const std::string fallback_component_id = "GravityNode"; + parser = std::unique_ptr(new GravityConfigParser(componentID)); - parser->ParseConfigFile("Gravity.ini"); + this->componentID = componentID; // this may change further down if it's an empty string - std::string id = parser->getString("GravityComponentID", ""); - - if (id != "") + // we always parse the default config file first (Gravity.ini) + if (configFilepath.empty()) // default configurations + { + parser->parseConfigFile("Gravity.ini"); + std::string config_file_name = componentID + ".ini"; + if (gravity::IsValidFilename(config_file_name)) + { + parser->parseConfigFile(config_file_name.c_str()); + } + } + else // user specified a specific file to parse { - return init(id); + parser->parseConfigFile(configFilepath); } - else + + + // empty componentID: discover from config file + if (componentID == "") { - componentID = "GravityNode"; - //Setup Logging if enabled. - if (!logInitialized) + std::string id = parser->getString("GravityComponentID", ""); + if (id != "") { - Log::LogLevel local_log_level = Log::LogStringToLevel(getStringParam("LocalLogLevel", "none").c_str()); - if (local_log_level != Log::NONE) - Log::initAndAddFileLogger(getStringParam("LogDirectory", "").c_str(), componentID.c_str(), - local_log_level, getBoolParam("CloseLogFileAfterWrite", false)); + // we found a non-empty component ID + this->componentID = id; + } + else + { + this->componentID = fallback_component_id; + } + // update the parser's componentID + parser->setComponentID(this->componentID); + } - Log::LogLevel console_log_level = Log::LogStringToLevel(getStringParam("ConsoleLogLevel", "none").c_str()); - if (console_log_level != Log::NONE) Log::initAndAddConsoleLogger(componentID.c_str(), console_log_level); + parser->parseComponentConfigFile(); - //log an error indicating the componentID was missing - logger->error( - "Field 'GravityComponentID' missing from Gravity.ini, using GravityComponentID='GravityNode'"); + configSpdLoggers(); - logInitialized = true; - } - return init(componentID); + if (this->componentID == fallback_component_id) + { + logger->error("Field 'GravityComponentID' missing from Gravity.ini, using GravityComponentID='{}'", + fallback_component_id); } -} -GravityReturnCode GravityNode::init(std::string componentID) -{ GravityReturnCode ret = GravityReturnCodes::SUCCESS; - this->componentID = componentID; std::string serviceDirectoryUrl = ""; bool domainTimeout = false; @@ -717,34 +717,6 @@ GravityReturnCode GravityNode::init(std::string componentID) // Setup zmq context if (!initialized) { - //////////////////////////////////////////////////////// - //Now that Gravity is set up, get gravity configuration. - parser = new GravityConfigParser(componentID); - - parser->ParseConfigFile("Gravity.ini"); - std::string config_file_name = componentID + ".ini"; - if (gravity::IsValidFilename(config_file_name)) - { - parser->ParseConfigFile(config_file_name.c_str()); - } - - // Setup Logging as soon as config parser is available. - if (!logInitialized) - { - Log::LogLevel local_log_level = Log::LogStringToLevel(getStringParam("LocalLogLevel", "none").c_str()); - if (local_log_level != Log::NONE) - Log::initAndAddFileLogger(getStringParam("LogDirectory", "").c_str(), componentID.c_str(), - local_log_level, getBoolParam("CloseLogFileAfterWrite", false)); - - Log::LogLevel console_log_level = Log::LogStringToLevel(getStringParam("ConsoleLogLevel", "none").c_str()); - if (console_log_level != Log::NONE) Log::initAndAddConsoleLogger(componentID.c_str(), console_log_level); - - // Configure spdlog loggers - configSpdLoggers(); - - logInitialized = true; - } - context = zmq_init(1); if (!context) { @@ -1020,10 +992,9 @@ GravityReturnCode GravityNode::init(std::string componentID) if (componentID != "ConfigServer" && getBoolParam("NoConfigServer", false) != true) { - parser->ParseConfigService( + parser->parseConfigService( *this); //Although this is done last, this has the least priority. We just need to do it last so we know where the service directory is located. } - //parser->ParseCmdLine configureServiceManager(); configureSubscriptionManager(); diff --git a/src/api/cpp/GravityNode.h b/src/api/cpp/GravityNode.h index 783fe9bd1..09253faf6 100644 --- a/src/api/cpp/GravityNode.h +++ b/src/api/cpp/GravityNode.h @@ -238,7 +238,7 @@ class GRAVITY_API GravityNode std::string myDomain; std::string componentID; std::map dataRegistrationTimeMap; // Maps data product id to registration time - GravityConfigParser* parser; + std::unique_ptr parser; GravityConfigParamPB configParamPB; GravityDataProduct settingsGDP = GravityDataProduct(gravity::constants::GRAVITY_SETTINGS_DPID); @@ -283,14 +283,16 @@ class GRAVITY_API GravityNode public: /** - * Default Constructor + * Default Constructor. Does not call init(). */ GravityNode(); /** - * Constructor that also initializes - * \param componentID ID of the component to initialize - */ + * Constructor that also calls init(), passing the component ID. + * \param componentID ID of the component to initialize + * \note Setting the GRAVITY_CONFIG_DIR environment variable will cause GravityNode to look in + * a different directory for configuration files than the current directory. + */ GravityNode(std::string componentID); /** @@ -298,19 +300,16 @@ class GRAVITY_API GravityNode */ virtual ~GravityNode(); - /** - * Initialize the Gravity infrastructure. - * Reads the ComponentID from the Gravity.ini file. - * \return GravityReturnCode code to identify any errors that occur during initialization - */ - GravityReturnCode init(); - /** * Initialize the Gravity infrastructure. * \copydetails GravityNode(std::string) * \return GravityReturnCode code to identify any errors that occur during initialization + * \note If componentID is an empty string (the default), the component ID will be inferred + * from the "GravityComponentID" located in the default configuration file. + * \note Setting the GRAVITY_CONFIG_DIR environment variable will cause GravityNode to look in + * a different directory for configuration files than the current directory. */ - GravityReturnCode init(std::string componentID); + GravityReturnCode init(std::string componentID = "", std::string configFilepath = ""); /** * Wait for the GravityNode to exit. diff --git a/src/api/java/src/swig/gravitynode.i b/src/api/java/src/swig/gravitynode.i index da1a650c3..b6fd61406 100755 --- a/src/api/java/src/swig/gravitynode.i +++ b/src/api/java/src/swig/gravitynode.i @@ -105,8 +105,7 @@ public: GravityNode(); GravityNode(std::string); ~GravityNode(); - GravityReturnCode init(); - GravityReturnCode init(std::string); + GravityReturnCode init(std::string="", std::string=""); void waitForExit(); GravityReturnCode registerDataProduct(const std::string& dataProductID, const GravityTransportType& transportType); GravityReturnCode registerDataProduct(const std::string& dataProductID, const GravityTransportType& transportType, bool cacheLastValue); diff --git a/src/api/python/src/swig/gravitynode.i b/src/api/python/src/swig/gravitynode.i index 2e14fd674..1335ec322 100755 --- a/src/api/python/src/swig/gravitynode.i +++ b/src/api/python/src/swig/gravitynode.i @@ -171,8 +171,7 @@ namespace gravity { GravityNode(); GravityNode(std::string); ~GravityNode(); - GravityReturnCode init(); - GravityReturnCode init(std::string); + GravityReturnCode init(std::string="", std::string=""); GravityReturnCode registerDataProduct(const std::string& dataProductID, const GravityTransportType& transportType); GravityReturnCode registerDataProduct(const std::string& dataProductID, const GravityTransportType& transportType, bool cacheLastValue); GravityReturnCode unregisterDataProduct(const std::string& dataProductID); diff --git a/src/components/cpp/Archiver/FileArchiver.cpp b/src/components/cpp/Archiver/FileArchiver.cpp index f5037554a..8cf758bad 100644 --- a/src/components/cpp/Archiver/FileArchiver.cpp +++ b/src/components/cpp/Archiver/FileArchiver.cpp @@ -31,8 +31,29 @@ using namespace std; int main(int argc, const char* argv[]) { - gravity::FileArchiver archiver; - archiver.waitForExit(); + + if (argc > 1) + { + std::string configFilepath = std::string(argv[1]); + if (configFilepath.substr(configFilepath.size() - 4) != ".ini") + { + std::cerr << "Usage: invalid filename. Must be .ini. Using default config path.\n"; + + gravity::FileArchiver archiver; + archiver.waitForExit(); + } + else + { + gravity::FileArchiver archiver(configFilepath); + archiver.waitForExit(); + } + } + else + { + gravity::FileArchiver archiver; + archiver.waitForExit(); + } + } namespace gravity @@ -40,11 +61,18 @@ namespace gravity const char* FileArchiver::ComponentName = "FileArchiver"; -FileArchiver::FileArchiver() +FileArchiver::FileArchiver(std::string configDir) { // Initialize Gravity Node - gravityNode.init(FileArchiver::ComponentName); - + if (configDir.empty()) + { + gravityNode.init(FileArchiver::ComponentName); + } + else + { + gravityNode.init(FileArchiver::ComponentName, configDir); + } + // Get Gravity logger logger = gravityNode.getGravityLogger(); if (!logger) diff --git a/src/components/cpp/Archiver/FileArchiver.h b/src/components/cpp/Archiver/FileArchiver.h index 074b3df72..937230e9e 100644 --- a/src/components/cpp/Archiver/FileArchiver.h +++ b/src/components/cpp/Archiver/FileArchiver.h @@ -45,7 +45,7 @@ class FileArchiver : public GravitySubscriber, GravityServiceProvider std::shared_ptr logger; public: - FileArchiver(); + FileArchiver(std::string configDir = ""); virtual ~FileArchiver(); virtual void subscriptionFilled(const std::vector >& dataProducts); diff --git a/src/components/cpp/ConfigServer/ConfigServer.cpp b/src/components/cpp/ConfigServer/ConfigServer.cpp index 5755fd09c..378b10e20 100644 --- a/src/components/cpp/ConfigServer/ConfigServer.cpp +++ b/src/components/cpp/ConfigServer/ConfigServer.cpp @@ -28,6 +28,7 @@ #include "spdlog/spdlog.h" #include "spdlog/fmt/fmt.h" + using namespace gravity; using namespace std; @@ -44,6 +45,8 @@ struct ConfigEntry std::string value; }; +std::string arg_path = ""; + class ConfigServer : public GravityServiceProvider { public: @@ -72,7 +75,12 @@ std::shared_ptr ConfigServer::request(const std::string serv sections.push_back(NULL); - KeyValueConfigParser parser("config_file.ini", sections); + std::string config_dir = "config_file.ini"; + if (!arg_path.empty()) { + config_dir = arg_path; + } + + KeyValueConfigParser parser(config_dir.c_str(), sections); keys = parser.GetKeys(); @@ -84,7 +92,7 @@ std::shared_ptr ConfigServer::request(const std::string serv if (!key_value_map.size()) { - cout << "Critical Error: Could not open config file: config_file.ini" << endl; + cout << "Critical Error: Could not open config file: " << config_dir << endl; return std::shared_ptr(); } @@ -107,15 +115,46 @@ std::shared_ptr ConfigServer::request(const std::string serv int main(int argc, const char** argv) { ConfigServer server; - GravityNode gn; - GravityReturnCode ret = gn.init("ConfigServer"); - while (ret != GravityReturnCodes::SUCCESS) + if (argc > 1) { - cerr << "Failed to initialize ConfigServer, retrying..." << endl; - ret = gn.init("ConfigServer"); + std::string configFilepath = std::string(argv[1]); + if (configFilepath.substr(configFilepath.size() - 4) != ".ini") + { + cerr << "Usage: invalid filename. Must be .ini. Using default config path.\n"; + + GravityReturnCode ret = gn.init("ConfigServer"); + while (ret != GravityReturnCodes::SUCCESS) + { + cerr << "Failed to initialize ConfigServer, retrying..." << endl; + ret = gn.init("ConfigServer"); + } + } + else + { + arg_path = std::string(argv[1]); + GravityReturnCode ret = gn.init("ConfigServer", configFilepath); + + while (ret != GravityReturnCodes::SUCCESS) + { + cerr << "Failed to initialize ConfigServer, retrying..." << endl; + ret = gn.init("ConfigServer", configFilepath); + } + } + } - + else + { + GravityReturnCode ret = gn.init("ConfigServer"); + + while (ret != GravityReturnCodes::SUCCESS) + { + cerr << "Failed to initialize ConfigServer, retrying..." << endl; + ret = gn.init("ConfigServer"); + } + } + + gn.registerService("ConfigService", GravityTransportTypes::TCP, server); gn.waitForExit(); diff --git a/src/components/cpp/LogRecorder/main.cpp b/src/components/cpp/LogRecorder/main.cpp index 4e6d85a93..83e65db76 100644 --- a/src/components/cpp/LogRecorder/main.cpp +++ b/src/components/cpp/LogRecorder/main.cpp @@ -20,11 +20,28 @@ #include #include "GravityLogRecorder.h" -int main() +int main(int argc, const char** argv) { using namespace gravity; GravityNode gn; - gn.init("GravityLogRecorder"); + if (argc > 1) + { + std::string configFilepath = std::string(argv[1]); + + if (configFilepath.substr(configFilepath.size() - 4) != ".ini") + { + std::cerr << "Usage: invalid filename. Must be .ini. Using default config path.\n"; + gn.init("GravityLogRecorder"); + } + else + { + gn.init("GravityLogRecorder", std::string(argv[1])); + } + } + else + { + gn.init("GravityLogRecorder"); + } LogRecorder lr(&gn, "MyBase"); diff --git a/src/components/cpp/Playback/FileReplay.cpp b/src/components/cpp/Playback/FileReplay.cpp index 1404e00db..0ae0e13a6 100644 --- a/src/components/cpp/Playback/FileReplay.cpp +++ b/src/components/cpp/Playback/FileReplay.cpp @@ -33,8 +33,19 @@ using namespace std; int main(int argc, const char* argv[]) { - gravity::FileReplay replay; - replay.waitForExit(); + std::string configFilepath = argc > 1 ? argv[1] : ""; + if (!configFilepath.empty() && configFilepath.substr(configFilepath.size() - 4) != ".ini") + { + std::cerr << "Usage: invalid filename. Must be .ini. Using default config path.\n"; + gravity::FileReplay replay; + replay.waitForExit(); + } + else + { + gravity::FileReplay replay(configFilepath); + replay.waitForExit(); + } + } namespace gravity @@ -42,10 +53,18 @@ namespace gravity const char* FileReplay::ComponentName = "FileReplay"; -FileReplay::FileReplay() +FileReplay::FileReplay(std::string configDir) { // Initialize Gravity Node - gravityNode.init(FileReplay::ComponentName); + if (configDir.empty()) + { + gravityNode.init(FileReplay::ComponentName); + } + else + { + gravityNode.init(FileReplay::ComponentName, configDir); + } + // Get Gravity logger logger = gravityNode.getGravityLogger(); diff --git a/src/components/cpp/Playback/FileReplay.h b/src/components/cpp/Playback/FileReplay.h index e56c74057..97ea23bda 100644 --- a/src/components/cpp/Playback/FileReplay.h +++ b/src/components/cpp/Playback/FileReplay.h @@ -47,7 +47,7 @@ class FileReplay std::shared_ptr logger; public: - FileReplay(); + FileReplay(std::string configDir = ""); virtual ~FileReplay(); void waitForExit(); }; diff --git a/src/components/cpp/Relay/Relay.cpp b/src/components/cpp/Relay/Relay.cpp index 8c1a8f6ca..d01f28035 100644 --- a/src/components/cpp/Relay/Relay.cpp +++ b/src/components/cpp/Relay/Relay.cpp @@ -69,13 +69,13 @@ class Relay : public GravitySubscriber Relay(){}; virtual ~Relay(){}; - int run(); + int run(std::string configDir = ""); void subscriptionFilled(const std::vector >& dataProducts); }; -int Relay::run() +int Relay::run(std::string configDir) { - GravityReturnCode ret = gravityNode.init(COMPONENT_ID); + GravityReturnCode ret = gravityNode.init(COMPONENT_ID, configDir); while (ret != GravityReturnCodes::SUCCESS) { cerr << "Failed to initialize " << COMPONENT_ID << ", retrying..." << endl; @@ -162,8 +162,23 @@ void Relay::subscriptionFilled(const std::vector 1) + { + std::string configFilepath = std::string(argv[1]); + + if (configFilepath.substr(configFilepath.size() - 4) != ".ini") + { + std::cerr << "Usage: invalid filename. Must be .ini. Using default config path.\n"; + exit(relay.run()); + } + exit(relay.run(std::string(argv[1]))); + } + else + { + exit(relay.run()); + } // Need to explicitly call exit here since we're capturing SIGINT and SIGTERM. Otherwise, if the SD // goes away while we're trying to unregister, this could hang indefinitely. - exit(relay.run()); + } diff --git a/src/components/cpp/ServiceDirectory/ServiceDirectory.cpp b/src/components/cpp/ServiceDirectory/ServiceDirectory.cpp index cedb7d047..533f753e8 100644 --- a/src/components/cpp/ServiceDirectory/ServiceDirectory.cpp +++ b/src/components/cpp/ServiceDirectory/ServiceDirectory.cpp @@ -60,10 +60,24 @@ struct RegistrationData gravity::GravityServiceProvider* provider; }; -int main(void) +int main(int argc, const char** argv) { + gravity::ServiceDirectory serviceDirectory; - serviceDirectory.start(); + if (argc > 1) { + std::string configFilepath = std::string(argv[1]); + + if (configFilepath.substr(configFilepath.size() - 4) != ".ini") + { + cerr << "Usage: invalid filename. Must be .ini. Using default config path.\n"; + serviceDirectory.start(); + } + serviceDirectory.start(configFilepath); + } else { + serviceDirectory.start(); + } + + } static void* registration(void* regData) @@ -158,10 +172,11 @@ static int parseDomainCSV(string& csv) namespace gravity { +const char* ServiceDirectory::ComponentName = "ServiceDirectory"; ServiceDirectory::~ServiceDirectory() {} -void ServiceDirectory::start() +void ServiceDirectory::start(std::string configDir) { //Declare threads to be spawned std::thread udpBroadcasterThread; @@ -179,7 +194,13 @@ void ServiceDirectory::start() } registeredPublishersReady = registeredPublishersProcessed = false; - gn.init("ServiceDirectory"); + if (configDir.empty()) + { + gn.init(ServiceDirectory::ComponentName); + } + else { + gn.init(ServiceDirectory::ComponentName, configDir); + } // Get Gravity logger logger = gn.getGravityLogger(); diff --git a/src/components/cpp/ServiceDirectory/ServiceDirectory.h b/src/components/cpp/ServiceDirectory/ServiceDirectory.h index 6b768e6a2..e3e463ea2 100644 --- a/src/components/cpp/ServiceDirectory/ServiceDirectory.h +++ b/src/components/cpp/ServiceDirectory/ServiceDirectory.h @@ -54,6 +54,7 @@ enum ChangeType class ServiceDirectory : GravityServiceProvider { private: + static const char* ComponentName; // domain name for this service directory std::string domain; @@ -102,7 +103,7 @@ class ServiceDirectory : GravityServiceProvider public: virtual ~ServiceDirectory(); - void start(); + void start(std::string configDir = ""); std::shared_ptr request(const GravityDataProduct& dataProduct); std::shared_ptr request(const std::string serviceID, const GravityDataProduct& dataProduct);