mirror of
https://github.com/Telecominfraproject/wlan-cloud-owprov.git
synced 2025-10-30 18:18:03 +00:00
712 lines
25 KiB
C++
712 lines
25 KiB
C++
//
|
|
// Created by stephane bourque on 2022-10-26.
|
|
//
|
|
|
|
#include "Poco/FileChannel.h"
|
|
#include "Poco/ConsoleChannel.h"
|
|
#include "Poco/PatternFormatter.h"
|
|
#include "Poco/FormattingChannel.h"
|
|
#include "Poco/AsyncChannel.h"
|
|
#include "Poco/NullChannel.h"
|
|
#include "Poco/SplitterChannel.h"
|
|
#include "Poco/Net/HTTPStreamFactory.h"
|
|
#include "Poco/Net/HTTPSStreamFactory.h"
|
|
#include "Poco/Net/FTPSStreamFactory.h"
|
|
#include "Poco/Net/FTPStreamFactory.h"
|
|
#include "Poco/Net/SSLManager.h"
|
|
#include "Poco/JSON/JSONException.h"
|
|
|
|
#include "framework/MicroService.h"
|
|
#include "framework/MicroServiceErrorHandler.h"
|
|
#include "framework/UI_WebSocketClientServer.h"
|
|
#include "framework/MicroServiceNames.h"
|
|
#include "framework/AuthClient.h"
|
|
#include "framework/ALBserver.h"
|
|
#include "framework/KafkaManager.h"
|
|
#include "framework/RESTAPI_GenericServerAccounting.h"
|
|
#include "framework/RESTAPI_ExtServer.h"
|
|
#include "framework/RESTAPI_IntServer.h"
|
|
#include "framework/utils.h"
|
|
#include "framework/WebSocketLogger.h"
|
|
|
|
namespace OpenWifi {
|
|
|
|
void MicroService::Exit(int Reason) {
|
|
std::exit(Reason);
|
|
}
|
|
|
|
void MicroService::BusMessageReceived([[maybe_unused]] const std::string &Key, const std::string & Payload) {
|
|
std::lock_guard G(InfraMutex_);
|
|
try {
|
|
Poco::JSON::Parser P;
|
|
auto Object = P.parse(Payload).extract<Poco::JSON::Object::Ptr>();
|
|
|
|
if (Object->has(KafkaTopics::ServiceEvents::Fields::ID) &&
|
|
Object->has(KafkaTopics::ServiceEvents::Fields::EVENT)) {
|
|
uint64_t ID = Object->get(KafkaTopics::ServiceEvents::Fields::ID);
|
|
auto Event = Object->get(KafkaTopics::ServiceEvents::Fields::EVENT).toString();
|
|
if (ID != ID_) {
|
|
if( Event==KafkaTopics::ServiceEvents::EVENT_JOIN ||
|
|
Event==KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE ||
|
|
Event==KafkaTopics::ServiceEvents::EVENT_LEAVE ) {
|
|
if( Object->has(KafkaTopics::ServiceEvents::Fields::TYPE) &&
|
|
Object->has(KafkaTopics::ServiceEvents::Fields::PUBLIC) &&
|
|
Object->has(KafkaTopics::ServiceEvents::Fields::PRIVATE) &&
|
|
Object->has(KafkaTopics::ServiceEvents::Fields::VRSN) &&
|
|
Object->has(KafkaTopics::ServiceEvents::Fields::KEY)) {
|
|
auto PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString();
|
|
if (Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE && Services_.find(PrivateEndPoint) != Services_.end()) {
|
|
Services_[PrivateEndPoint].LastUpdate = Utils::Now();
|
|
} else if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) {
|
|
Services_.erase(PrivateEndPoint);
|
|
poco_debug(logger(),fmt::format("Service {} ID={} leaving system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID));
|
|
} else if (Event == KafkaTopics::ServiceEvents::EVENT_JOIN || Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE) {
|
|
poco_debug(logger(),fmt::format("Service {} ID={} joining system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID));
|
|
Services_[PrivateEndPoint] = Types::MicroServiceMeta{
|
|
.Id = ID,
|
|
.Type = Poco::toLower(Object->get(KafkaTopics::ServiceEvents::Fields::TYPE).toString()),
|
|
.PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),
|
|
.PublicEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PUBLIC).toString(),
|
|
.AccessKey = Object->get(KafkaTopics::ServiceEvents::Fields::KEY).toString(),
|
|
.Version = Object->get(KafkaTopics::ServiceEvents::Fields::VRSN).toString(),
|
|
.LastUpdate = Utils::Now() };
|
|
|
|
std::string SvcList;
|
|
for (const auto &Svc: Services_) {
|
|
if(SvcList.empty())
|
|
SvcList = Svc.second.Type;
|
|
else
|
|
SvcList += ", " + Svc.second.Type;
|
|
}
|
|
poco_information(logger(),fmt::format("Current list of microservices: {}", SvcList));
|
|
}
|
|
} else {
|
|
poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing a field.",Event));
|
|
}
|
|
} else if (Event==KafkaTopics::ServiceEvents::EVENT_REMOVE_TOKEN) {
|
|
if(Object->has(KafkaTopics::ServiceEvents::Fields::TOKEN)) {
|
|
#ifndef TIP_SECURITY_SERVICE
|
|
AuthClient()->RemovedCachedToken(Object->get(KafkaTopics::ServiceEvents::Fields::TOKEN).toString());
|
|
#endif
|
|
} else {
|
|
poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing token",Event));
|
|
}
|
|
} else {
|
|
poco_error(logger(),fmt::format("Unknown Event: {} Source: {}", Event, ID));
|
|
}
|
|
}
|
|
} else {
|
|
poco_error(logger(),"Bad bus message.");
|
|
}
|
|
|
|
auto i=Services_.begin();
|
|
auto now = Utils::Now();
|
|
for(;i!=Services_.end();) {
|
|
if((now - i->second.LastUpdate)>60) {
|
|
i = Services_.erase(i);
|
|
} else
|
|
++i;
|
|
}
|
|
|
|
} catch (const Poco::Exception &E) {
|
|
logger().log(E);
|
|
}
|
|
}
|
|
|
|
Types::MicroServiceMetaVec MicroService::GetServices(const std::string & Type) {
|
|
std::lock_guard G(InfraMutex_);
|
|
|
|
auto T = Poco::toLower(Type);
|
|
Types::MicroServiceMetaVec Res;
|
|
for(const auto &[_,ServiceRec]:Services_) {
|
|
if(ServiceRec.Type==T)
|
|
Res.push_back(ServiceRec);
|
|
}
|
|
return Res;
|
|
}
|
|
|
|
Types::MicroServiceMetaVec MicroService::GetServices() {
|
|
std::lock_guard G(InfraMutex_);
|
|
|
|
Types::MicroServiceMetaVec Res;
|
|
for(const auto &[_,ServiceRec]:Services_) {
|
|
Res.push_back(ServiceRec);
|
|
}
|
|
return Res;
|
|
}
|
|
|
|
void MicroService::LoadConfigurationFile() {
|
|
std::string Location = Poco::Environment::get(DAEMON_CONFIG_ENV_VAR,".");
|
|
ConfigFileName_ = ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : ConfigFileName_;
|
|
Poco::Path ConfigFile(ConfigFileName_);
|
|
|
|
if(!ConfigFile.isFile())
|
|
{
|
|
std::cerr << DAEMON_APP_NAME << ": Configuration "
|
|
<< ConfigFile.toString() << " does not seem to exist. Please set " + DAEMON_CONFIG_ENV_VAR
|
|
+ " env variable the path of the " + DAEMON_PROPERTIES_FILENAME + " file." << std::endl;
|
|
std::exit(Poco::Util::Application::EXIT_CONFIG);
|
|
}
|
|
|
|
// loadConfiguration(ConfigFile.toString());
|
|
PropConfigurationFile_ = new Poco::Util::PropertyFileConfiguration(ConfigFile.toString());
|
|
configPtr()->addWriteable(PropConfigurationFile_, PRIO_DEFAULT);
|
|
}
|
|
|
|
void MicroService::Reload() {
|
|
LoadConfigurationFile();
|
|
LoadMyConfig();
|
|
}
|
|
|
|
void MicroService::LoadMyConfig() {
|
|
NoAPISecurity_ = ConfigGetBool("openwifi.security.restapi.disable",false);
|
|
std::string KeyFile = ConfigPath("openwifi.service.key","");
|
|
if(!KeyFile.empty()) {
|
|
std::string KeyFilePassword = ConfigPath("openwifi.service.key.password", "");
|
|
AppKey_ = Poco::SharedPtr<Poco::Crypto::RSAKey>(new Poco::Crypto::RSAKey("", KeyFile, KeyFilePassword));
|
|
Cipher_ = CipherFactory_.createCipher(*AppKey_);
|
|
Signer_.setRSAKey(AppKey_);
|
|
Signer_.addAllAlgorithms();
|
|
NoBuiltInCrypto_ = false;
|
|
} else {
|
|
NoBuiltInCrypto_ = true;
|
|
}
|
|
|
|
ID_ = Utils::GetSystemId();
|
|
if(!DebugMode_)
|
|
DebugMode_ = ConfigGetBool("openwifi.system.debug",false);
|
|
MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private");
|
|
MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public");
|
|
UIURI_ = ConfigGetString("openwifi.system.uri.ui");
|
|
MyHash_ = Utils::ComputeHash(MyPublicEndPoint_);
|
|
}
|
|
|
|
void MicroService::InitializeLoggingSystem() {
|
|
static auto initialized = false;
|
|
|
|
if(!initialized) {
|
|
initialized = true;
|
|
LoadConfigurationFile();
|
|
|
|
auto LoggingDestination = MicroService::instance().ConfigGetString("logging.type", "file");
|
|
auto LoggingFormat = MicroService::instance().ConfigGetString("logging.format",
|
|
"%Y-%m-%d %H:%M:%S.%i %s: [%p][thr:%I] %t");
|
|
auto UseAsyncLogs_ = MicroService::instance().ConfigGetBool("logging.asynch", true);
|
|
auto DisableWebSocketLogging = MicroService::instance().ConfigGetBool("logging.websocket",false);
|
|
|
|
if (LoggingDestination == "null") {
|
|
Poco::AutoPtr<Poco::NullChannel> DevNull(new Poco::NullChannel);
|
|
Poco::Logger::root().setChannel(DevNull);
|
|
} else if (LoggingDestination == "console") {
|
|
SetConsoleLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
|
|
} else if (LoggingDestination == "colorconsole") {
|
|
SetColorConsoleLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
|
|
} else if (LoggingDestination == "sql") {
|
|
SetSQLLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
|
|
} else if (LoggingDestination == "syslog") {
|
|
SetSyslogLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
|
|
} else {
|
|
SetFileLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat, DAEMON_ROOT_ENV_VAR);
|
|
}
|
|
|
|
auto Level = Poco::Logger::parseLevel(MicroService::instance().ConfigGetString("logging.level", "debug"));
|
|
Poco::Logger::root().setLevel(Level);
|
|
if(!DisableWebSocketLogging) {
|
|
static const UI_WebSocketClientServer::NotificationTypeIdVec Notifications = {
|
|
{1, "log"}};
|
|
UI_WebSocketClientServer()->RegisterNotifications(Notifications);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MicroService::SetConsoleLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern) {
|
|
|
|
Poco::AutoPtr<Poco::ConsoleChannel> Console(new Poco::ConsoleChannel);
|
|
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
|
|
Formatter->setProperty("pattern", FormatterPattern);
|
|
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, Console));
|
|
|
|
if(DisableWebSocketLogging) {
|
|
if(UseAsync) {
|
|
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
|
|
Poco::Logger::root().setChannel(Async);
|
|
} else {
|
|
Poco::Logger::root().setChannel(FormattingChannel);
|
|
}
|
|
} else {
|
|
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
|
|
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
|
|
Splitter->addChannel(WSLogger);
|
|
Splitter->addChannel(FormattingChannel);
|
|
if(UseAsync) {
|
|
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
|
|
Poco::Logger::root().setChannel(Async);
|
|
} else {
|
|
Poco::Logger::root().setChannel(Splitter);
|
|
}
|
|
}
|
|
Poco::Logger::root().information(fmt::format("Enabled console logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
|
|
}
|
|
|
|
void MicroService::SetColorConsoleLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern) {
|
|
|
|
Poco::AutoPtr<Poco::ColorConsoleChannel> Console(new Poco::ColorConsoleChannel);
|
|
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
|
|
Formatter->setProperty("pattern", FormatterPattern);
|
|
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, Console));
|
|
|
|
if(DisableWebSocketLogging) {
|
|
if(UseAsync) {
|
|
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
|
|
Poco::Logger::root().setChannel(Async);
|
|
} else {
|
|
Poco::Logger::root().setChannel(FormattingChannel);
|
|
}
|
|
} else {
|
|
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
|
|
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
|
|
Splitter->addChannel(WSLogger);
|
|
Splitter->addChannel(FormattingChannel);
|
|
if(UseAsync) {
|
|
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
|
|
Poco::Logger::root().setChannel(Async);
|
|
} else {
|
|
Poco::Logger::root().setChannel(Splitter);
|
|
}
|
|
}
|
|
Poco::Logger::root().information(fmt::format("Enabled color console logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
|
|
}
|
|
|
|
void MicroService::SetSQLLogs([[maybe_unused]] bool UseAsync,[[maybe_unused]] bool DisableWebSocketLogging,[[maybe_unused]] const std::string & FormatterPattern) {
|
|
//"CREATE TABLE T_POCO_LOG (Source VARCHAR, Name VARCHAR, ProcessId INTEGER, Thread VARCHAR, ThreadId INTEGER, Priority INTEGER, Text VARCHAR, DateTime DATE)"
|
|
}
|
|
|
|
void MicroService::SetSyslogLogs([[maybe_unused]] bool UseAsync,[[maybe_unused]] bool DisableWebSocketLogging,[[maybe_unused]] const std::string & FormatterPattern) {
|
|
|
|
}
|
|
|
|
void MicroService::SetFileLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern, const std::string & root_env_var) {
|
|
std::string DefaultLogPath = fmt::format("${}/logs",root_env_var);
|
|
auto LoggingLocationDir = MicroService::instance().ConfigPath("logging.path", DefaultLogPath);
|
|
Poco::File LD(LoggingLocationDir);
|
|
try {
|
|
if(!LD.exists()) {
|
|
LD.createDirectory();
|
|
}
|
|
} catch(const Poco::Exception &E) {
|
|
std::cout << "Cannot create " << LD.path() << " Error: " << E.message() << std::endl;
|
|
}
|
|
auto LoggingLocationDirFilePattern = LoggingLocationDir + "/log";
|
|
|
|
Poco::AutoPtr<Poco::FileChannel> FileChannel(new Poco::FileChannel);
|
|
FileChannel->setProperty("rotation", "10 M");
|
|
FileChannel->setProperty("archive", "timestamp");
|
|
FileChannel->setProperty("purgeCount", "10");
|
|
FileChannel->setProperty("path", LoggingLocationDirFilePattern);
|
|
|
|
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
|
|
Formatter->setProperty("pattern", FormatterPattern);
|
|
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, FileChannel));
|
|
|
|
if(DisableWebSocketLogging) {
|
|
if(UseAsync) {
|
|
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
|
|
Poco::Logger::root().setChannel(Async);
|
|
} else {
|
|
Poco::Logger::root().setChannel(FormattingChannel);
|
|
}
|
|
} else {
|
|
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
|
|
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
|
|
Splitter->addChannel(WSLogger);
|
|
Splitter->addChannel(FormattingChannel);
|
|
if(UseAsync) {
|
|
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
|
|
Poco::Logger::root().setChannel(Async);
|
|
} else {
|
|
Poco::Logger::root().setChannel(Splitter);
|
|
}
|
|
}
|
|
Poco::Logger::root().information(fmt::format("Enabled file logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
|
|
}
|
|
|
|
void DaemonPostInitialization(Poco::Util::Application &self);
|
|
|
|
void MicroService::initialize(Poco::Util::Application &self) {
|
|
// add the default services
|
|
LoadConfigurationFile();
|
|
InitializeLoggingSystem();
|
|
|
|
SubSystems_.push_back(KafkaManager());
|
|
SubSystems_.push_back(ALBHealthCheckServer());
|
|
SubSystems_.push_back(RESTAPI_ExtServer());
|
|
SubSystems_.push_back(RESTAPI_IntServer());
|
|
#ifndef TIP_SECURITY_SERVICE
|
|
SubSystems_.push_back(AuthClient());
|
|
#endif
|
|
Poco::Net::initializeSSL();
|
|
Poco::Net::HTTPStreamFactory::registerFactory();
|
|
Poco::Net::HTTPSStreamFactory::registerFactory();
|
|
Poco::Net::FTPStreamFactory::registerFactory();
|
|
Poco::Net::FTPSStreamFactory::registerFactory();
|
|
|
|
Poco::File DataDir(ConfigPath("openwifi.system.data"));
|
|
DataDir_ = DataDir.path();
|
|
if(!DataDir.exists()) {
|
|
try {
|
|
DataDir.createDirectory();
|
|
} catch (const Poco::Exception &E) {
|
|
logger().log(E);
|
|
}
|
|
}
|
|
WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets","");
|
|
if(WWWAssetsDir_.empty())
|
|
WWWAssetsDir_ = DataDir_;
|
|
|
|
LoadMyConfig();
|
|
|
|
InitializeSubSystemServers();
|
|
ServerApplication::initialize(self);
|
|
DaemonPostInitialization(self);
|
|
|
|
Types::TopicNotifyFunction F = [this](const std::string &Key,const std::string &Payload) { this->BusMessageReceived(Key, Payload); };
|
|
KafkaManager()->RegisterTopicWatcher(KafkaTopics::SERVICE_EVENTS, F);
|
|
}
|
|
|
|
void MicroService::uninitialize() {
|
|
// add your own uninitialization code here
|
|
ServerApplication::uninitialize();
|
|
}
|
|
|
|
void MicroService::reinitialize(Poco::Util::Application &self) {
|
|
ServerApplication::reinitialize(self);
|
|
// add your own reinitialization code here
|
|
}
|
|
|
|
void MicroService::defineOptions(Poco::Util::OptionSet &options) {
|
|
ServerApplication::defineOptions(options);
|
|
|
|
options.addOption(
|
|
Poco::Util::Option("help", "", "display help information on command line arguments")
|
|
.required(false)
|
|
.repeatable(false)
|
|
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleHelp)));
|
|
|
|
options.addOption(
|
|
Poco::Util::Option("file", "", "specify the configuration file")
|
|
.required(false)
|
|
.repeatable(false)
|
|
.argument("file")
|
|
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleConfig)));
|
|
|
|
options.addOption(
|
|
Poco::Util::Option("debug", "", "to run in debug, set to true")
|
|
.required(false)
|
|
.repeatable(false)
|
|
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleDebug)));
|
|
|
|
options.addOption(
|
|
Poco::Util::Option("logs", "", "specify the log directory and file (i.e. dir/file.log)")
|
|
.required(false)
|
|
.repeatable(false)
|
|
.argument("dir")
|
|
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleLogs)));
|
|
|
|
options.addOption(
|
|
Poco::Util::Option("version", "", "get the version and quit.")
|
|
.required(false)
|
|
.repeatable(false)
|
|
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleVersion)));
|
|
|
|
}
|
|
|
|
void MicroService::handleHelp([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) {
|
|
HelpRequested_ = true;
|
|
displayHelp();
|
|
stopOptionsProcessing();
|
|
}
|
|
|
|
void MicroService::handleVersion([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) {
|
|
HelpRequested_ = true;
|
|
std::cout << Version() << std::endl;
|
|
stopOptionsProcessing();
|
|
}
|
|
|
|
void MicroService::handleDebug([[maybe_unused]] const std::string &name, const std::string &value) {
|
|
if(value == "true")
|
|
DebugMode_ = true ;
|
|
}
|
|
|
|
void MicroService::handleLogs([[maybe_unused]] const std::string &name, const std::string &value) {
|
|
LogDir_ = value;
|
|
}
|
|
|
|
void MicroService::handleConfig([[maybe_unused]] const std::string &name, const std::string &value) {
|
|
ConfigFileName_ = value;
|
|
}
|
|
|
|
void MicroService::displayHelp() {
|
|
Poco::Util::HelpFormatter helpFormatter(options());
|
|
helpFormatter.setCommand(commandName());
|
|
helpFormatter.setUsage("OPTIONS");
|
|
helpFormatter.setHeader("A " + DAEMON_APP_NAME + " implementation for TIP.");
|
|
helpFormatter.format(std::cout);
|
|
}
|
|
|
|
void MicroService::InitializeSubSystemServers() {
|
|
for(auto i:SubSystems_) {
|
|
addSubsystem(i);
|
|
}
|
|
}
|
|
|
|
void MicroService::StartSubSystemServers() {
|
|
AddActivity("Starting");
|
|
for(auto i:SubSystems_) {
|
|
i->Start();
|
|
}
|
|
EventBusManager_ = std::make_unique<EventBusManager>(Poco::Logger::create("EventBusManager",Poco::Logger::root().getChannel(),Poco::Logger::root().getLevel()));
|
|
EventBusManager_->Start();
|
|
}
|
|
|
|
void MicroService::StopSubSystemServers() {
|
|
AddActivity("Stopping");
|
|
EventBusManager_->Stop();
|
|
for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) {
|
|
(*i)->Stop();
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] std::string MicroService::CreateUUID() {
|
|
static std::random_device rd;
|
|
static std::mt19937_64 gen(rd());
|
|
static std::uniform_int_distribution<> dis(0, 15);
|
|
static std::uniform_int_distribution<> dis2(8, 11);
|
|
|
|
std::stringstream ss;
|
|
int i;
|
|
ss << std::hex;
|
|
for (i = 0; i < 8; i++) {
|
|
ss << dis(gen);
|
|
}
|
|
ss << "-";
|
|
for (i = 0; i < 4; i++) {
|
|
ss << dis(gen);
|
|
}
|
|
ss << "-4";
|
|
for (i = 0; i < 3; i++) {
|
|
ss << dis(gen);
|
|
}
|
|
ss << "-";
|
|
ss << dis2(gen);
|
|
for (i = 0; i < 3; i++) {
|
|
ss << dis(gen);
|
|
}
|
|
ss << "-";
|
|
for (i = 0; i < 12; i++) {
|
|
ss << dis(gen);
|
|
};
|
|
return ss.str();
|
|
}
|
|
|
|
bool MicroService::SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) {
|
|
try {
|
|
auto P = Poco::Logger::parseLevel(Level);
|
|
auto Sub = Poco::toLower(SubSystem);
|
|
|
|
if (Sub == "all") {
|
|
for (auto i : SubSystems_) {
|
|
i->Logger().setLevel(P);
|
|
}
|
|
return true;
|
|
} else {
|
|
for (auto i : SubSystems_) {
|
|
if (Sub == Poco::toLower(i->Name())) {
|
|
i->Logger().setLevel(P);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} catch (const Poco::Exception & E) {
|
|
std::cerr << "Exception" << std::endl;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MicroService::Reload(const std::string &Sub) {
|
|
for (auto i : SubSystems_) {
|
|
if (Poco::toLower(Sub) == Poco::toLower(i->Name())) {
|
|
i->reinitialize(Poco::Util::Application::instance());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
Types::StringVec MicroService::GetSubSystems() const {
|
|
Types::StringVec Result;
|
|
for(auto i:SubSystems_)
|
|
Result.push_back(Poco::toLower(i->Name()));
|
|
return Result;
|
|
}
|
|
|
|
Types::StringPairVec MicroService::GetLogLevels() {
|
|
Types::StringPairVec Result;
|
|
|
|
for(auto &i:SubSystems_) {
|
|
auto P = std::make_pair( i->Name(), Utils::LogLevelToString(i->GetLoggingLevel()));
|
|
Result.push_back(P);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
const Types::StringVec & MicroService::GetLogLevelNames() {
|
|
static Types::StringVec LevelNames{"none", "fatal", "critical", "error", "warning", "notice", "information", "debug", "trace" };
|
|
return LevelNames;
|
|
}
|
|
|
|
uint64_t MicroService::ConfigGetInt(const std::string &Key,uint64_t Default) {
|
|
return (uint64_t) config().getInt64(Key,Default);
|
|
}
|
|
|
|
uint64_t MicroService::ConfigGetInt(const std::string &Key) {
|
|
return config().getInt(Key);
|
|
}
|
|
|
|
uint64_t MicroService::ConfigGetBool(const std::string &Key,bool Default) {
|
|
return config().getBool(Key,Default);
|
|
}
|
|
|
|
uint64_t MicroService::ConfigGetBool(const std::string &Key) {
|
|
return config().getBool(Key);
|
|
}
|
|
|
|
std::string MicroService::ConfigGetString(const std::string &Key,const std::string & Default) {
|
|
return config().getString(Key, Default);
|
|
}
|
|
|
|
std::string MicroService::ConfigGetString(const std::string &Key) {
|
|
return config().getString(Key);
|
|
}
|
|
|
|
std::string MicroService::ConfigPath(const std::string &Key,const std::string & Default) {
|
|
std::string R = config().getString(Key, Default);
|
|
return Poco::Path::expand(R);
|
|
}
|
|
|
|
std::string MicroService::ConfigPath(const std::string &Key) {
|
|
std::string R = config().getString(Key);
|
|
return Poco::Path::expand(R);
|
|
}
|
|
|
|
std::string MicroService::Encrypt(const std::string &S) {
|
|
if(NoBuiltInCrypto_) {
|
|
return S;
|
|
}
|
|
return Cipher_->encryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
|
}
|
|
|
|
std::string MicroService::Decrypt(const std::string &S) {
|
|
if(NoBuiltInCrypto_) {
|
|
return S;
|
|
}
|
|
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
|
}
|
|
|
|
std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
|
|
Poco::JSON::Object Obj;
|
|
Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type);
|
|
Obj.set(KafkaTopics::ServiceEvents::Fields::ID,ID_);
|
|
Obj.set(KafkaTopics::ServiceEvents::Fields::TYPE,Poco::toLower(DAEMON_APP_NAME));
|
|
Obj.set(KafkaTopics::ServiceEvents::Fields::PUBLIC,MyPublicEndPoint_);
|
|
Obj.set(KafkaTopics::ServiceEvents::Fields::PRIVATE,MyPrivateEndPoint_);
|
|
Obj.set(KafkaTopics::ServiceEvents::Fields::KEY,MyHash_);
|
|
Obj.set(KafkaTopics::ServiceEvents::Fields::VRSN,Version_);
|
|
std::stringstream ResultText;
|
|
Poco::JSON::Stringifier::stringify(Obj, ResultText);
|
|
return ResultText.str();
|
|
}
|
|
|
|
[[nodiscard]] bool MicroService::IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request) {
|
|
try {
|
|
auto APIKEY = Request.get("X-API-KEY");
|
|
return APIKEY == MyHash_;
|
|
} catch (const Poco::Exception &E) {
|
|
logger().log(E);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MicroService::SavePID() {
|
|
try {
|
|
std::ofstream O;
|
|
O.open(MicroService::instance().DataDir() + "/pidfile",std::ios::binary | std::ios::trunc);
|
|
O << Poco::Process::id();
|
|
O.close();
|
|
} catch (...)
|
|
{
|
|
std::cout << "Could not save system ID" << std::endl;
|
|
}
|
|
}
|
|
|
|
int MicroService::main([[maybe_unused]] const ArgVec &args) {
|
|
MicroServiceErrorHandler ErrorHandler(*this);
|
|
Poco::ErrorHandler::set(&ErrorHandler);
|
|
|
|
if (!HelpRequested_) {
|
|
SavePID();
|
|
|
|
Poco::Logger &logger = Poco::Logger::get(DAEMON_APP_NAME);
|
|
logger.notice(fmt::format("Starting {} version {}.",DAEMON_APP_NAME, Version()));
|
|
|
|
if(Poco::Net::Socket::supportsIPv6())
|
|
poco_information(logger,"System supports IPv6.");
|
|
else
|
|
poco_information(logger,"System does NOT support IPv6.");
|
|
|
|
if (config().getBool("application.runAsDaemon", false)) {
|
|
poco_information(logger,"Starting as a daemon.");
|
|
}
|
|
|
|
poco_information(logger,fmt::format("System ID set to {}",ID_));
|
|
StartSubSystemServers();
|
|
waitForTerminationRequest();
|
|
StopSubSystemServers();
|
|
logger.notice(fmt::format("Stopped {}...",DAEMON_APP_NAME));
|
|
}
|
|
|
|
return Application::EXIT_OK;
|
|
}
|
|
|
|
void MicroService::AddActivity(const std::string &Activity) {
|
|
if(!DataDir_.empty()) {
|
|
std::string ActivityFile{ DataDir_ + "/activity.log"};
|
|
try {
|
|
std::ofstream of(ActivityFile,std::ios_base::app | std::ios_base::out );
|
|
auto t = std::chrono::system_clock::now();
|
|
std::time_t now = std::chrono::system_clock::to_time_t(t);
|
|
of << Activity << " at " << std::ctime(&now) ;
|
|
} catch (...) {
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] std::string MicroService::Sign(Poco::JWT::Token &T, const std::string &Algo) {
|
|
if(NoBuiltInCrypto_) {
|
|
return T.toString();
|
|
} else {
|
|
return Signer_.sign(T,Algo);
|
|
}
|
|
}
|
|
|
|
void MicroService::DeleteOverrideConfiguration() {
|
|
Poco::File F(DataDir_ + ExtraConfigurationFilename);
|
|
|
|
try {
|
|
if(F.exists())
|
|
F.remove();
|
|
} catch (...) {
|
|
|
|
}
|
|
}
|
|
|
|
} |