Adds further ext deps as-is binaries copies from customers env.
Qt6 Migration CI / migrate (push) Canceled after 0s
Qt6 Migration CI / migrate (push) Canceled after 0s
This commit is contained in:
3700 files changed
+2132394
No files matched your search
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/ConfigRw.hpp"
|
||||
#include "ddkit/base/ConfigLoader.hpp"
|
||||
|
||||
#include "ddkit/access/System.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
/// @brief ConfigLoaderDds holds the ConfigLoader (Config) and the DdsSystem (process-wide dds-initialization)
|
||||
/// if created before everything else (on the stack), this will do for clean termination.
|
||||
class ConfigLoaderDds;
|
||||
typedef std::shared_ptr<ConfigLoaderDds> ConfigLoaderDdsPtr;
|
||||
|
||||
class ConfigLoaderDds {
|
||||
|
||||
public:
|
||||
ConfigLoaderDds();
|
||||
ConfigLoaderDds(const std::string& configFile);
|
||||
~ConfigLoaderDds();
|
||||
|
||||
base::IConfig& config() { return m_configRw; }
|
||||
base::IConfigWrite& configWrite() { return m_configRw; }
|
||||
|
||||
// checks all keys, which start '<section>.' to be '<section>.<key>' with a <key> from given list
|
||||
// - checks whole config(-file) right now.
|
||||
// - enables checking from now on in all calls to above config-functions has(), get(), set().
|
||||
// the checking-function will throw, if a violation is detected.
|
||||
void registerKnownConfigKey(const std::string& section, const std::string& key);
|
||||
|
||||
void reloadConfig(const std::string& configFile);
|
||||
static ConfigLoaderDdsPtr instance();
|
||||
private:
|
||||
// no copying
|
||||
ConfigLoaderDds(ConfigLoaderDds const&) = delete;
|
||||
ConfigLoaderDds(ConfigLoaderDds&&) = delete;
|
||||
void operator=(ConfigLoaderDds const&) = delete;
|
||||
void operator=(ConfigLoaderDds&&) = delete;
|
||||
|
||||
void loadDefaultTerminateHandlers();
|
||||
|
||||
std::unique_ptr<base::ConfigLoader> m_configLoader;
|
||||
base::ConfigRw m_configRw;
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/IConnectUpdate.hpp"
|
||||
#include "ddkit/access/IConnectCheck.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class ConnectState final : public IConnectUpdate,
|
||||
public IConnectCheck {
|
||||
|
||||
public:
|
||||
ConnectState(const std::string& name, const std::string& nameModule, const std::string& nameTopic);
|
||||
|
||||
// IConnectUpdate
|
||||
void setIsConnected() override;
|
||||
void setIsNotConnected() override;
|
||||
|
||||
// IConnectCheck
|
||||
std::string name() override;
|
||||
std::string nameModule() override;
|
||||
std::string nameTopic() override;
|
||||
bool isConnected() override;
|
||||
|
||||
void waitUntilConnected();
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_nameModule;
|
||||
std::string m_nameTopic;
|
||||
|
||||
std::recursive_mutex m_mutex;
|
||||
std::condition_variable_any m_condition;
|
||||
bool m_isConnected;
|
||||
|
||||
// no copying
|
||||
ConnectState(ConnectState const&) = delete;
|
||||
ConnectState(ConnectState&&) = delete;
|
||||
void operator=(ConnectState const&) = delete;
|
||||
};
|
||||
typedef std::shared_ptr<ConnectState> ConnectStatePtr;
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
//
|
||||
// only ever include DdsWrap.hpp instead of dds/dds.hpp!
|
||||
//
|
||||
// - visual studio-mechanism for isystem (external includes), that is avoid warnings in third-party-code, is not
|
||||
// working with (our) cmake so far.
|
||||
// - so we need to disable all warnings from dds-vendor "by hand". this is done
|
||||
// - here, while including dds-headers directly
|
||||
// - in all wrapper-headers around dds-generated files (which include dds indirectly as well obviously)
|
||||
// - see genVendorWrap for that.
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#include <dds/dds.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// the ostream-operator (operator<<) for InstanceHandle is declared in connext and cyclone nearly the same way
|
||||
// - connext: ndds/hpp/dds/core/InstanceHandle.hpp
|
||||
// - cyclone: ddscxx/dds/core/InstanceHandle.hpp
|
||||
// but connext implements it inline (delegates to rhs.delegate()), while cyclone does not.
|
||||
// this seems to be the reason, for that the operator is not usable with cyclone at first glance.
|
||||
// but we simply need to make it known in the namespace for ADL (argument-dependent-lookup) to work.
|
||||
|
||||
namespace dds {
|
||||
namespace core {
|
||||
|
||||
using ::operator<<;
|
||||
|
||||
}
|
||||
} // namespace dds
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/Thread.hpp"
|
||||
#include "ddkit/access/ConfigLoaderDds.hpp"
|
||||
#include "ddkit/access/DdsWrap.hpp"
|
||||
#include "ddkit/access/System.hpp"
|
||||
#include "ddkit/access/ICleanup.hpp"
|
||||
#include "ddkit/utils/Logger.hpp"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class Dispatcher : public base::Thread {
|
||||
|
||||
public:
|
||||
explicit Dispatcher(const std::string& threadName);
|
||||
Dispatcher(const std::string& threadName, std::shared_ptr<ICleanup> cleanup);
|
||||
~Dispatcher();
|
||||
|
||||
void addReadCondition(const dds::sub::cond::ReadCondition& readCondition);
|
||||
void removeReadCondition(const dds::sub::cond::ReadCondition& readCondition);
|
||||
|
||||
void requestCleanup();
|
||||
|
||||
// Thread
|
||||
void run() override;
|
||||
void onStop() override;
|
||||
|
||||
private:
|
||||
// System has to be referenced because System::instance() call (and therefore instantiation of the singleton)
|
||||
// has to happen before the waitset is initialized. Otherwise the waitset would access the policy first and
|
||||
// the manipulation by System later will throw an exception because the policy is already immutable.
|
||||
std::shared_ptr<access::ConfigLoaderDds> m_configLoaderDds; // contains System
|
||||
|
||||
std::shared_ptr<ICleanup> m_cleanup;
|
||||
|
||||
std::recursive_mutex m_addRemoveMutex;
|
||||
|
||||
dds::core::cond::WaitSet m_waitset;
|
||||
dds::core::cond::GuardCondition m_guardCondition;
|
||||
|
||||
void callCleanupIf();
|
||||
|
||||
Dispatcher(Dispatcher const&) = delete;
|
||||
void operator=(Dispatcher const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class ICleanup {
|
||||
|
||||
public:
|
||||
virtual void cleanup() = 0;
|
||||
virtual ~ICleanup() = default;
|
||||
|
||||
virtual bool isShutdownRequested() = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class IConnectCheck {
|
||||
public:
|
||||
virtual std::string name() = 0;
|
||||
virtual std::string nameModule() = 0;
|
||||
virtual std::string nameTopic() = 0;
|
||||
virtual bool isConnected() = 0;
|
||||
virtual ~IConnectCheck() = default;
|
||||
};
|
||||
typedef std::shared_ptr<IConnectCheck> IConnectCheckPtr;
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class IConnectUpdate {
|
||||
public:
|
||||
virtual void setIsConnected() = 0;
|
||||
virtual void setIsNotConnected() = 0;
|
||||
virtual ~IConnectUpdate() = default;
|
||||
};
|
||||
typedef std::shared_ptr<IConnectUpdate> IConnectUpdatePtr;
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/QosPattern.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
/// contains one or more QosPatterns and returns them on request by typeName.
|
||||
class IQosStrategy {
|
||||
|
||||
public:
|
||||
virtual QosPattern selectQosPattern(const std::string& typeName) = 0;
|
||||
virtual ~IQosStrategy() = default;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IQosStrategy> IQosStrategyPtr;
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
/// @brief template-independent base-class of topics (needed to have a type for generically store a topic-map)
|
||||
class ITopic {
|
||||
|
||||
public:
|
||||
virtual std::string topicName() = 0;
|
||||
virtual bool hasReader() = 0;
|
||||
virtual void unloadReader() = 0;
|
||||
virtual void closeReader() = 0;
|
||||
virtual bool hasWriter() = 0;
|
||||
virtual void closeWriter() = 0;
|
||||
virtual ~ITopic() = default;
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class ITopicStrategy {
|
||||
public:
|
||||
virtual std::string get(const std::string& typeName) = 0;
|
||||
|
||||
virtual ~ITopicStrategy() = default;
|
||||
|
||||
protected:
|
||||
ITopicStrategy() = default;
|
||||
|
||||
private:
|
||||
// no copying
|
||||
ITopicStrategy(ITopicStrategy const&) = delete;
|
||||
ITopicStrategy(ITopicStrategy&&) = delete;
|
||||
void operator=(ITopicStrategy const&) = delete;
|
||||
void operator=(ITopicStrategy&&) = delete;
|
||||
};
|
||||
typedef std::shared_ptr<ITopicStrategy> ITopicStrategyPtr;
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/DdsWrap.hpp"
|
||||
#include "ddkit/access/ConnectState.hpp"
|
||||
|
||||
#include "ddkit/utils/Logger.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
std::string policyName(unsigned policyId);
|
||||
|
||||
template <class T>
|
||||
class ListenerTopic : public dds::topic::TopicListener<T> {
|
||||
|
||||
public:
|
||||
void on_inconsistent_topic(
|
||||
dds::topic::Topic<T>&, dds::core::status::InconsistentTopicStatus const& status) override {
|
||||
|
||||
ddkit::log::warn() << "Inconsistent Topic: "
|
||||
<< dds::topic::topic_type_name<T>::value()
|
||||
<< ", count=" << status.total_count()
|
||||
<< "(" << std::showpos << status.total_count_change() << ")";
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ListenerRead : public dds::sub::DataReaderListener<T> {
|
||||
|
||||
ConnectStatePtr m_connectUpdate;
|
||||
|
||||
public:
|
||||
ListenerRead(ConnectStatePtr connectState): m_connectUpdate(connectState) {
|
||||
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(connectState->nameModule())
|
||||
<< DDKIT_LOG_VAR_VALUE(connectState->nameTopic());
|
||||
}
|
||||
|
||||
/// @brief We use waitsets and read conditions to get the data more granulary.
|
||||
/// So we actually dont need this on data here in the dds-listeners.
|
||||
void on_data_available(dds::sub::DataReader<T>& /* dataReader */) override {
|
||||
/*DDKIT_LOG_TRACE << std::addressof(dataReader)
|
||||
<< " topic name: "
|
||||
<< dataReader.topic_description().name()
|
||||
<< ", topic type: "
|
||||
<< dataReader.topic_description().type_name();*/
|
||||
}
|
||||
|
||||
void on_liveliness_changed(
|
||||
dds::sub::DataReader<T>&, const dds::core::status::LivelinessChangedStatus& status) override {
|
||||
|
||||
ddkit::log::debug() << "liveliness changed: "
|
||||
<< dds::topic::topic_type_name<T>::value() << ", " << status.alive_count() << "/"
|
||||
<< status.not_alive_count();
|
||||
}
|
||||
|
||||
void on_requested_deadline_missed(
|
||||
dds::sub::DataReader<T>&, const dds::core::status::RequestedDeadlineMissedStatus&) override {
|
||||
|
||||
ddkit::log::warn() << "on_requested_deadline_missed";
|
||||
}
|
||||
|
||||
void on_requested_incompatible_qos(
|
||||
dds::sub::DataReader<T>& /*reader*/,
|
||||
const dds::core::status::RequestedIncompatibleQosStatus& status) override {
|
||||
|
||||
// When partitions do not match it does not mean that there is a problem.
|
||||
// It may is intended to direct the dataflow on a logical level.
|
||||
|
||||
#if defined(DDS_VENDOR_CONNEXT) || defined(DDS_VENDOR_CYCLONE)
|
||||
if (status.last_policy_id() != DDS_PARTITION_QOS_POLICY_ID) {
|
||||
#else
|
||||
if (true) {
|
||||
#endif
|
||||
ddkit::log::warn() << "Reader: Incompatible QoS requested: ("
|
||||
<< std::to_string(status.last_policy_id()) << "): " << policyName(status.last_policy_id()) << ", "
|
||||
<< dds::topic::topic_type_name<T>::value() << ", count=" << status.total_count() << "("
|
||||
<< std::showpos << status.total_count_change() << ")";
|
||||
}
|
||||
}
|
||||
|
||||
void on_sample_lost(dds::sub::DataReader<T>&, const dds::core::status::SampleLostStatus&) override {
|
||||
ddkit::log::warn() << "on_sample_lost";
|
||||
}
|
||||
|
||||
void on_sample_rejected(dds::sub::DataReader<T>&, const dds::core::status::SampleRejectedStatus& status) override {
|
||||
if (status.last_reason() != dds::core::status::SampleRejectedState::not_rejected()) {
|
||||
ddkit::log::warn() << "on_sample_rejected " << status.last_reason();
|
||||
}
|
||||
}
|
||||
|
||||
void on_subscription_matched(
|
||||
dds::sub::DataReader<T>&, const dds::core::status::SubscriptionMatchedStatus& status) override {
|
||||
|
||||
ddkit::log::debug() << "Subscription matched: "
|
||||
<< dds::topic::topic_type_name<T>::value() << ", " << status.current_count();
|
||||
|
||||
if (status.current_count()) {
|
||||
m_connectUpdate->setIsConnected();
|
||||
} else {
|
||||
m_connectUpdate->setIsNotConnected();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~ListenerRead() {
|
||||
DDKIT_LOG_TRACE
|
||||
<< DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameModule())
|
||||
<< DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameTopic());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ListenerWrite : public dds::pub::DataWriterListener<T> {
|
||||
|
||||
ConnectStatePtr m_connectUpdate;
|
||||
|
||||
public:
|
||||
ListenerWrite(ConnectStatePtr connectState): m_connectUpdate(connectState) {
|
||||
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameModule())
|
||||
<< DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameTopic());
|
||||
}
|
||||
|
||||
void on_liveliness_lost(dds::pub::DataWriter<T>&, dds::core::status::LivelinessLostStatus const&) override {
|
||||
ddkit::log::warn() << "liveliness lost";
|
||||
}
|
||||
|
||||
void on_offered_deadline_missed(
|
||||
dds::pub::DataWriter<T>&, dds::core::status::OfferedDeadlineMissedStatus const&) override {
|
||||
|
||||
ddkit::log::warn() << "on_offered_deadline_missed";
|
||||
}
|
||||
|
||||
void on_offered_incompatible_qos(
|
||||
dds::pub::DataWriter<T>&, dds::core::status::OfferedIncompatibleQosStatus const& status) override {
|
||||
|
||||
#if defined(DDS_VENDOR_CONNEXT) || defined(DDS_VENDOR_CYCLONE)
|
||||
if (status.last_policy_id() != DDS_PARTITION_QOS_POLICY_ID) {
|
||||
#else
|
||||
if (true) {
|
||||
#endif
|
||||
ddkit::log::warn() << "Writer: Incompatible QoS offered: ("
|
||||
<< std::to_string(status.last_policy_id()) << "): " << policyName(status.last_policy_id()) << ", "
|
||||
<< dds::topic::topic_type_name<T>::value() << ", count=" << status.total_count() << "("
|
||||
<< std::showpos << status.total_count_change() << ")";
|
||||
}
|
||||
}
|
||||
|
||||
void on_publication_matched(
|
||||
dds::pub::DataWriter<T>&, dds::core::status::PublicationMatchedStatus const& status) override {
|
||||
|
||||
ddkit::log::debug() << "Publication matched: " << DDKIT_LOG_VAR_VALUE(status.current_count());
|
||||
if (status.current_count()) {
|
||||
m_connectUpdate->setIsConnected();
|
||||
} else {
|
||||
m_connectUpdate->setIsNotConnected();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DDS_VENDOR_CONNEXT)
|
||||
void on_application_acknowledgment(
|
||||
dds::pub::DataWriter<T>& /*dataWriter*/,
|
||||
rti::pub::AcknowledgmentInfo const& /*acknowledgment_info*/) override {
|
||||
DDKIT_LOG_TRACE;
|
||||
}
|
||||
|
||||
void* on_data_request(dds::pub::DataWriter<T>&, rti::core::Cookie const&) override {
|
||||
DDKIT_LOG_TRACE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void on_data_return(dds::pub::DataWriter<T>&, void*, rti::core::Cookie const&) override {
|
||||
DDKIT_LOG_TRACE;
|
||||
}
|
||||
|
||||
void on_destination_unreachable(
|
||||
dds::pub::DataWriter<T>&, dds::core::InstanceHandle const&, rti::core::Locator const&) override {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
}
|
||||
|
||||
void on_instance_replaced(dds::pub::DataWriter<T>&, dds::core::InstanceHandle const& /*handle*/) override {
|
||||
DDKIT_LOG_TRACE;
|
||||
}
|
||||
|
||||
void on_reliable_reader_activity_changed(
|
||||
dds::pub::DataWriter<T>&, const rti::core::status::ReliableReaderActivityChangedStatus&) override {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
}
|
||||
|
||||
void on_reliable_writer_cache_changed(
|
||||
dds::pub::DataWriter<T>&, rti::core::status::ReliableWriterCacheChangedStatus const& status) override {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.empty_reliable_writer_cache());
|
||||
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.full_reliable_writer_cache());
|
||||
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.low_watermark_reliable_writer_cache());
|
||||
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.high_watermark_reliable_writer_cache());
|
||||
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.unacknowledged_sample_count());
|
||||
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.unacknowledged_sample_count_peak());
|
||||
}
|
||||
|
||||
void on_sample_removed(dds::pub::DataWriter<T>&, rti::core::Cookie const&) override {
|
||||
DDKIT_LOG_TRACE;
|
||||
}
|
||||
|
||||
void on_service_request_accepted(
|
||||
dds::pub::DataWriter<T>&, rti::core::status::ServiceRequestAcceptedStatus const&) override {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
}
|
||||
#elif defined(DDS_VENDOR_CYCLONE)
|
||||
// other vendors may have other extensions
|
||||
#elif defined(DDS_VENDOR_OPENSPLICE)
|
||||
// other vendors may have other extensions
|
||||
#else
|
||||
#error "DDS_VENDOR not set"
|
||||
#endif
|
||||
|
||||
virtual ~ListenerWrite() {
|
||||
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameModule())
|
||||
<< DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameTopic());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/Config.hpp"
|
||||
#include "ddkit/access/TopicPoolRead.hpp"
|
||||
#include "ddkit/access/TopicPoolWrite.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class ModelMonitor final {
|
||||
public:
|
||||
ModelMonitor(
|
||||
base::Config& config,
|
||||
bool isWrite,
|
||||
bool isRmodel,
|
||||
const std::string& header,
|
||||
int domain,
|
||||
const IQosStrategyPtr& qosStrategy,
|
||||
const ITopicStrategyPtr& topicStrategy);
|
||||
|
||||
// start current module for addition
|
||||
void startModule(const std::string& moduleName);
|
||||
|
||||
// ... for current module
|
||||
template <typename T>
|
||||
void addTopic();
|
||||
|
||||
// listen forever
|
||||
void doRun();
|
||||
|
||||
private:
|
||||
base::Config& m_config;
|
||||
bool m_isWrite;
|
||||
bool m_isRmodel;
|
||||
std::string m_header;
|
||||
int m_domain;
|
||||
std::shared_ptr<Dispatcher> m_dispatcher;
|
||||
Participant m_participant;
|
||||
TopicPoolWrite m_topicPoolWrite;
|
||||
TopicPoolRead m_topicPoolRead;
|
||||
|
||||
std::string m_moduleCurrent;
|
||||
int m_ctCurrent;
|
||||
int m_ctTotal;
|
||||
std::map<std::string, int> m_module2ct;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void ModelMonitor::addTopic() {
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
std::string typeName = dds::topic::topic_type_name<T>::value();
|
||||
if (m_isRmodel) {
|
||||
ddkit::utils::string::removePrefix(typeName, "VendorData::");
|
||||
}
|
||||
|
||||
std::string partFirst = typeName.substr(0, typeName.find("::"));
|
||||
std::string partLast = typeName.substr(typeName.rfind("::") + 2);
|
||||
std::string moduleName = partFirst;
|
||||
std::string topicName = partLast;
|
||||
|
||||
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(moduleName);
|
||||
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(m_moduleCurrent);
|
||||
|
||||
if(moduleName != m_moduleCurrent){
|
||||
ddkit::log::error() << "ModelMonitor::addTopic: mismatch in module name: \"" << m_moduleCurrent << "\" in class and \"" << moduleName << "\" in topic_type_name.";
|
||||
return;
|
||||
}
|
||||
|
||||
// bei isRmodel muss das config-format anders werden IService.ConfigAbc ...
|
||||
std::string key = "module." + moduleName + "." + topicName;
|
||||
bool isOn = m_config.hasKey(key) && m_config.getBoolValue(key);
|
||||
ddkit::log::trace() << key;
|
||||
if (isOn) {
|
||||
++m_ctCurrent;
|
||||
if (m_isWrite) {
|
||||
std::ostringstream deadEnd; deadEnd << "not implemented yet"; // todo
|
||||
ddkit::log::fatal() << deadEnd.str();
|
||||
throw std::logic_error(deadEnd.str());
|
||||
// m_topicPoolWrite.createTopicWrite<T>();
|
||||
} else {
|
||||
m_topicPoolRead.createTopicRead<T>(
|
||||
[=](T const& val) { std::cout << m_header << typeName << ": " << val << std::endl; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/DdsWrap.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class Participant {
|
||||
|
||||
public:
|
||||
explicit Participant(int domainId, bool connextExtensibleCompliant=false);
|
||||
|
||||
int domain();
|
||||
dds::domain::DomainParticipant& domainParticipant();
|
||||
|
||||
private:
|
||||
void setConnextXTypesSpecCompliant(bool compliant);
|
||||
|
||||
dds::domain::qos::DomainParticipantQos getParticipantQos();
|
||||
|
||||
bool m_connextExtensibleCompliant;
|
||||
|
||||
int m_domainId;
|
||||
dds::domain::DomainParticipant m_domainParticipant;
|
||||
// default copying
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/DdsWrap.hpp"
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
/// @brief wraps dds::pub::qos::DataWriterQos and dds::sub::qos::DataReaderQos
|
||||
/// allows defining an arbitrary list of qos-settings.
|
||||
class QosPattern {
|
||||
|
||||
public:
|
||||
QosPattern();
|
||||
QosPattern get();
|
||||
|
||||
dds::sub::qos::DataReaderQos& qosRead();
|
||||
dds::pub::qos::DataWriterQos& qosWrite();
|
||||
dds::topic::qos::TopicQos& qosTopic();
|
||||
dds::sub::qos::SubscriberQos& qosSub();
|
||||
dds::pub::qos::PublisherQos& qosPub();
|
||||
QosPattern& qosReadWrite();
|
||||
|
||||
template <typename T>
|
||||
QosPattern& operator<<(T const& rhs) {
|
||||
qosRead() << rhs;
|
||||
qosWrite() << rhs;
|
||||
qosTopic() << rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
dds::sub::qos::DataReaderQos m_dataReaderQos;
|
||||
dds::pub::qos::DataWriterQos m_dataWriterQos;
|
||||
dds::topic::qos::TopicQos m_topicQos;
|
||||
dds::sub::qos::SubscriberQos m_subscriberQos;
|
||||
dds::pub::qos::PublisherQos m_publisherQos;
|
||||
};
|
||||
|
||||
|
||||
class QosPatternDefault : public QosPattern {
|
||||
|
||||
public:
|
||||
QosPatternDefault() {
|
||||
using namespace dds::core::policy;
|
||||
qosReadWrite() << Ownership(OwnershipKind::SHARED)
|
||||
<< Reliability(ReliabilityKind::RELIABLE)
|
||||
<< Durability(DurabilityKind::TRANSIENT_LOCAL);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/QosPattern.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
|
||||
/// @brief Tmsif (rmodel-generated-models/appls)
|
||||
class QosPatternRm : public QosPattern {
|
||||
|
||||
public:
|
||||
QosPatternRm(const std::vector<std::string>& partitions, const bool ignoreLocal);
|
||||
};
|
||||
|
||||
|
||||
/// @brief Config/Report
|
||||
class QosPatternRmLateJoin : public QosPatternRm {
|
||||
|
||||
public:
|
||||
QosPatternRmLateJoin(const std::vector<std::string>& partitions, const bool ignoreLocal);
|
||||
};
|
||||
|
||||
|
||||
/// @brief Notify/Event / Cmd/Request/Response
|
||||
class QosPatternRmFireForget : public QosPatternRm {
|
||||
|
||||
public:
|
||||
QosPatternRmFireForget(const std::vector<std::string>& partitions, const bool ignoreLocal);
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/IQosStrategy.hpp"
|
||||
#include "ddkit/access/QosPattern.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
// default and example
|
||||
class QosStrategyDefault : public IQosStrategy {
|
||||
public:
|
||||
QosPattern selectQosPattern(const std::string& /*typeName*/) override {
|
||||
// typeName ignored in this case, set default for all typenames
|
||||
return QosPatternDefault().get();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/IQosStrategy.hpp"
|
||||
#include "ddkit/access/QosPattern.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class QosStrategyRm : public IQosStrategy {
|
||||
|
||||
public:
|
||||
QosStrategyRm(const std::vector<std::string>& partitions, const bool ignoreLocal);
|
||||
|
||||
QosPattern selectQosPattern(const std::string& typeName) override;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_partitions;
|
||||
bool m_ignoreLocal = false;
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/DdsWrap.hpp"
|
||||
#include "ddkit/access/Dispatcher.hpp"
|
||||
#include "ddkit/access/Topic.hpp"
|
||||
#include "ddkit/access/Listener.hpp"
|
||||
#include "ddkit/access/ConnectState.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
#if defined(DDS_VENDOR_CONNEXT)
|
||||
#define DDKIT_USE_KEY_VALUE ON
|
||||
#ifdef _WIN32
|
||||
#define DDKIT_COND_TYPE_UNUSED
|
||||
#else
|
||||
#define DDKIT_COND_TYPE_UNUSED dds::core::cond::Condition
|
||||
#endif
|
||||
#elif defined(DDS_VENDOR_CYCLONE)
|
||||
#define DDKIT_COND_TYPE_UNUSED dds::core::cond::Condition
|
||||
#elif defined(DDS_VENDOR_OPENSPLICE)
|
||||
#define DDKIT_COND_TYPE_UNUSED dds::core::cond::Condition
|
||||
#else
|
||||
#error "DDS_VENDOR not set"
|
||||
#endif
|
||||
|
||||
|
||||
template <typename T>
|
||||
class Reader final {
|
||||
public:
|
||||
Reader(
|
||||
std::shared_ptr<access::Dispatcher> dispatcher,
|
||||
std::shared_ptr<Topic<T>> topic,
|
||||
dds::sub::qos::DataReaderQos dataReaderQos,
|
||||
dds::sub::qos::SubscriberQos subQos,
|
||||
std::function<void(T const&)> funcWrite,
|
||||
std::function<void(T const&)> funcDispose)
|
||||
: m_dispatcher(dispatcher)
|
||||
, m_connectState(std::make_shared<ConnectState>(topic->topicName(), topic->topicNameModule(), topic->topicNameTopic()))
|
||||
, m_listener(std::make_shared<ListenerRead<T> >(m_connectState))
|
||||
, m_ddsReader(dataReader(topic, m_listener.get(), dataReaderQos, subQos))
|
||||
, m_dataState(dds::sub::status::DataState::any())
|
||||
, m_shutdownRequest(false)
|
||||
, m_funcWrite(funcWrite)
|
||||
, m_funcDispose(funcDispose)
|
||||
, m_func([this](DDKIT_COND_TYPE_UNUSED) {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
const dds::sub::LoanedSamples<T> samples = m_ddsReader.select().state(m_dataState).take();
|
||||
for (const auto& sample : samples) {
|
||||
if (m_shutdownRequest) return; // fast exit
|
||||
|
||||
const auto& sampleInfo = sample.info();
|
||||
#ifdef DDKIT_USE_KEY_VALUE
|
||||
const auto& instanceHandle = sampleInfo.instance_handle();
|
||||
#endif
|
||||
const auto& dataState = sampleInfo.state();
|
||||
const auto& instanceState = dataState.instance_state();
|
||||
|
||||
using namespace dds::sub::status;
|
||||
ddkit::log::trace() << "Sample alive:" << (instanceState == InstanceState::alive());
|
||||
ddkit::log::trace() << "Sample disposed:" << (instanceState == InstanceState::not_alive_disposed());
|
||||
ddkit::log::trace() << "Sample no_writers:" << (instanceState == InstanceState::not_alive_no_writers());
|
||||
|
||||
// How to get partition of sending writer
|
||||
// only connext and cyclone > 0.10
|
||||
// auto pubData = dds::sub::matched_publication_data(m_ddsReader, sampleInfo.publication_handle());
|
||||
// for (auto& n : pubData.partition()->name()) {
|
||||
// std::cout << "Partition: " << n << std::endl;
|
||||
// }
|
||||
|
||||
if (sampleInfo.valid() && instanceState == InstanceState::alive()) {
|
||||
const T& t = sample.data();
|
||||
|
||||
// callback
|
||||
if (m_funcWrite) {
|
||||
ddkit::log::debug() << "received: " << t << ". Callbacking user ...";
|
||||
m_funcWrite(t);
|
||||
ddkit::log::trace() << "... usercallback called.";
|
||||
}
|
||||
} else {
|
||||
|
||||
if (m_funcDispose) {
|
||||
#ifdef DDKIT_USE_KEY_VALUE
|
||||
// - 'key_value()' works perfectly for connext
|
||||
// (and for cyclone+opensplice while explicitly disposing)
|
||||
// - no (positive) effect on cross-vendor (see top of file)
|
||||
// - so it is best to stay with native sample.data() for cyclone+opensplice but
|
||||
// use simple key_value for connext
|
||||
T t;
|
||||
m_ddsReader.key_value(t, instanceHandle);
|
||||
#else
|
||||
// - vendors, that are able to fetch the key even on dispose-calls via sample.data()
|
||||
// (they fill in default-ctor-data in the other attrs, because only the key has
|
||||
// to be transferred via DDS for dispose - same definition on our API - fine).
|
||||
const T& t = sample.data();
|
||||
#endif
|
||||
ddkit::log::debug() << "received for disposing: " << t << ". Callbacking user ...";
|
||||
m_funcDispose(t);
|
||||
ddkit::log::trace() << "... usercallback called.";
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
, m_readCondition(m_ddsReader, m_dataState, m_func) {
|
||||
DDKIT_LOG_TRACE;
|
||||
m_dispatcher->addReadCondition(m_readCondition);
|
||||
}
|
||||
|
||||
~Reader() {
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
unload();
|
||||
m_ddsReader.close();
|
||||
}
|
||||
|
||||
void unload() {
|
||||
if (!m_shutdownRequest) {
|
||||
m_shutdownRequest = true;
|
||||
m_dispatcher->removeReadCondition(m_readCondition);
|
||||
}
|
||||
}
|
||||
|
||||
IConnectCheckPtr getConnectCheck() {
|
||||
return m_connectState;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Dispatcher> m_dispatcher;
|
||||
ConnectStatePtr m_connectState;
|
||||
std::shared_ptr<ListenerRead<T>> m_listener;
|
||||
dds::sub::DataReader<T> m_ddsReader;
|
||||
dds::sub::status::DataState m_dataState;
|
||||
|
||||
std::atomic<bool> m_shutdownRequest;
|
||||
std::function<void(T const&)> m_funcWrite;
|
||||
std::function<void(T const&)> m_funcDispose;
|
||||
std::function<void(DDKIT_COND_TYPE_UNUSED)> m_func;
|
||||
dds::sub::cond::ReadCondition m_readCondition;
|
||||
|
||||
/// Note on reader-listeners: see writer-listeners in Writer.hpp
|
||||
static dds::sub::DataReader<T> dataReader(
|
||||
std::shared_ptr<Topic<T>> topic,
|
||||
ListenerRead<T>* listener,
|
||||
dds::sub::qos::DataReaderQos dataReaderQos,
|
||||
dds::sub::qos::SubscriberQos subQos) {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
dds::sub::DataReader<T> ddsReader = dds::sub::DataReader<T>(
|
||||
dds::sub::Subscriber(topic->domainParticipant(), subQos),
|
||||
topic->ddsTopic(),
|
||||
dataReaderQos,
|
||||
listener,
|
||||
dds::core::status::StatusMask::all());
|
||||
|
||||
return ddsReader;
|
||||
}
|
||||
|
||||
// no copying
|
||||
Reader(Reader const&) = delete;
|
||||
Reader(Reader&&) = delete;
|
||||
void operator=(Reader const&) = delete;
|
||||
};
|
||||
|
||||
#undef DDKIT_USE_KEY_VALUE
|
||||
#undef DDKIT_COND_TYPE_UNUSED
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class System {
|
||||
|
||||
public:
|
||||
static System& instance();
|
||||
|
||||
private:
|
||||
System();
|
||||
~System();
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/DdsWrap.hpp"
|
||||
#include "ddkit/access/ITopic.hpp"
|
||||
#include "ddkit/access/Participant.hpp"
|
||||
#include "ddkit/access/Listener.hpp"
|
||||
|
||||
#include "ddkit/utils/Logger.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
template <typename T>
|
||||
class Reader;
|
||||
template <typename T>
|
||||
using ReaderPtr = std::shared_ptr<Reader<T>>;
|
||||
|
||||
template <typename T>
|
||||
class Writer;
|
||||
template <typename T>
|
||||
using WriterPtr = std::shared_ptr<Writer<T>>;
|
||||
|
||||
template <typename T>
|
||||
class Topic final : public ITopic {
|
||||
|
||||
public:
|
||||
dds::domain::DomainParticipant& domainParticipant() { return m_domainParticipant; }
|
||||
dds::topic::Topic<T> ddsTopic() { return m_ddsTopic; }
|
||||
std::string typeName() { return dds::topic::topic_type_name<T>::value(); }
|
||||
std::string topicNameModule() { return m_topicNameModule; }
|
||||
std::string topicNameTopic() { return m_topicNameTopic; }
|
||||
|
||||
// ITopic
|
||||
std::string topicName() override { return m_topicName; }
|
||||
|
||||
bool hasReader() override {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
return m_reader != nullptr;
|
||||
}
|
||||
|
||||
void unloadReader() override {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
DDKIT_LOG_TRACE << typeName();
|
||||
if (hasReader()) {
|
||||
m_reader->unload();
|
||||
}
|
||||
}
|
||||
|
||||
void closeReader() override {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
ddkit::log::debug() << "closeReader (" << typeName() << ")";
|
||||
if (hasReader()) {
|
||||
m_reader = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasWriter() override {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
return m_writer != nullptr;
|
||||
}
|
||||
|
||||
void closeWriter() override {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
ddkit::log::debug() << "closeWriter (" << typeName() << ")";
|
||||
if (hasWriter()) {
|
||||
m_writer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Topic(
|
||||
dds::domain::DomainParticipant& domainParticipant,
|
||||
const std::string& topicName,
|
||||
const std::string& topicNameModule,
|
||||
const std::string& topicNameTopic,
|
||||
dds::topic::qos::TopicQos topicQos) try
|
||||
: m_domainParticipant(domainParticipant)
|
||||
, m_topicName(topicName)
|
||||
, m_topicNameModule(topicNameModule)
|
||||
, m_topicNameTopic(topicNameTopic)
|
||||
, m_listener(std::make_shared<ListenerTopic<T> >())
|
||||
, m_ddsTopic(dds::core::null)
|
||||
, m_reader(nullptr)
|
||||
, m_writer(nullptr) {
|
||||
|
||||
#if defined(DDS_VENDOR_CONNEXT)
|
||||
m_ddsTopic = dds::topic::find<dds::topic::Topic<T>>(domainParticipant, topicName);
|
||||
#endif
|
||||
if (m_ddsTopic == dds::core::null) {
|
||||
m_ddsTopic = dds::topic::Topic<T>(
|
||||
m_domainParticipant,
|
||||
m_topicName,
|
||||
topicQos,
|
||||
m_listener.get(), // has to be set in constructor of topic
|
||||
dds::core::status::StatusMask::all()
|
||||
);
|
||||
}
|
||||
|
||||
ddkit::log::info() << "Created topic: " << m_topicName;
|
||||
|
||||
} catch (dds::core::Exception& e) {
|
||||
// happens once in a while on connext (if the same topic is ctored twice in same participant)
|
||||
ddkit::log::fatal() << "construction Topic " << topicName << " failed: " << e.what();
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
||||
void setReader(ReaderPtr<T> reader) {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
m_reader = reader;
|
||||
}
|
||||
|
||||
std::shared_ptr<Writer<T>> writer() {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
return m_writer;
|
||||
}
|
||||
|
||||
void setWriter(WriterPtr<T> writer) {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
m_writer = writer;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_isRead;
|
||||
dds::domain::DomainParticipant& m_domainParticipant;
|
||||
std::string m_topicName;
|
||||
std::string m_topicNameModule;
|
||||
std::string m_topicNameTopic;
|
||||
std::shared_ptr<ListenerTopic<T>> m_listener;
|
||||
dds::topic::Topic<T> m_ddsTopic;
|
||||
|
||||
std::recursive_mutex m_mutex;
|
||||
std::shared_ptr<Reader<T>> m_reader;
|
||||
std::shared_ptr<Writer<T>> m_writer;
|
||||
|
||||
// no copying
|
||||
Topic(Topic const&) = delete;
|
||||
Topic(Topic&&) = delete;
|
||||
void operator=(Topic const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/ITopic.hpp"
|
||||
#include "ddkit/access/IQosStrategy.hpp"
|
||||
#include "ddkit/access/TopicStrategy.hpp"
|
||||
#include "ddkit/access/Topic.hpp"
|
||||
|
||||
// Topic is included and only forward declares Reader,Writer - for writing-only-users we additionaly need the read-side
|
||||
// for template-instantiiation ... so include everything just in case ...
|
||||
#include "ddkit/access/Reader.hpp"
|
||||
#include "ddkit/access/Writer.hpp"
|
||||
|
||||
#include "ddkit/utils/string.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
// TopicPool very well could be the (abstract) base-class for TopicPoolRead and TopicPoolWrite again
|
||||
class TopicPool final {
|
||||
|
||||
public:
|
||||
TopicPool(
|
||||
dds::domain::DomainParticipant& domainParticipant,
|
||||
const IQosStrategyPtr& qosStrategy,
|
||||
const ITopicStrategyPtr& topicStrategy);
|
||||
|
||||
template <typename T>
|
||||
std::string getTopicName() {
|
||||
DDKIT_LOG_TRACE;
|
||||
std::string className = dds::topic::topic_type_name<T>::value();
|
||||
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(className);
|
||||
std::string topicName = m_topicStrategy->get(className);
|
||||
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(topicName);
|
||||
TopicStrategyMapChars topicStrategyMapChars;
|
||||
std::string topicNameSafe = topicStrategyMapChars.get(topicName);
|
||||
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(topicNameSafe);
|
||||
return topicNameSafe;
|
||||
}
|
||||
|
||||
/// @brief create or get
|
||||
template <typename T>
|
||||
std::shared_ptr<Topic<T>> topic() {
|
||||
DDKIT_LOG_TRACE;
|
||||
std::string topicName = getTopicName<T>();
|
||||
|
||||
if (!hasTopic(topicName)) {
|
||||
std::string className = dds::topic::topic_type_name<T>::value();
|
||||
ddkit::utils::string::removePrefixIf(className, "VendorData::");
|
||||
std::string::size_type pos = className.rfind("::");
|
||||
std::string partFirst = (pos == std::string::npos) ? "no-module" : className.substr(0, pos);
|
||||
std::string partLast = (pos == std::string::npos) ? className : className.substr(pos + 2);
|
||||
std::string topicNameModule = partFirst;
|
||||
std::string topicNameTopic = partLast;
|
||||
|
||||
m_name2topic.insert(std::make_pair(topicName, std::make_shared<Topic<T>>(
|
||||
m_domainParticipant,
|
||||
topicName,
|
||||
topicNameModule,
|
||||
topicNameTopic,
|
||||
m_qosStrategy->selectQosPattern(className).qosTopic()
|
||||
)));
|
||||
}
|
||||
|
||||
return std::dynamic_pointer_cast<Topic<T>>(getTopic(topicName));
|
||||
}
|
||||
|
||||
QosPattern qosPattern(const std::string& typeName) { return m_qosStrategy->selectQosPattern(typeName); }
|
||||
|
||||
template <typename T> // probably not needed with template-param
|
||||
QosPattern qosPattern() {
|
||||
std::string typeName = dds::topic::topic_type_name<T>::value();
|
||||
return qosPattern(typeName);
|
||||
}
|
||||
|
||||
bool hasTopic(const std::string& topicName);
|
||||
std::shared_ptr<ITopic> getTopic(const std::string& topicName);
|
||||
|
||||
bool hasReaders();
|
||||
void closeReaders();
|
||||
void closeWriters();
|
||||
void unloadReaders();
|
||||
|
||||
private:
|
||||
dds::domain::DomainParticipant& m_domainParticipant;
|
||||
IQosStrategyPtr m_qosStrategy;
|
||||
ITopicStrategyPtr m_topicStrategy;
|
||||
|
||||
std::recursive_mutex m_mutex;
|
||||
std::map<std::string, std::shared_ptr<ITopic>> m_name2topic;
|
||||
|
||||
// no copying
|
||||
TopicPool(TopicPool const&) = delete;
|
||||
TopicPool(TopicPool&&) = delete;
|
||||
void operator=(TopicPool const&) = delete;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<TopicPool> TopicPoolPtr;
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/TopicPool.hpp"
|
||||
#include "ddkit/access/Topic.hpp"
|
||||
#include "ddkit/access/Dispatcher.hpp"
|
||||
#include "ddkit/access/Reader.hpp"
|
||||
|
||||
#include "ddkit/utils/string.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class TopicPoolRead final {
|
||||
|
||||
public:
|
||||
TopicPoolRead(
|
||||
Participant& participant,
|
||||
const IQosStrategyPtr& qosStrategy,
|
||||
const ITopicStrategyPtr& topicStrategy,
|
||||
std::shared_ptr<Dispatcher> dispatcher);
|
||||
~TopicPoolRead();
|
||||
|
||||
// create Topic and Reader and register function for beeing callbacked by given dispatcher
|
||||
// (a second callback may be given for reading disposes as well)
|
||||
// todo name is historical, could be createReader
|
||||
template <typename T>
|
||||
void createTopicRead(std::function<void(T const&)> func, std::function<void(T const&)> funcDispose = nullptr) {
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
std::string topicName = m_topicPool.getTopicName<T>();
|
||||
|
||||
std::shared_ptr<Topic<T>> topic = m_topicPool.topic<T>();
|
||||
|
||||
if(!topic) {
|
||||
ddkit::log::error() << "TopicPoolRead::createTopicRead: no topic in topic pool.";
|
||||
return;
|
||||
}
|
||||
if(topic->hasReader()) {
|
||||
ddkit::log::error() << "TopicPoolRead::createTopicRead: Reader (" << topicName << ") already exists.";
|
||||
return;
|
||||
}
|
||||
|
||||
QosPattern qosPattern = m_topicPool.qosPattern(topic->typeName());
|
||||
dds::sub::qos::DataReaderQos dataReaderQos = qosPattern.qosRead();
|
||||
dds::sub::qos::SubscriberQos subQos = qosPattern.qosSub();
|
||||
|
||||
auto reader = std::make_shared<Reader<T>>(m_dispatcher, topic, dataReaderQos, subQos, func, funcDispose);
|
||||
topic->setReader(reader);
|
||||
}
|
||||
|
||||
// to be able to call with member-function-callbacks as well - transform to std::function
|
||||
// - this is used in ldm/test-context so far, no dispose-callback used here so far ...
|
||||
template <typename T, typename U>
|
||||
void createTopicRead(void (U::*funcPtr)(T const&), U& u) {
|
||||
DDKIT_LOG_TRACE;
|
||||
createTopicRead<T>(std::bind(funcPtr, &u, std::placeholders::_1));
|
||||
}
|
||||
|
||||
bool hasReaders();
|
||||
void closeReaders();
|
||||
void unloadReaders();
|
||||
|
||||
private:
|
||||
std::recursive_mutex m_mutex;
|
||||
TopicPool m_topicPool;
|
||||
std::shared_ptr<Dispatcher> m_dispatcher;
|
||||
|
||||
// no copying
|
||||
TopicPoolRead(TopicPoolRead const&) = delete;
|
||||
TopicPoolRead(TopicPoolRead&&) = delete;
|
||||
void operator=(TopicPoolRead const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,137 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/TopicPool.hpp"
|
||||
#include "ddkit/access/Topic.hpp"
|
||||
#include "ddkit/access/Writer.hpp"
|
||||
|
||||
#include "ddkit/utils/system.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class TopicPoolWrite final {
|
||||
|
||||
public:
|
||||
TopicPoolWrite(
|
||||
Participant& participant, const IQosStrategyPtr& qosStrategy, const ITopicStrategyPtr& topicStrategy);
|
||||
~TopicPoolWrite();
|
||||
|
||||
// create or get writer
|
||||
template <typename T>
|
||||
std::shared_ptr<Writer<T>> writer() {
|
||||
DDKIT_LOG_TRACE;
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
createTopicWriteIf<T>(); // must be done here and not in Topic (because TopicPool and qos access needed)
|
||||
|
||||
std::shared_ptr<Topic<T>> topic = m_topicPool.topic<T>();
|
||||
if(topic) {
|
||||
auto writer = topic->writer();
|
||||
if(!writer){
|
||||
ddkit::log::error() << "TopicPoolWrite::writer: no writer in topic";
|
||||
}
|
||||
return writer;
|
||||
} else {
|
||||
ddkit::log::error() << "TopicPoolWrite::writer: no topic in topic pool";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// shortcut, no interface+virtual possible (templates)
|
||||
template <class T>
|
||||
void write(T const& t) {
|
||||
bool isOkUnconnected = false;
|
||||
bool isThrowUnconnected = false;
|
||||
writeIntern(t, isOkUnconnected, isThrowUnconnected);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void writeUnconnectedOk(T const& t) {
|
||||
bool isOkUnconnected = true;
|
||||
bool isThrowUnconnected = false;
|
||||
writeIntern(t, isOkUnconnected, isThrowUnconnected);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void writeUnconnectedThrow(T const& t) {
|
||||
bool isOkUnconnected = false;
|
||||
bool isThrowUnconnected = false;
|
||||
writeIntern(t, isOkUnconnected, isThrowUnconnected);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void writeIntern(T const& t, bool isOkUnconnected, bool isThrowUnconnected) {
|
||||
ddkit::log::trace() << "writing " << dds::topic::topic_type_name<T>::value() << ":" << t;
|
||||
|
||||
createTopicWriteIf<T>();
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
auto currentWriter = writer<T>();
|
||||
if(currentWriter){
|
||||
currentWriter->send(t, isOkUnconnected, isThrowUnconnected);
|
||||
} else {
|
||||
ddkit::log::error() << "TopicPoolWrite::writeIntern: no writer in topic pool";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void createTopicWrite() {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
std::string topicName = m_topicPool.getTopicName<T>();
|
||||
std::shared_ptr<Topic<T>> topic = m_topicPool.topic<T>();
|
||||
std::string typeName = topic->typeName();
|
||||
|
||||
if(!topic) {
|
||||
ddkit::log::error() << "TopicPoolWrite::createTopicWrite: no topic in topic pool.";
|
||||
return;
|
||||
}
|
||||
if(topic->hasWriter()) {
|
||||
ddkit::log::error() << "TopicPoolWrite::createTopicWrite: Writer (" << topicName << ") already exists.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QosPattern qosPattern = m_topicPool.qosPattern(typeName);
|
||||
dds::pub::qos::DataWriterQos dataWriterQos = qosPattern.qosWrite();
|
||||
dds::pub::qos::PublisherQos pubQos = qosPattern.qosPub();
|
||||
|
||||
auto writer = std::make_shared<Writer<T>>(topic, dataWriterQos, pubQos);
|
||||
topic->setWriter(writer);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void createTopicWriteIf() {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
std::shared_ptr<Topic<T>> topic = m_topicPool.topic<T>();
|
||||
if (topic && !topic->hasWriter()) {
|
||||
createTopicWrite<T>();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
void dispose(T const& t) {
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
auto currentWriter = writer<T>();
|
||||
if(currentWriter){
|
||||
currentWriter->dispose(t);
|
||||
} else {
|
||||
ddkit::log::error() << "TopicPoolWrite::dispose: no writer in topic pool";
|
||||
}
|
||||
}
|
||||
|
||||
void closeWriters();
|
||||
|
||||
private:
|
||||
std::recursive_mutex m_mutex;
|
||||
TopicPool m_topicPool;
|
||||
|
||||
TopicPoolWrite(TopicPoolWrite const&) = delete;
|
||||
void operator=(TopicPoolWrite const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/ITopicStrategy.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
class TopicStrategyRemoveNamespaces : public ITopicStrategy {
|
||||
|
||||
public:
|
||||
std::string get(const std::string& typeName) override;
|
||||
};
|
||||
|
||||
|
||||
/// @brief replace "::" with "__" (as for example cyclone does not like '::' in topic-names)
|
||||
class TopicStrategyReplaceColons : public ITopicStrategy {
|
||||
|
||||
public:
|
||||
std::string get(const std::string& typeName) override;
|
||||
};
|
||||
|
||||
|
||||
/// @brief simply prepend the prefix (plus "_") - nothing else
|
||||
class TopicStrategyPrefix : public ITopicStrategy {
|
||||
|
||||
public:
|
||||
TopicStrategyPrefix(const std::string& prefix);
|
||||
|
||||
std::string get(const std::string& typeName) override;
|
||||
|
||||
private:
|
||||
std::string m_prefix;
|
||||
};
|
||||
|
||||
|
||||
/// @brief maps all 'unallowed' characters (everything besides [a-zA-Z0-9]) to '_' - implicitly called in TopicPool - always!
|
||||
class TopicStrategyMapChars : public ITopicStrategy {
|
||||
|
||||
public:
|
||||
TopicStrategyMapChars();
|
||||
|
||||
std::string get(const std::string& orig) override;
|
||||
};
|
||||
|
||||
|
||||
/// @brief SensorService + VendorData::M_Sensor::IService::ConfigSth -> ddkit_SensorService_Sensor_c2s_ConfigSth
|
||||
class TopicStrategyRmodel : public ITopicStrategy {
|
||||
|
||||
public:
|
||||
TopicStrategyRmodel(const std::string& prefix);
|
||||
|
||||
std::string get(const std::string& typeName) override;
|
||||
|
||||
private:
|
||||
TopicStrategyReplaceColons m_tnsReplaceColons;
|
||||
TopicStrategyPrefix m_tnsPrefix;
|
||||
};
|
||||
|
||||
|
||||
/// @brief module::name -> module_name
|
||||
class TopicStrategySimple : public ITopicStrategy {
|
||||
|
||||
public:
|
||||
std::string get(const std::string& typeName) override;
|
||||
};
|
||||
|
||||
|
||||
/// @brief remove big-char-prefixes and -suffixes and replace colons by underscore
|
||||
/// - P_Navigation_Reference_PSM::C_Angular_Motion --> Navigation_Reference__Angular_Motion
|
||||
class TopicStrategyStd : public ITopicStrategy {
|
||||
|
||||
public:
|
||||
std::string get(const std::string& typeName) override;
|
||||
};
|
||||
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/access/DdsWrap.hpp"
|
||||
#include "ddkit/access/Topic.hpp"
|
||||
#include "ddkit/access/Listener.hpp"
|
||||
#include "ddkit/access/ConnectState.hpp"
|
||||
|
||||
#include "ddkit/utils/Logger.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
|
||||
template <typename T>
|
||||
class Writer final {
|
||||
|
||||
public:
|
||||
explicit Writer(std::shared_ptr<Topic<T>> topic, dds::pub::qos::DataWriterQos dataWriterQos, dds::pub::qos::PublisherQos pubQos)
|
||||
: m_connectState(std::make_shared<ConnectState>(topic->topicName(), topic->topicNameModule(), topic->topicNameTopic()))
|
||||
, m_listener(std::make_shared<ListenerWrite<T> >(m_connectState))
|
||||
, m_writer(dataWriter(topic, m_listener.get(), dataWriterQos, pubQos)) {
|
||||
DDKIT_LOG_TRACE;
|
||||
}
|
||||
|
||||
~Writer() {
|
||||
DDKIT_LOG_TRACE;
|
||||
// ddkit::log::info() << "closing writer!";
|
||||
m_writer.close();
|
||||
}
|
||||
|
||||
bool isConnected() { return m_connectState->isConnected(); }
|
||||
void waitUntilConnected() { m_connectState->waitUntilConnected(); }
|
||||
|
||||
IConnectCheckPtr getConnectCheck() { return m_connectState; }
|
||||
|
||||
/// @brief isOkUnconnected == true -> do not warn about write while not connected
|
||||
/// - one could set this on a late-join-topic to avoid the warnings
|
||||
/// isThrowUnconnected == true -> do throw momentarily
|
||||
/// - one could set this on a 'checked' write ('Cmd')
|
||||
void send(T const& sample, bool isOkUnconnected, bool isThrowUnconnected) {
|
||||
ddkit::log::debug() << "send: " << DDKIT_LOG_VAR_VALUE(sample);
|
||||
|
||||
bool isConnected = m_connectState->isConnected();
|
||||
|
||||
// return immediately, if Service for command is not yet connected (and told to throw)
|
||||
if (!isConnected && isThrowUnconnected) {
|
||||
throw std::runtime_error("Service for Cmd is unavailable yet - try later.");
|
||||
}
|
||||
// todo: as monitor-sessions are not distinguished so far, this (direct) exception will not be thrown,
|
||||
// if a monitor is running and connected
|
||||
|
||||
// warn about probably lost samples (if not told otherwise)
|
||||
if (!isConnected && !isOkUnconnected) {
|
||||
ddkit::log::info() << "Writer not connected while sending (" << dds::topic::topic_type_name<T>::value() << ").";
|
||||
}
|
||||
|
||||
// do the write
|
||||
m_writer.write(sample);
|
||||
}
|
||||
|
||||
void dispose(T const& sample) {
|
||||
DDKIT_LOG_TRACE;
|
||||
ddkit::log::debug() << "dispose: " << DDKIT_LOG_VAR_VALUE(sample);
|
||||
|
||||
// Get handle of instance
|
||||
auto handle = m_writer.lookup_instance(sample);
|
||||
|
||||
// Instance has to be known
|
||||
if (handle.is_nil()) {
|
||||
ddkit::log::error() << "Tried to remove object \"" << sample << "\", which does not exist in dds.";
|
||||
return;
|
||||
}
|
||||
|
||||
// We have to do both `dispose_instance` and `unregister_instance`
|
||||
// to fully free the instance. If we would just dispose the instance
|
||||
// the instance would remain stored by the reader and writer since it
|
||||
// remains `active`. Only after the `unregister_instance` the instance
|
||||
// has no associated writer and can be freed.
|
||||
m_writer.dispose_instance(handle);
|
||||
m_writer.unregister_instance(handle);
|
||||
}
|
||||
|
||||
private:
|
||||
ConnectStatePtr m_connectState;
|
||||
std::shared_ptr<ListenerWrite<T>> m_listener;
|
||||
dds::pub::DataWriter<T> m_writer;
|
||||
|
||||
/// Note on writer-listeners:
|
||||
/// - listeners have to be set in the constructor of the writer, because
|
||||
/// an event could be missing, when the listener is set afterwards
|
||||
/// - all depending on how fast discovery etc is, see also here:
|
||||
/// https://github.com/eclipse-cyclonedds/cyclonedds-cxx/issues/378#issuecomment-1463626212
|
||||
static dds::pub::DataWriter<T> dataWriter(
|
||||
std::shared_ptr<Topic<T>> topic,
|
||||
ListenerWrite<T>* listener,
|
||||
dds::pub::qos::DataWriterQos dataWriterQos,
|
||||
dds::pub::qos::PublisherQos pubQos) {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
dds::pub::DataWriter<T> ddsWriter = dds::pub::DataWriter<T>(
|
||||
dds::pub::Publisher(topic->domainParticipant(), pubQos),
|
||||
topic->ddsTopic(),
|
||||
dataWriterQos,
|
||||
listener,
|
||||
dds::core::status::StatusMask::all());
|
||||
|
||||
return ddsWriter;
|
||||
}
|
||||
|
||||
// no copying
|
||||
Writer(Writer const&) = delete;
|
||||
Writer(Writer&&) = delete;
|
||||
void operator=(Writer const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <ostream>
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
struct ActorInfo;
|
||||
struct ActorConfiguration;
|
||||
|
||||
// serviceName must be simple (a-z...)
|
||||
void checkApiServiceName(const std::string& serviceName);
|
||||
void checkServiceNameIntern(const std::string& serviceName);
|
||||
|
||||
// M_Mount::IService
|
||||
std::string interfaceNameApi(bool isService, const std::string& module);
|
||||
|
||||
// M_Mount::Service
|
||||
std::string serviceClientNameApi(bool isService, const std::string& module);
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, ActorConfiguration const& rhs);
|
||||
|
||||
struct ActorConfiguration {
|
||||
|
||||
ActorConfiguration(
|
||||
const std::string& module,
|
||||
bool isService,
|
||||
int domain,
|
||||
const std::string& serviceName);
|
||||
ActorConfiguration(const ddkit::actors::ActorInfo& actorInfo);
|
||||
ActorConfiguration() = default;
|
||||
|
||||
operator std::string() const {
|
||||
if (serviceName.empty()) {
|
||||
return std::string() + "(" + serviceClientNameApi(isService, module) + ", " + std::to_string(domain) + ", <no-servicename>)";
|
||||
}
|
||||
return std::string() + "(" + serviceClientNameApi(isService, module) + ", " + std::to_string(domain) + ", \"" + serviceName + "\")";
|
||||
}
|
||||
|
||||
bool operator==(ActorConfiguration const& rhs) const;
|
||||
bool operator<(ActorConfiguration const& rhs) const;
|
||||
|
||||
std::string module;
|
||||
bool isService;
|
||||
int domain;
|
||||
std::string serviceName;
|
||||
};
|
||||
|
||||
|
||||
/// @brief this is "ServiceInfo" / "ClientInfo" really. Do not mistake this for ddkit_intern::ActorInfo (idl-generated class)
|
||||
/// for monitoring applications like Listener
|
||||
/// - do not use in other cases.
|
||||
struct ActorInfo {
|
||||
|
||||
ActorInfo() = default;
|
||||
|
||||
ActorConfiguration config;
|
||||
|
||||
// also part of config (needed to disambiguate clients (multiple of same config allowed in network), also useful for error-detection of services)
|
||||
std::string actorId;
|
||||
|
||||
int32_t processId;
|
||||
std::string hostName;
|
||||
std::string procName;
|
||||
|
||||
bool isReading;
|
||||
std::vector<std::string> openReaders;
|
||||
bool isWriting;
|
||||
std::vector<std::string> openWriters;
|
||||
|
||||
// todo: maybe implement more informations here about the inherited interfaces? See section 7,
|
||||
// possible Inspector-improvements
|
||||
// maybe something like 'std::map<std::string, std::vector<std::string>> m_module2openReadersModule' would be
|
||||
// fine here, but probably it's only a matter of display. Inspector can show everything without changes here.
|
||||
|
||||
std::string clientName; // client-display-Name, on service: filled with "undefined"
|
||||
// on client: actorId or setName/create/add-given user-value
|
||||
|
||||
// bool isMonitor - no, not needed, the monitoring-actorInfos are not sent to the dds ... so true never shows up
|
||||
|
||||
// debug
|
||||
friend std::ostream& operator<<(std::ostream& s, ActorInfo const& rhs);
|
||||
operator std::string() const;
|
||||
|
||||
// set-order
|
||||
bool operator<(ActorInfo const& rhs) const;
|
||||
|
||||
// default copying
|
||||
};
|
||||
|
||||
typedef ActorInfo ServiceInfo;
|
||||
typedef ActorInfo ClientInfo;
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/ThreadSync.hpp"
|
||||
#include "ddkit/access/TopicPoolWrite.hpp"
|
||||
#include "ddkit/access/TopicPoolRead.hpp"
|
||||
#include "ddkit/idls/ActorInfo.hpp"
|
||||
#include "ddkit/actors/ActorInfo.hpp"
|
||||
#include "ddkit/actors/ILocalServices.hpp"
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
/// @brief DDS-Database for all ddkit_intern::ActorInfo on the network.
|
||||
/// The data is added/removed by the ActorInfoDbCaretaker.
|
||||
class ActorInfoDb {
|
||||
|
||||
public:
|
||||
ActorInfoDb(ILocalServices& localServices);
|
||||
~ActorInfoDb();
|
||||
|
||||
void updateActorInfo(ddkit_intern::ActorInfo actorInfo, int domainId);
|
||||
void removeActorInfo(ddkit_intern::ActorInfo actorInfo, int domainId);
|
||||
|
||||
// for "find()"
|
||||
std::vector<ActorInfo> findActorInfo(const std::string& module, bool isService, int domain);
|
||||
std::vector<ActorInfo> findActorInfo(
|
||||
const std::string& module, bool isService, int domain, const std::string& serviceName);
|
||||
std::vector<ActorInfo> findActorInfo(ActorConfiguration config);
|
||||
std::vector<ActorInfo> findActorInfo(const std::string& actorId);
|
||||
|
||||
// for "isRunning()"
|
||||
bool hasService(const std::string& module, int domain, const std::string& serviceName);
|
||||
|
||||
// for "wait()"
|
||||
void waitForService(const std::string& module, int domain, const std::string& serviceName);
|
||||
|
||||
// access meta-infos for callbackInfo
|
||||
std::string clientActorId2clientName(const std::string& clientActorId);
|
||||
|
||||
private:
|
||||
std::recursive_mutex m_mutex;
|
||||
std::condition_variable_any m_dbChanged;
|
||||
ILocalServices& m_localServices;
|
||||
|
||||
std::vector<ddkit_intern::ActorInfo> m_actorInfos;
|
||||
std::map<std::string, std::string> m_discardedActorIdToClientName;
|
||||
|
||||
// no copying
|
||||
ActorInfoDb(ActorInfoDb const&) = delete;
|
||||
ActorInfoDb(ActorInfoDb&&) = delete;
|
||||
void operator=(ActorInfoDb const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/ThreadSync.hpp"
|
||||
#include "ddkit/access/TopicPoolWrite.hpp"
|
||||
#include "ddkit/access/TopicPoolRead.hpp"
|
||||
#include "ddkit/idls/ActorInfo.hpp"
|
||||
#include "ddkit/actors/ActorInfo.hpp"
|
||||
#include "ddkit/actors/ActorInfoDb.hpp"
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
ActorConfiguration actorInfoToActorConfiguration(ddkit_intern::ActorInfo actorInfo);
|
||||
ActorInfo actorInfoToActorInfo(const ddkit_intern::ActorInfo& ddsActorInfo);
|
||||
|
||||
/// @brief Caretaker for actorInfo.
|
||||
/// Registers for ActorInfo-msgs on dds and stores them in ActorInfoDb.
|
||||
class ActorInfoDbCaretaker {
|
||||
|
||||
public:
|
||||
ActorInfoDbCaretaker(ActorInfoDb& db);
|
||||
~ActorInfoDbCaretaker();
|
||||
|
||||
void init(access::Participant& participant, std::shared_ptr<access::Dispatcher> dispatcher);
|
||||
void close();
|
||||
|
||||
void onWrite_actorInfo(const ddkit_intern::ActorInfo& actorInfo);
|
||||
void onDispose_actorInfo(const ddkit_intern::ActorInfo& actorInfo);
|
||||
|
||||
private:
|
||||
ActorInfoDb& m_db;
|
||||
|
||||
access::IQosStrategyPtr m_qosStrategy;
|
||||
access::ITopicStrategyPtr m_topicStrategy;
|
||||
|
||||
std::unique_ptr<access::TopicPoolRead> m_topicPoolRead;
|
||||
|
||||
int m_domainId;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/ThreadSync.hpp"
|
||||
#include "ddkit/access/TopicPoolWrite.hpp"
|
||||
#include "ddkit/access/TopicPoolRead.hpp"
|
||||
#include "ddkit/idls/ActorInfo.hpp"
|
||||
#include "ddkit/actors/ActorInfo.hpp"
|
||||
#include "ddkit/actors/ActorInfoDb.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
/// @brief Encapsulation of a dds-writer for ActorInfo-messages (per domain) / SessionImpl uses.
|
||||
class ActorInfoWriter {
|
||||
|
||||
public:
|
||||
explicit ActorInfoWriter(access::Participant& participant);
|
||||
void write(const ddkit_intern::ActorInfo& actorInfo);
|
||||
void dispose(const ddkit_intern::ActorInfo& actorInfo);
|
||||
|
||||
private:
|
||||
int m_domain;
|
||||
access::IQosStrategyPtr m_qosStrategy;
|
||||
access::ITopicStrategyPtr m_topicStrategy;
|
||||
access::TopicPoolWrite m_topicPoolWrite;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,382 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/utils/assert.hpp"
|
||||
#include "ddkit/actors/Key.hpp"
|
||||
#include "ddkit/actors/SessionManager.hpp"
|
||||
#include "ddkit/actors/SessionImpl.hpp"
|
||||
#include "ddkit/actors/SimpleActor.hpp"
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
/// @brief The calls (add/create/remove/remove/shutdown/shutdown) from the generated code are delegated here.
|
||||
/// We try to create/remove Actors as much as "normal" as it would be done via Session/Service/Client
|
||||
/// but of course there are some differences, as two calls may create only one Actor etc.
|
||||
/// Keep one SimpleActorPtr as replacement for the not-existing Service/Client-proxys in own list.
|
||||
class BackwardManager {
|
||||
|
||||
public:
|
||||
static BackwardManager& instance();
|
||||
|
||||
/// @brief called from generated code: ObsFactory::add()
|
||||
template <typename Observer>
|
||||
void createObserver(
|
||||
const std::string& serviceName,
|
||||
int domain,
|
||||
bool isService,
|
||||
const std::string& moduleName,
|
||||
typename Observer::TypeUser* callbacks,
|
||||
const std::vector<std::string>& methods,
|
||||
const std::string& clientName = "") {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
ddkit::log::warn() << "add(): You are using the deprecated C-Style API. "
|
||||
<< "It is recommended to upgrade to the new object-oriented API. "
|
||||
<< " Please note that it may be removed in future versions.";
|
||||
|
||||
ddkit::log::debug() << "create observer by key api: " << serviceName << ", " << std::to_string(domain);
|
||||
|
||||
checkApiServiceName(serviceName);
|
||||
|
||||
checkObserverType<Observer>();
|
||||
|
||||
ActorConfiguration config(moduleName, isService, domain, serviceName);
|
||||
SimpleActorPtr actor = createOrGetActor(serviceName, domain, isService, moduleName);
|
||||
|
||||
DDKIT_THROW_ON_FALSE_INFO(actor, "Failed to create actor");
|
||||
|
||||
IObserverPtr observer = actor->createObserver<Observer>(*callbacks, methods);
|
||||
|
||||
// if empty there is no need to send data over the wire
|
||||
if (!clientName.empty() && !isService) {
|
||||
actor->setClientName(clientName);
|
||||
}
|
||||
|
||||
// global maps
|
||||
m_observer2actorConfig.insert(std::make_pair(observer, config));
|
||||
typeUser2observerMap<Observer>().insert(std::make_pair(callbacks, observer));
|
||||
}
|
||||
|
||||
/// @brief called from generated code: Factory::create()
|
||||
template <typename Sender>
|
||||
typename Sender::TypeUser* createSender(
|
||||
const std::string& serviceName,
|
||||
int domain,
|
||||
bool isService,
|
||||
const std::string& moduleName,
|
||||
const std::vector<std::string>& methods,
|
||||
const std::string& clientName = "") {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
ddkit::log::warn() << "create(): You are using the deprecated C-Style API. "
|
||||
<< "It is recommended to upgrade to the new object-oriented API. "
|
||||
<< "Please note that it may be removed in future versions.";
|
||||
|
||||
ddkit::log::debug() << "create sender by key api: " << moduleName;
|
||||
|
||||
checkApiServiceName(serviceName);
|
||||
|
||||
checkSenderType<Sender>();
|
||||
|
||||
ActorConfiguration config(moduleName, isService, domain, serviceName);
|
||||
SimpleActorPtr actor = createOrGetActor(serviceName, domain, isService, moduleName);
|
||||
|
||||
DDKIT_THROW_ON_FALSE_INFO(actor, "Failed to create actor");
|
||||
|
||||
ISenderPtr isender = actor->createSender<Sender>(methods);
|
||||
|
||||
DDKIT_THROW_ON_FALSE_INFO(isender, "BackwardManager::createSender: could not create sender");
|
||||
|
||||
// if empty there is no need to send data over the wire
|
||||
if (!clientName.empty()) {
|
||||
actor->setClientName(clientName);
|
||||
}
|
||||
|
||||
// return raw-ptr for old C-API
|
||||
Sender* sender = dynamic_cast<Sender*>(isender.get()); // downcast - Sender inherits ISender
|
||||
DDKIT_THROW_ON_FALSE(sender);
|
||||
typename Sender::TypeUser* senderUser = sender; // upcast - Sender inherits IService/IClient
|
||||
|
||||
// global maps
|
||||
std::unique_lock<std::recursive_mutex> lockMaps(m_mutex);
|
||||
m_sender2actorConfig.insert(std::make_pair(isender, config));
|
||||
|
||||
typeUser2senderMap<Sender>().insert(std::make_pair(senderUser, isender));
|
||||
|
||||
return senderUser;
|
||||
}
|
||||
|
||||
/// @brief called from generated code: ObsFactory::remove()
|
||||
template <typename Observer>
|
||||
void removeObserverByObserverUser(
|
||||
typename Observer::TypeUser* observerUser, bool isService, const std::string& moduleName) {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
ddkit::log::warn() << "remove(): You are using the deprecated C-Style API. "
|
||||
<< "It is recommended to upgrade to the new object-oriented API. "
|
||||
<< "Please note that it may be removed in future versions.";
|
||||
|
||||
ddkit::log::debug() << "Remove Observer By Observer User: " << moduleName;
|
||||
|
||||
{
|
||||
checkObserverType<Observer>();
|
||||
|
||||
DDKIT_THROW_ON_FALSE_INFO(observerUser, interfaceNameApi(isService, moduleName) + "ObsFactory::remove()"
|
||||
+ " called with Observer* == nullptr ?");
|
||||
|
||||
// global maps
|
||||
DDKIT_THROW_ON_FALSE_INFO(typeUser2observerMap<Observer>().find(observerUser) != typeUser2observerMap<Observer>().end(),
|
||||
interfaceNameApi(isService, moduleName) + "ObsFactory::remove()"
|
||||
+ " called with Observer* not given to " + interfaceNameApi(isService, moduleName)
|
||||
+ "ObsFactory::add*() before? (or removed twice?)");
|
||||
|
||||
IObserverPtr observer = typeUser2observerMap<Observer>().at(observerUser);
|
||||
DDKIT_THROW_ON_FALSE_INFO(observer, "removeObserverByObserverUser: observer not found");
|
||||
|
||||
ActorConfiguration config = m_observer2actorConfig.at(observer);
|
||||
ddkit::log::debug() << "called Obs...remove() on " << config;
|
||||
|
||||
DDKIT_THROW_ON_FALSE(config.isService == isService);
|
||||
DDKIT_THROW_ON_FALSE(config.module == moduleName);
|
||||
|
||||
// global maps
|
||||
m_observer2actorConfig.erase(observer);
|
||||
typeUser2observerMap<Observer>().erase(typeUser2observerMap<Observer>().find(observerUser));
|
||||
|
||||
SessionImplPtr sessionImpl = findSession(config.domain);
|
||||
if (sessionImpl) {
|
||||
SimpleActorPtr actor = sessionImpl->findActor(config.serviceName, config.isService, config.module);
|
||||
if (actor) {
|
||||
if (actor->hasSender()) {
|
||||
ddkit::log::warn() << "The actor still has a sender, the observer will be deleted after sender is also destoryed!"
|
||||
<< " Consider using the OO-Api.";
|
||||
} else {
|
||||
auto it = m_config2actor.find(config);
|
||||
if (it != m_config2actor.end()) {
|
||||
if (m_config2actor.at(config) == actor) {
|
||||
m_config2actor.erase(it);
|
||||
|
||||
actor->shutdown();
|
||||
|
||||
// wait until dispatcher etc are done.
|
||||
while (actor.use_count() > 1) {
|
||||
ddkit::utils::system::msSleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sessionImpl.reset(); // local hold ptr
|
||||
removeSessionIfEmpty(config.domain);
|
||||
}
|
||||
}
|
||||
checkIfEmpty();
|
||||
}
|
||||
|
||||
/// @brief called from generated code: Factory::remove()
|
||||
template <typename Sender>
|
||||
void removeSenderBySenderUser(typename Sender::TypeUser* senderUser, bool isService, const std::string& moduleName) {
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
ddkit::log::warn() << "remove(): You are using the deprecated C-Style API. "
|
||||
<< "It is recommended to upgrade to the new object-oriented API. "
|
||||
<< "Please note that it may be removed in future versions.";
|
||||
|
||||
ddkit::log::debug() << "RemoveSender By Sender User: " << moduleName;
|
||||
|
||||
{
|
||||
checkSenderType<Sender>();
|
||||
|
||||
DDKIT_THROW_ON_FALSE_INFO(senderUser, interfaceNameApi(isService, moduleName) + "Factory::remove()"
|
||||
+ " called with Sender* == nullptr ?");
|
||||
// global maps
|
||||
DDKIT_THROW_ON_FALSE_INFO(typeUser2senderMap<Sender>().find(senderUser) != typeUser2senderMap<Sender>().end(),
|
||||
interfaceNameApi(isService, moduleName) + "Factory::remove()"
|
||||
+ " called with Sender* not received from " + interfaceNameApi(isService, moduleName)
|
||||
+ "Factory::create() before? (or removed twice?)");
|
||||
|
||||
ISenderPtr sender = typeUser2senderMap<Sender>().at(senderUser);
|
||||
DDKIT_THROW_ON_FALSE_INFO(sender, "Sender not found");
|
||||
|
||||
ActorConfiguration config = m_sender2actorConfig.at(sender);
|
||||
ddkit::log::debug() << "called ...remove() on " << config;
|
||||
DDKIT_THROW_ON_FALSE(config.isService == isService);
|
||||
DDKIT_THROW_ON_FALSE(config.module == moduleName);
|
||||
|
||||
// remove sender from global maps
|
||||
m_sender2actorConfig.erase(sender);
|
||||
typeUser2senderMap<Sender>().erase(typeUser2senderMap<Sender>().find(senderUser));
|
||||
|
||||
SessionImplPtr sessionImpl = findSession(config.domain);
|
||||
if (sessionImpl) {
|
||||
SimpleActorPtr actor = sessionImpl->findActor(config.serviceName, config.isService, config.module);
|
||||
if (actor) {
|
||||
actor->discardSender();
|
||||
if (actor->hasObserver()) {
|
||||
// still has a observer dont shutdown actor!
|
||||
ddkit::log::warn() << "There is still a observer, make sure to delete it too."
|
||||
<< " Consider using the new OO-Api.";
|
||||
} else {
|
||||
ddkit::log::debug() << "Does not have a observer, we can shutdown the actor.";
|
||||
auto configIt = m_config2actor.find(config);
|
||||
if (configIt != m_config2actor.end()) {
|
||||
if (m_config2actor.at(config) == actor) {
|
||||
m_config2actor.erase(configIt);
|
||||
|
||||
actor->shutdown();
|
||||
|
||||
// wait until dispatcher etc are done.
|
||||
while (actor.use_count() > 1) {
|
||||
ddkit::utils::system::msSleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sessionImpl.reset(); // local hold session-ptr
|
||||
removeSessionIfEmpty(config.domain);
|
||||
}
|
||||
}
|
||||
checkIfEmpty();
|
||||
}
|
||||
|
||||
/// @brief called from generated code: ObsFactory::shutdown()
|
||||
template <typename Observer>
|
||||
void shutdownObservers(bool isService, const std::string& moduleName) {
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
ddkit::log::warn() << "shutdown(): You are using the deprecated C-Style API. "
|
||||
<< "It is recommended to upgrade to the new object-oriented API. "
|
||||
<< "Please note that it may be removed in future versions.";
|
||||
|
||||
ddkit::log::debug() << "shutdown observers: " << moduleName;
|
||||
|
||||
checkObserverType<Observer>();
|
||||
typedef typename Observer::TypeUser TypeUser;
|
||||
|
||||
std::vector<TypeUser*> observerUsers;
|
||||
for (auto& p : typeUser2observerMap<Observer>()) {
|
||||
observerUsers.push_back(p.first);
|
||||
}
|
||||
for (TypeUser* typeUser : observerUsers) {
|
||||
removeObserverByObserverUser<Observer>(typeUser, isService, moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief called from generated code: Factory::shutdown()
|
||||
template <typename Sender>
|
||||
void shutdownSenders(bool isService, const std::string& moduleName) {
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
ddkit::log::warn() << "shutdown(): You are using the deprecated C-Style API. "
|
||||
<< "It is recommended to upgrade to the new object-oriented API. "
|
||||
<< "Please note that it may be removed in future versions.";
|
||||
|
||||
ddkit::log::debug() << "Shutdown senders: " << moduleName;
|
||||
|
||||
checkSenderType<Sender>();
|
||||
typedef typename Sender::TypeUser TypeUser;
|
||||
|
||||
std::vector<TypeUser*> senderUsers;
|
||||
for (auto& p : typeUser2senderMap<Sender>()) {
|
||||
senderUsers.push_back(p.first);
|
||||
}
|
||||
for (TypeUser* typeUser : senderUsers) {
|
||||
removeSenderBySenderUser<Sender>(typeUser, isService, moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief called from generated code: ObsFactory::getSource()
|
||||
template <typename Observer>
|
||||
std::string getSource(bool isService, const std::string& moduleName) {
|
||||
|
||||
DDKIT_LOG_TRACE;
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
ddkit::log::warn() << "getSource(): You are using the deprecated C-Style API. "
|
||||
<< "It is recommended to upgrade to the new object-oriented API. "
|
||||
<< "Please note that it may be removed in future versions. "
|
||||
<< "Use ddkit::actors::CallbackInfo::current(); instead.";
|
||||
|
||||
CallbackInfo callbackInfo = SessionManager::instance().callbackInfo();
|
||||
|
||||
bool isToServiceReal = callbackInfo.isFromClient;
|
||||
|
||||
if (isService != isToServiceReal) {
|
||||
ddkit::log::warn() << "getSource() was called on ObsFactory of " << interfaceNameApi(isService, moduleName)
|
||||
<< " but callback right now is sending data to "
|
||||
<< serviceClientNameApi(isToServiceReal, moduleName) << ". Probably one should use \""
|
||||
<< interfaceNameApi(isToServiceReal, moduleName) << "ObsFactory\" instead of \""
|
||||
<< interfaceNameApi(isService, moduleName) << "ObsFactory\", to remove this warning.";
|
||||
}
|
||||
|
||||
// as "source" we gave back the serviceName or the clientId, depending on the side
|
||||
if (callbackInfo.isFromClient) {
|
||||
// client called service
|
||||
return callbackInfo.clientName; // this is sendingActor (=clientActorId) or user-given clientName
|
||||
} else {
|
||||
// service called client
|
||||
return callbackInfo.serviceName;
|
||||
}
|
||||
}
|
||||
|
||||
SessionImplPtr createOrGetSession_(int domain);
|
||||
|
||||
bool isClean() const;
|
||||
|
||||
private:
|
||||
std::recursive_mutex m_mutex;
|
||||
std::map<int, SessionImplPtr> m_domain2session;
|
||||
std::map<ActorConfiguration, SimpleActorPtr> m_config2actor; // holding Actors exactly as long, as add/create/remove tells
|
||||
|
||||
// Pointers to actors-configs
|
||||
std::map<IObserverPtr, ActorConfiguration> m_observer2actorConfig;
|
||||
std::map<ISenderPtr, ActorConfiguration> m_sender2actorConfig;
|
||||
|
||||
BackwardManager();
|
||||
~BackwardManager();
|
||||
|
||||
SimpleActorPtr createOrGetActor(const std::string& serviceName, int domain, bool isService, const std::string& moduleName);
|
||||
SessionImplPtr findSession(int domain);
|
||||
SessionImplPtr createOrGetSession(int domain);
|
||||
void removeSessionIfEmpty(int domain);
|
||||
void checkIfEmpty();
|
||||
|
||||
// these functions are used to circumvent the fact das data members cant be templated
|
||||
// which is only somewhat fine since BackwardManger is a singleton class
|
||||
template <typename Sender> std::map<typename Sender::TypeUser*, ISenderPtr>& typeUser2senderMap() {
|
||||
static std::map<typename Sender::TypeUser*, ISenderPtr> s_typeUser2sender;
|
||||
return s_typeUser2sender;
|
||||
}
|
||||
|
||||
template <typename Observer> std::map<typename Observer::TypeUser*, IObserverPtr>& typeUser2observerMap() {
|
||||
static std::map<typename Observer::TypeUser*, IObserverPtr> s_typeUser2observer;
|
||||
return s_typeUser2observer;
|
||||
}
|
||||
|
||||
// no copying
|
||||
BackwardManager(BackwardManager const&) = delete;
|
||||
BackwardManager(BackwardManager&&) = delete;
|
||||
void operator=(BackwardManager const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <memory>
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class IActor;
|
||||
typedef std::shared_ptr<IActor> ActorPtr;
|
||||
|
||||
struct CallbackInfo {
|
||||
std::string serviceName; // serviceName of sending actor (client or service), this is always a real name
|
||||
std::string sendingActor; // clientActorId or serviceActorId
|
||||
std::string operationName; // rmodel-operationName, for example "ConfigAbc"
|
||||
|
||||
bool isFromClient;
|
||||
bool isFromService;
|
||||
bool isToClient;
|
||||
bool isToService;
|
||||
|
||||
std::string clientName; // filled, if isFromClient, clientActorId, if user set clientName, clientName
|
||||
|
||||
int64_t timestampInMsSinceEpoch;
|
||||
|
||||
/// @brief Get informations about the current callback
|
||||
/// This function should only be used inside a callback.
|
||||
/// @return The current CallbackInfo object.
|
||||
static CallbackInfo current();
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& s, CallbackInfo const& rhs);
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "SessionImpl.hpp"
|
||||
#include "ddkit/utils/container.hpp"
|
||||
|
||||
#include "ddkit/actors/SessionImpl.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class IActor;
|
||||
typedef std::shared_ptr<IActor> ActorPtr;
|
||||
|
||||
class SessionImpl;
|
||||
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
|
||||
typedef std::weak_ptr<SessionImpl> SessionImplWeakPtr;
|
||||
|
||||
class IActor : public std::enable_shared_from_this<IActor> {
|
||||
public:
|
||||
virtual ~IActor();
|
||||
SessionImplPtr sessionImpl();
|
||||
|
||||
bool isMonitor();
|
||||
|
||||
virtual void shutdown() = 0;
|
||||
virtual bool isValid() = 0;
|
||||
|
||||
protected:
|
||||
IActor(const SessionImplPtr& sessionImpl);
|
||||
|
||||
IActor() = delete;
|
||||
IActor(IActor&) = delete;
|
||||
IActor(IActor&&) = delete;
|
||||
|
||||
// todo nth: for which members exactly the syncing is needed? for now: try for all
|
||||
std::recursive_mutex m_mutex;
|
||||
std::condition_variable_any m_condition;
|
||||
|
||||
SessionImplWeakPtr m_sessionImplWeak;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/actors/ActorInfo.hpp"
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
/// @brief an ActorInfoDb must know about those services, which are 'important',
|
||||
/// - that is: services local to the session, in/for which the actorInfoDb works.
|
||||
/// - if some service is recognized twice in the network (normally a warning), and the local session is accountable
|
||||
/// for it, the local process must die
|
||||
/// so a session creating an ActorInfoDb must provide a function for up-to-date-knowledge about the local services
|
||||
class ILocalServices {
|
||||
|
||||
public:
|
||||
virtual bool isLocalService(ActorConfiguration config) = 0;
|
||||
virtual ~ILocalServices() = default;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/utils/Logger.hpp"
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
//
|
||||
// IComponent, IObserver, ISender
|
||||
//
|
||||
|
||||
// IObserver or ISender
|
||||
class IComponent {
|
||||
|
||||
public:
|
||||
virtual std::string module() = 0;
|
||||
virtual bool isService() = 0; // caution: these method-names refer to Service and Client (Actor),
|
||||
virtual bool isObserver() = 0; // in which the Sender/Observer live, not to IService/IClient!
|
||||
|
||||
// exceptionally we have (very lightweight) convenience-methods in the interface as well
|
||||
inline bool isClient() { return !isService(); }
|
||||
inline bool isSender() { return !isObserver(); }
|
||||
|
||||
virtual ~IComponent() = default;
|
||||
};
|
||||
|
||||
class IObserver : public IComponent {
|
||||
|
||||
public:
|
||||
// IComponent
|
||||
std::string module() override = 0;
|
||||
bool isService() override = 0;
|
||||
bool isObserver() override { return true; }
|
||||
|
||||
virtual void clearCallbacks() {}
|
||||
|
||||
virtual ~IObserver() = default;
|
||||
};
|
||||
typedef std::shared_ptr<IObserver> IObserverPtr;
|
||||
|
||||
class ISender : public IComponent {
|
||||
|
||||
public:
|
||||
// IComponent
|
||||
std::string module() override = 0;
|
||||
bool isService() override = 0;
|
||||
bool isObserver() override { return false; }
|
||||
|
||||
virtual ~ISender() = default;
|
||||
};
|
||||
typedef std::shared_ptr<ISender> ISenderPtr;
|
||||
|
||||
|
||||
//
|
||||
// static_asserts to be included in every template-function
|
||||
//
|
||||
// observer w/o object - call checkTypeOfObserver<Observer>();
|
||||
template <typename Observer>
|
||||
void checkObserverType() {
|
||||
DDKIT_LOG_TRACE;
|
||||
static_assert(std::is_base_of<IObserver, Observer>::value, "Observer not derived from IObserver");
|
||||
static_assert(!std::is_same<IObserver, Observer>::value, "Observer same class as IObserver");
|
||||
}
|
||||
|
||||
// observer with object - simply call checkTypeOfObserver(observer);
|
||||
template <typename Observer>
|
||||
void checkTypeOfObserver(Observer* observer) {
|
||||
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(observer);
|
||||
checkObserverType<Observer>();
|
||||
}
|
||||
|
||||
// sender w/o object - call checkSenderType<Sender>();
|
||||
template <typename Sender>
|
||||
void checkSenderType() {
|
||||
DDKIT_LOG_TRACE;
|
||||
static_assert(std::is_base_of<ISender, Sender>::value, "Sender not derived from ISender");
|
||||
static_assert(!std::is_same<ISender, Sender>::value, "Sender same class as ISender");
|
||||
static_assert(std::is_base_of<typename Sender::TypeUser, Sender>::value, "Sender not derived from TypeUser");
|
||||
}
|
||||
|
||||
// sender with object - simply call checkTypeOfSender(sender);
|
||||
template <typename Sender>
|
||||
void checkTypeOfSender(Sender* sender) {
|
||||
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(sender);
|
||||
checkSenderType<Sender>();
|
||||
}
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/actors/ActorInfo.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class SessionImpl;
|
||||
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
|
||||
|
||||
class MonitorSession final {
|
||||
|
||||
public:
|
||||
MonitorSession(int domain);
|
||||
~MonitorSession();
|
||||
|
||||
std::vector<ServiceInfo> findServices(const std::string& module);
|
||||
std::vector<ClientInfo> findClients(const std::string& module);
|
||||
std::vector<ClientInfo> findClients(const std::string& serviceName, const std::string& module);
|
||||
|
||||
private:
|
||||
friend class SessionImpl;
|
||||
SessionImplPtr m_sessionImpl;
|
||||
|
||||
SessionImpl& sessionImpl();
|
||||
|
||||
// no copying
|
||||
MonitorSession(MonitorSession const&) = delete;
|
||||
MonitorSession(MonitorSession&&) = delete;
|
||||
void operator=(MonitorSession const&) = delete;
|
||||
void operator=(MonitorSession&&) = delete;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "SessionImpl.hpp"
|
||||
#include "ddkit/actors/IActor.hpp"
|
||||
#include "ddkit/actors/MultiplexActorThread.hpp"
|
||||
#include "ddkit/actors/SimpleActor.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class MultiplexActor : public IActor {
|
||||
|
||||
public:
|
||||
MultiplexActor(
|
||||
const SessionImplPtr& sessionImpl,
|
||||
bool isService,
|
||||
const std::string& module,
|
||||
const std::function<SimpleActorPtr(SessionImplPtr, const std::string&)>& createActor);
|
||||
~MultiplexActor();
|
||||
|
||||
bool isValid() override;
|
||||
void shutdown() override;
|
||||
|
||||
private:
|
||||
std::vector<SimpleActorPtr> m_actors;
|
||||
std::shared_ptr<MultiplexActorThread> m_threadActorMultiplex;
|
||||
|
||||
};
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/actors/SessionImpl.hpp"
|
||||
#include "ddkit/base/Thread.hpp"
|
||||
|
||||
#include "ddkit/actors/ActorInfo.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class SessionImpl;
|
||||
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
|
||||
typedef std::weak_ptr<SessionImpl> SessionImplWeakPtr;
|
||||
|
||||
class SimpleActor;
|
||||
typedef std::shared_ptr<SimpleActor> SimpleActorPtr;
|
||||
|
||||
class MultiplexActorThread : public base::Thread {
|
||||
|
||||
public:
|
||||
MultiplexActorThread(
|
||||
std::vector<SimpleActorPtr>& actors,
|
||||
const SessionImplPtr& sessionImpl,
|
||||
const std::function<SimpleActorPtr(SessionImplPtr, const std::string&)>& createActor,
|
||||
const std::string& module,
|
||||
bool isService);
|
||||
~MultiplexActorThread();
|
||||
|
||||
// Thread
|
||||
void run() override;
|
||||
void shutdown();
|
||||
|
||||
private:
|
||||
void addNewActors(std::vector<ActorInfo> const& actorsCurrent, SessionImplPtr sessionImpl);
|
||||
void removeOldActors(std::vector<ActorInfo> const& actorsCurrent);
|
||||
|
||||
SessionImplWeakPtr m_sessionImpl;
|
||||
std::function<SimpleActorPtr(SessionImplPtr, const std::string&)> m_createActor;
|
||||
std::vector<SimpleActorPtr>& m_actors;
|
||||
std::string m_module;
|
||||
bool m_isService;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/actors/ActorInfo.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class SessionImpl;
|
||||
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
|
||||
|
||||
/// @brief Typically there should be only one Session per domain.
|
||||
class Session final {
|
||||
|
||||
public:
|
||||
Session(int domain);
|
||||
~Session();
|
||||
|
||||
std::string sessionId();
|
||||
|
||||
std::vector<ServiceInfo> findServices(const std::string& module);
|
||||
std::vector<ClientInfo> findClients(const std::string& module);
|
||||
std::vector<ClientInfo> findClients(const std::string& serviceName, const std::string& module);
|
||||
|
||||
private:
|
||||
friend class SessionImpl;
|
||||
SessionImplPtr m_sessionImpl;
|
||||
|
||||
SessionImpl& sessionImpl();
|
||||
|
||||
Session() = delete;
|
||||
// no copying
|
||||
Session(Session const&) = delete;
|
||||
Session(Session&&) = delete;
|
||||
void operator=(Session const&) = delete;
|
||||
void operator=(Session&&) = delete;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/actors/Session.hpp"
|
||||
#include "ddkit/actors/MonitorSession.hpp"
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class SessionFactory {
|
||||
|
||||
public:
|
||||
/// @brief static
|
||||
static SessionFactory& instance() {
|
||||
static SessionFactory instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::shared_ptr<ddkit::actors::Session> getSession(int domain);
|
||||
std::shared_ptr<ddkit::actors::MonitorSession> getMonitorSession(int domain);
|
||||
|
||||
bool isClean() const;
|
||||
private:
|
||||
template <typename T>
|
||||
std::shared_ptr<T> get(int& domain, std::unordered_map<int, std::weak_ptr<T>>& map) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
auto it = map.find(domain);
|
||||
if (it != map.end()) {
|
||||
auto session_ptr = it->second.lock();
|
||||
if (session_ptr) {
|
||||
// Return existing session
|
||||
return session_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new session
|
||||
auto session = std::shared_ptr<T>(
|
||||
new T(domain),
|
||||
[domain, &map, this](T* s) {
|
||||
delete s;
|
||||
cleanup(domain, map);
|
||||
});
|
||||
map[domain] = session;
|
||||
return session;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void cleanup(int domain, std::unordered_map<int, std::weak_ptr<T>>& map) {
|
||||
// clean up
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
// We only erase if the weak pointer is expired, indicating no active shared_ptr exists.
|
||||
auto it = map.find(domain);
|
||||
if (it != map.end() && it->second.expired()) {
|
||||
map.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
SessionFactory() = default;
|
||||
SessionFactory(const SessionFactory&) = delete;
|
||||
SessionFactory& operator=(const SessionFactory&) = delete;
|
||||
|
||||
std::unordered_map<int, std::weak_ptr<ddkit::actors::Session>> m_sessions;
|
||||
std::unordered_map<int, std::weak_ptr<ddkit::actors::MonitorSession>> m_monitorSessions;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/IConfig.hpp"
|
||||
#include "ddkit/access/Dispatcher.hpp"
|
||||
#include "ddkit/access/ICleanup.hpp"
|
||||
#include "ddkit/actors/ActorInfoDbCaretaker.hpp"
|
||||
#include "ddkit/actors/ActorInfoDb.hpp"
|
||||
#include "ddkit/actors/ActorInfoWriter.hpp"
|
||||
#include "ddkit/actors/Session.hpp"
|
||||
#include "ddkit/actors/MonitorSession.hpp"
|
||||
#include "ddkit/actors/ILocalServices.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class IActor;
|
||||
typedef std::shared_ptr<IActor> ActorPtr;
|
||||
typedef std::weak_ptr<IActor> ActorPtrWeak;
|
||||
|
||||
class SimpleActor;
|
||||
typedef std::shared_ptr<SimpleActor> SimpleActorPtr;
|
||||
|
||||
class MultiplexActor;
|
||||
typedef std::shared_ptr<MultiplexActor> MultiplexActorPtr;
|
||||
|
||||
class SessionImpl final : public std::enable_shared_from_this<SessionImpl>,
|
||||
public access::ICleanup,
|
||||
public ILocalServices {
|
||||
public:
|
||||
SessionImpl(base::IConfig& config, int domain, bool isMonitor);
|
||||
~SessionImpl();
|
||||
|
||||
void init();
|
||||
|
||||
// create a new SessionImpl (even if another Session with same domain exists already)
|
||||
static SessionImplPtr create(int domain, bool isMonitor);
|
||||
|
||||
// needed from generated createSome (api) (friend access on Session)
|
||||
static SessionImplPtr getSessionImpl(Session& session);
|
||||
static SessionImplPtr getSessionImpl(MonitorSession& session);
|
||||
|
||||
// getter
|
||||
int domain();
|
||||
access::Participant& participant();
|
||||
std::string sessionId();
|
||||
std::shared_ptr<access::Dispatcher> dispatcher();
|
||||
ddkit_intern::Session sessionInfo();
|
||||
bool isMonitor();
|
||||
|
||||
bool isCheckMostDerivedClassType();
|
||||
int timeoutSecsWaitUntilConnected();
|
||||
|
||||
// key2actor
|
||||
bool hasActor(const std::string& serviceName, bool isService, const std::string& module);
|
||||
SimpleActorPtr findActor(const std::string& serviceName, bool isService, const std::string& module);
|
||||
SimpleActorPtr createActor(const std::string& serviceName, bool isService, const std::string& module);
|
||||
MultiplexActorPtr createActorMultiplex(
|
||||
bool isService,
|
||||
const std::string& module,
|
||||
const std::function<SimpleActorPtr(SessionImplPtr, const std::string&)>& createActor);
|
||||
SimpleActorPtr createOrFindActor(const std::string& serviceName, bool isService, const std::string& module);
|
||||
|
||||
// ICleanup
|
||||
void cleanup() override; // called from dispatcher regularly for removing non-referenced actors
|
||||
bool isShutdownRequested() override;
|
||||
|
||||
// ids for Actors
|
||||
int nextSequenceId() { return m_nextSequenceId++; }
|
||||
|
||||
// ActorInfo (sending to dds - actor-specific-part)
|
||||
void publishActorInfo(ddkit_intern::ActorInfo actorInfo);
|
||||
void disposeActorInfo(ddkit_intern::ActorInfo actorInfo);
|
||||
|
||||
// ActorInfo (using dds-meta-info)
|
||||
std::vector<ServiceInfo> findRunningServices(const std::string& module);
|
||||
std::vector<ServiceInfo> findRunningServices(const std::string& serviceName, const std::string& module); // max 1
|
||||
std::vector<ClientInfo> findRunningClients(const std::string& module);
|
||||
std::vector<ClientInfo> findRunningClients(const std::string& serviceName, const std::string& module);
|
||||
|
||||
// ILocalServices
|
||||
bool isLocalService(ActorConfiguration config); // called from ActorInfoDb
|
||||
|
||||
std::string clientActorId2clientName(const std::string& clientActorId); // access meta-infos for callbackInfo
|
||||
|
||||
void shutdownActors();
|
||||
void shutdownMultiplexActors();
|
||||
|
||||
void requestShutdown();
|
||||
void requestCleanup();
|
||||
|
||||
void removeMultiplexActor(std::shared_ptr<IActor> multiplexActor);
|
||||
|
||||
private:
|
||||
std::recursive_mutex m_mutex;
|
||||
std::condition_variable_any m_condition;
|
||||
|
||||
bool m_isMonitor;
|
||||
int m_domain;
|
||||
access::Participant m_participant;
|
||||
std::string m_sessionId; // identifies this session globally!
|
||||
int m_nextSequenceId; // identifiying-addition for Actors
|
||||
|
||||
std::shared_ptr<access::Dispatcher> m_dispatcher;
|
||||
|
||||
std::vector<SimpleActorPtr> m_simpleActors; // 'normal'-actors (including internal actors of multiplex)
|
||||
std::vector<MultiplexActorPtr> m_multiplexActors; // 'multiplex'-actors (have no serviceName for key, thus extra)
|
||||
|
||||
// ActorInfo (sending to dds - session-specific-part)
|
||||
ddkit_intern::Process m_process;
|
||||
ddkit_intern::Session m_sessionInfo;
|
||||
ActorInfoWriter m_actorInfoWriter;
|
||||
std::vector<ActorConfiguration> m_localServices; // log which services accountable for
|
||||
|
||||
// ActorInfo (reading from dds - monitor-intern-part)
|
||||
ActorInfoDb m_actorInfoDb;
|
||||
ActorInfoDbCaretaker m_ActorInfoDbCaretaker;
|
||||
|
||||
bool m_isCheckMostDerivedClassType;
|
||||
int m_timeoutSecsWaitUntilConnected;
|
||||
|
||||
std::atomic<bool> m_shutdownRequested;
|
||||
|
||||
// no copying
|
||||
SessionImpl(SessionImpl const&) = delete;
|
||||
SessionImpl(SessionImpl&&) = delete;
|
||||
void operator=(SessionImpl const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/ThreadInline.hpp"
|
||||
#include "ddkit/access/ConfigLoaderDds.hpp"
|
||||
#include "ddkit/actors/CallbackInfo.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class SessionImpl;
|
||||
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
|
||||
typedef std::weak_ptr<SessionImpl> SessionImplWeakPtr;
|
||||
|
||||
class SessionManager {
|
||||
|
||||
public:
|
||||
static SessionManager& instance();
|
||||
|
||||
SessionImplPtr createSessionImpl(int domain, bool isMonitor); // called from SessionImpl
|
||||
|
||||
SessionImplPtr findSession(const std::string& sessionId); // called from BackwardManager
|
||||
|
||||
void removeExpiredSessions(); // called from BackwardManager, MonitorSession, Session
|
||||
void removeSession(const std::string& sessionId);
|
||||
|
||||
void setCallbackInfo(const CallbackInfo& callbackInfo); // called from ActorImpl
|
||||
void resetCallbackInfo(); // called from ActorImpl, generated Code
|
||||
CallbackInfo callbackInfo(); // called from ActorImpl, BackwardManager, CallbackInfo, generated Code
|
||||
|
||||
bool isClean() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<access::ConfigLoaderDds> m_configLoaderDds;
|
||||
|
||||
std::mutex m_sessionMutex;
|
||||
std::map<std::string, SessionImplWeakPtr> m_sessionId2sessionImpl; // holding map for sessions
|
||||
|
||||
std::mutex m_callbackMutex;
|
||||
std::map<std::string, CallbackInfo> m_threadId2callbackInfo; // per thread (typically one entry - while callback)
|
||||
|
||||
SessionManager();
|
||||
~SessionManager();
|
||||
|
||||
bool hasSession(const std::string& sessionId);
|
||||
bool hasSessions();
|
||||
|
||||
// no copying
|
||||
SessionManager(SessionManager const&) = delete;
|
||||
SessionManager(SessionManager&&) = delete;
|
||||
void operator=(SessionManager const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/utils/assert.hpp"
|
||||
#include "ddkit/access/TopicPoolRead.hpp"
|
||||
#include "ddkit/access/TopicPoolWrite.hpp"
|
||||
#include "ddkit/actors/CallbackInfo.hpp"
|
||||
#include "ddkit/actors/IActor.hpp"
|
||||
#include "ddkit/actors/SessionImpl.hpp"
|
||||
#include "ddkit/idls/ActorInfo.hpp"
|
||||
#include "ddkit/actors/Key.hpp"
|
||||
#include "ddkit/utils/CallbackWrapper.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace actors {
|
||||
|
||||
class SimpleActor : public IActor {
|
||||
|
||||
public:
|
||||
SimpleActor(const SessionImplPtr& sessionImpl,
|
||||
const std::string& serviceName,
|
||||
bool isService,
|
||||
const std::string& module);
|
||||
|
||||
~SimpleActor();
|
||||
|
||||
bool hasObserver();
|
||||
bool hasSender();
|
||||
|
||||
access::TopicPoolRead& topicPoolRead();
|
||||
access::TopicPoolWrite& topicPoolWrite();
|
||||
|
||||
std::string moduleName() const;
|
||||
bool isService() const;
|
||||
int domain() const;
|
||||
std::string serviceName() const;
|
||||
ActorConfiguration config() const;
|
||||
|
||||
std::string actorId() const;
|
||||
|
||||
bool operator==(const SimpleActor& other) const;
|
||||
|
||||
void setClientName(const std::string& clientName);
|
||||
|
||||
void waitUntilConnected();
|
||||
|
||||
void addConnectCheck(access::IConnectCheckPtr connectCheck);
|
||||
|
||||
// template-class-parameters Observer and Sender in the following methods must be the 'reader-class'
|
||||
// respectively the 'writer-class' of one of the rmodel-modules. They are called Observer and Sender
|
||||
// in the corresponding namespace and inherit the interface IObserver/ISender. They define a typedef TypeUser
|
||||
// to refer to the API-Interface-Type IClient/IService. Sender also inherits its TypeUser-Type
|
||||
|
||||
/// @brief - needed for access from generated Service/Client, to call write-stuff
|
||||
template <typename Sender>
|
||||
ISenderPtr sender() {
|
||||
DDKIT_LOG_TRACE;
|
||||
checkSenderType<Sender>();
|
||||
|
||||
if (hasSender()) {
|
||||
std::shared_ptr<Sender> sender = std::dynamic_pointer_cast<Sender>(m_sender); // Sender inherits ISender
|
||||
if (sender) {
|
||||
checkTypeOfSender(sender.get());
|
||||
return sender;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ISenderPtr sender() {
|
||||
return m_sender;
|
||||
}
|
||||
|
||||
IObserverPtr observer() {
|
||||
return m_observer;
|
||||
}
|
||||
|
||||
bool hasSession() {
|
||||
return !m_sessionImplWeak.expired();
|
||||
}
|
||||
|
||||
template <typename Observer>
|
||||
IObserverPtr createObserver(typename Observer::TypeUser& callbacks, const std::vector<std::string>& methods) {
|
||||
|
||||
ddkit::log::info() << "Create observer";
|
||||
|
||||
SessionImplPtr sessionImpl = m_sessionImplWeak.lock();
|
||||
if (!sessionImpl) {
|
||||
throw std::runtime_error("Failure locking std::weak_ptr<SessionImpl> in ActorImpl");
|
||||
}
|
||||
|
||||
checkObserverType<Observer>();
|
||||
|
||||
typename Observer::TypeUser* userCallback = &callbacks; // (keep * inside ... else problems with capturing)
|
||||
|
||||
// insert observer
|
||||
DDKIT_THROW_ON_FALSE_INFO(
|
||||
!hasObserver(),
|
||||
"Inserting an observer to an actor already containing one."
|
||||
"Called ObsFactory::add() twice? (same serviceName + domain)");
|
||||
m_observer = std::make_shared<Observer>(*this, m_topicPoolRead, methods, userCallback);
|
||||
DDKIT_THROW_ON_FALSE_INFO(hasObserver(), "creation of observer failed");
|
||||
|
||||
// update actorInfo
|
||||
if (m_actorInfo.isReading()) {
|
||||
ddkit::log::warn() << "SimpleActor::createObserver: " << "actor is already reading";
|
||||
}
|
||||
m_actorInfo.isReading() = true;
|
||||
m_actorInfo.openReaders() = methods; // only vectors on dds
|
||||
|
||||
sessionImpl->publishActorInfo(m_actorInfo);
|
||||
|
||||
return m_observer;
|
||||
}
|
||||
|
||||
template <typename Observer>
|
||||
IObserverPtr createObserver(std::map<std::string, std::vector<ddkit::callback::Base*>> callbacks, const std::vector<std::string> methods) {
|
||||
|
||||
ddkit::log::info() << "Create observer";
|
||||
|
||||
SessionImplPtr sessionImpl = m_sessionImplWeak.lock();
|
||||
if (!sessionImpl) {
|
||||
throw std::runtime_error("Failure locking std::weak_ptr<SessionImpl> in ActorImpl");
|
||||
}
|
||||
|
||||
checkObserverType<Observer>();
|
||||
|
||||
// insert observer
|
||||
DDKIT_THROW_ON_FALSE_INFO(
|
||||
!hasObserver(),
|
||||
"Inserting an observer to an actor already containing one."
|
||||
"Called ObsFactory::add() twice? (same serviceName + domain)");
|
||||
m_observer = std::make_shared<Observer>(*this, m_topicPoolRead, methods, callbacks);
|
||||
DDKIT_THROW_ON_FALSE_INFO(hasObserver(), "creation of observer failed");
|
||||
|
||||
// update actorInfo
|
||||
if(m_actorInfo.isReading()) {
|
||||
ddkit::log::warn() << "SimpleActor::createObserver: actor is already reading";
|
||||
}
|
||||
m_actorInfo.isReading() = true;
|
||||
m_actorInfo.openReaders() = methods; // only vectors on dds
|
||||
|
||||
sessionImpl->publishActorInfo(m_actorInfo);
|
||||
|
||||
return m_observer;
|
||||
}
|
||||
|
||||
template <typename Sender>
|
||||
ISenderPtr createSender(const std::vector<std::string>& methods) {
|
||||
|
||||
ddkit::log::info() << "Create sender";
|
||||
|
||||
SessionImplPtr sessionImpl = m_sessionImplWeak.lock();
|
||||
if (!sessionImpl) {
|
||||
throw std::runtime_error("Failure locking std::weak_ptr<SessionImpl> in ActorImpl");
|
||||
}
|
||||
|
||||
checkSenderType<Sender>();
|
||||
|
||||
DDKIT_THROW_ON_FALSE_INFO(
|
||||
!hasSender(),
|
||||
"Inserting a sender to an actor already containing one. "
|
||||
"Called Factory::create() twice? (same serviceName + domain)");
|
||||
m_sender = std::make_shared<Sender>(*this, m_topicPoolWrite);
|
||||
Sender* sender2 = dynamic_cast<Sender*>(m_sender.get());
|
||||
checkTypeOfSender(sender2);
|
||||
DDKIT_THROW_ON_FALSE(sender2);
|
||||
DDKIT_THROW_ON_FALSE(hasSender());
|
||||
|
||||
// update actorInfo
|
||||
if (m_actorInfo.isWriting()) {
|
||||
ddkit::log::warn() << "SimpleActor::createSender: " << "actor is already writing";
|
||||
}
|
||||
m_actorInfo.isWriting() = true;
|
||||
m_actorInfo.openWriters() = methods; // only vectors on dds
|
||||
sessionImpl->publishActorInfo(m_actorInfo);
|
||||
return m_sender;
|
||||
}
|
||||
|
||||
void discardSender();
|
||||
void discardObserver();
|
||||
bool isValid() override;
|
||||
void shutdown() override;
|
||||
bool shutdownRequested();
|
||||
|
||||
CallbackInfo callbackInfoBase();
|
||||
CallbackInfo callbackInfo();
|
||||
void setCallbackInfo(CallbackInfo callbackInfo);
|
||||
void resetCallbackInfo();
|
||||
|
||||
private:
|
||||
ddkit_intern::ActorInfo m_actorInfo;
|
||||
|
||||
access::IQosStrategyPtr m_qosStrategy;
|
||||
access::ITopicStrategyPtr m_topicStrategy;
|
||||
access::TopicPoolRead m_topicPoolRead;
|
||||
access::TopicPoolWrite m_topicPoolWrite;
|
||||
std::vector<access::IConnectCheckPtr> m_connectCheckSet;
|
||||
|
||||
IObserverPtr m_observer; // or nullptr, if none
|
||||
ISenderPtr m_sender; // or nullptr, if none
|
||||
|
||||
CallbackInfo m_callbackInfoBase;
|
||||
|
||||
std::atomic<bool> m_shutdownRequested;
|
||||
};
|
||||
|
||||
} // namespace actors
|
||||
} // namespace ddkit
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/IConfig.hpp"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace ddkit {
|
||||
namespace base {
|
||||
|
||||
class Config : public IConfig {
|
||||
|
||||
public:
|
||||
// as both ctor-params are strings, make constructor-calls disambiguous:
|
||||
struct Text {
|
||||
explicit Text(const std::string& text)
|
||||
: m_text(text) {}
|
||||
std::string m_text;
|
||||
};
|
||||
struct Filename {
|
||||
explicit Filename(const std::string& filename)
|
||||
: m_filename(filename) {}
|
||||
std::string m_filename;
|
||||
};
|
||||
|
||||
class FileNotFound : public std::runtime_error {
|
||||
public:
|
||||
FileNotFound(const std::string& filename) : std::runtime_error("could not open file \"" + filename + "\""){}
|
||||
};
|
||||
|
||||
Config();
|
||||
Config(const nlohmann::json&);
|
||||
Config(const Text& text); // call: Config config((Config::Text("{ abc = 17 }")));
|
||||
Config(const Filename& filename);
|
||||
Config(const Config&);
|
||||
void operator=(Config const&);
|
||||
|
||||
// IConfig
|
||||
bool hasKey(const std::string& key) const override;
|
||||
std::string getStringValue(const std::string& key) const override;
|
||||
int getIntValue(const std::string& key) const override;
|
||||
int64_t getInt64Value(const std::string& key) const override;
|
||||
bool getBoolValue(const std::string& key) const override;
|
||||
|
||||
// todo array into IConfig?
|
||||
int getArraySize(const std::string& key) const;
|
||||
|
||||
// no template-getter any more (error-prone in conjunction with type-casts)
|
||||
// no default-getter any more (error-prone in conjunction with typos)
|
||||
// no optional-getter any more (too much tmsif-API-logic, might be useful in other place)
|
||||
|
||||
bool isInt64Value(const std::string& key) const; // int or int64
|
||||
bool isBoolValue(const std::string& key) const;
|
||||
bool isStringValue(const std::string& key) const;
|
||||
bool isArrayValue(const std::string& key) const;
|
||||
bool isListValue(const std::string& key) const; // has subKeys
|
||||
|
||||
std::vector<std::string> getSubKeys(const std::string& key) const;
|
||||
|
||||
Config getSubConfig(const std::string& key) const;
|
||||
|
||||
operator std::string() const;
|
||||
|
||||
private:
|
||||
|
||||
static nlohmann::json::json_pointer keyToJsonPointer(const std::string& key);
|
||||
nlohmann::json getValue(const std::string& key) const;
|
||||
bool hasKey(const nlohmann::json&, const std::string& key) const;
|
||||
bool hasKey(const nlohmann::json& jsonObj, const nlohmann::json::json_pointer& jsonPtr) const;
|
||||
|
||||
nlohmann::json m_json;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/Config.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace access {
|
||||
class ConfigLoaderDds;
|
||||
}
|
||||
|
||||
namespace base {
|
||||
|
||||
/// @brief class "ConfigLoader"
|
||||
/// - it holds the config-File of the application and sets up the logger
|
||||
/// Hold by ConfigLoaderDds
|
||||
class ConfigLoader final {
|
||||
|
||||
public:
|
||||
|
||||
ConfigLoader(const std::string& configFile);
|
||||
~ConfigLoader();
|
||||
|
||||
Config& config() { return m_config; }
|
||||
|
||||
private:
|
||||
|
||||
std::string m_programName;
|
||||
Config m_config;
|
||||
|
||||
// no copying
|
||||
ConfigLoader(ConfigLoader const&) = delete;
|
||||
ConfigLoader(ConfigLoader&&) = delete;
|
||||
void operator=(ConfigLoader const&) = delete;
|
||||
void operator=(ConfigLoader&&) = delete;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
} // namespace ddkit
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/Config.hpp"
|
||||
#include "ddkit/base/IConfigWrite.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
namespace ddkit {
|
||||
namespace base {
|
||||
|
||||
/// @brief ConfigRw (ReadWrite) is constructed with a normal Config (read, from a file) and enables overwrite of keys as well.
|
||||
/// additionally it may be checked, which keys are allowed
|
||||
class ConfigRw : public IConfig,
|
||||
public IConfigWrite {
|
||||
|
||||
public:
|
||||
ConfigRw();
|
||||
ConfigRw(Config& config);
|
||||
ConfigRw(const ConfigRw&);
|
||||
void operator=(const ConfigRw&);
|
||||
|
||||
// IConfig
|
||||
bool hasKey(const std::string& key) const override;
|
||||
std::string getStringValue(const std::string& key) const override;
|
||||
int getIntValue(const std::string& key) const override;
|
||||
int64_t getInt64Value(const std::string& key) const override;
|
||||
bool getBoolValue(const std::string& key) const override;
|
||||
|
||||
// IConfigWrite
|
||||
void setStringValue(const std::string& key, const std::string& value) override;
|
||||
void setIntValue(const std::string& key, int value) override;
|
||||
void setInt64Value(const std::string& key, int64_t value) override;
|
||||
void setBoolValue(const std::string& key, bool value) override;
|
||||
|
||||
// activate checks. i.e. foo.bar -> section foo and key bar
|
||||
void registerKnownConfigKey(
|
||||
const std::string& section,
|
||||
const std::string& key);
|
||||
|
||||
void checkConfig() const; // check in file (only for corresponding top-level)
|
||||
|
||||
private:
|
||||
// the 'real' BaseConfig (ConfigFile from ConfigLoader)
|
||||
Config m_config;
|
||||
|
||||
// the overwritten key-values
|
||||
std::vector<std::string> m_keys;
|
||||
std::map<std::string, std::string> m_key2stringValue;
|
||||
std::map<std::string, int> m_key2intValue;
|
||||
std::map<std::string, int64_t> m_key2int64Value;
|
||||
std::map<std::string, bool> m_key2boolValue;
|
||||
|
||||
// keys allowed
|
||||
std::map<std::string, std::vector<std::string>> m_knownKeysMap;
|
||||
void checkKey(const std::string& key) const;
|
||||
void checkConfig(const std::string& prefix) const; // check in file
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
} // namespace ddkit
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ddkit {
|
||||
namespace base {
|
||||
|
||||
class IConfig {
|
||||
public:
|
||||
virtual ~IConfig() = default;
|
||||
|
||||
virtual bool hasKey(const std::string& key) const = 0;
|
||||
|
||||
// getters which throw if the key does not exist
|
||||
virtual std::string getStringValue(const std::string& key) const = 0;
|
||||
virtual int getIntValue(const std::string& key) const = 0;
|
||||
virtual int64_t getInt64Value(const std::string& key) const = 0;
|
||||
virtual bool getBoolValue(const std::string& key) const = 0;
|
||||
|
||||
// getters which return a default if the key does not exist
|
||||
std::string getStringValue(const std::string& key, const std::string& defaultValue) const {
|
||||
if (hasKey(key)) return getStringValue(key);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int getIntValue(const std::string& key, int defaultValue) const {
|
||||
if (hasKey(key)) return getIntValue(key);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int64_t getInt64Value(const std::string& key, int64_t defaultValue) const {
|
||||
if (hasKey(key)) return getInt64Value(key);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
bool getBoolValue(const std::string& key, bool defaultValue) const {
|
||||
if (hasKey(key)) return getBoolValue(key);
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ddkit {
|
||||
namespace base {
|
||||
|
||||
class IConfigWrite {
|
||||
public:
|
||||
virtual void setStringValue(const std::string& key, const std::string& value) = 0;
|
||||
virtual void setIntValue(const std::string& key, int value) = 0;
|
||||
virtual void setInt64Value(const std::string& key, int64_t value) = 0;
|
||||
virtual void setBoolValue(const std::string& key, bool value) = 0;
|
||||
virtual ~IConfigWrite() = default;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
} // namespace ddkit
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
|
||||
namespace ddkit {
|
||||
namespace base {
|
||||
|
||||
/// @brief exception class for serialization errors
|
||||
/// emitted for any errors encouted during parsing
|
||||
/// for details refere to what() message
|
||||
class SerializationError : public std::exception {
|
||||
public:
|
||||
SerializationError(const std::string& message) : m_message(message) {
|
||||
}
|
||||
|
||||
virtual const char* what() const noexcept override {
|
||||
return m_message.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string m_message;
|
||||
};
|
||||
|
||||
/// @brief simple serialization like stringstream
|
||||
/// - serialized format is a string, readable
|
||||
/// - may be deserialized with same operator-calling-pattern of types on another instance
|
||||
/// mixed calls to serializing and deserializing on same object -> undefined behaviour
|
||||
class Serialization {
|
||||
std::ostringstream m_os;
|
||||
std::istringstream m_is;
|
||||
// bool m_isSerializing; // todo nth check?
|
||||
// bool m_isDeserializing;
|
||||
public:
|
||||
// serializing
|
||||
Serialization();
|
||||
std::string str();
|
||||
|
||||
// deserializing
|
||||
explicit Serialization(const std::string& text);
|
||||
bool isEnd();
|
||||
|
||||
|
||||
// bool
|
||||
Serialization& operator<<(bool rhs);
|
||||
Serialization& operator>>(bool& rhs);
|
||||
|
||||
// int char
|
||||
Serialization& operator<<(uint8_t rhs);
|
||||
Serialization& operator>>(uint8_t& rhs);
|
||||
|
||||
Serialization& operator<<(uint16_t rhs);
|
||||
Serialization& operator>>(uint16_t& rhs);
|
||||
|
||||
Serialization& operator<<(uint32_t rhs);
|
||||
Serialization& operator>>(uint32_t& rhs);
|
||||
|
||||
Serialization& operator<<(uint64_t rhs);
|
||||
Serialization& operator>>(uint64_t& rhs);
|
||||
|
||||
Serialization& operator<<(int8_t rhs);
|
||||
Serialization& operator>>(int8_t& rhs);
|
||||
|
||||
Serialization& operator<<(int16_t rhs);
|
||||
Serialization& operator>>(int16_t& rhs);
|
||||
|
||||
Serialization& operator<<(int32_t rhs);
|
||||
Serialization& operator>>(int32_t& rhs);
|
||||
|
||||
Serialization& operator<<(int64_t rhs);
|
||||
Serialization& operator>>(int64_t& rhs);
|
||||
|
||||
Serialization& operator<<(char rhs);
|
||||
Serialization& operator>>(char& rhs);
|
||||
|
||||
// float double
|
||||
Serialization& operator<<(double rhs);
|
||||
Serialization& operator>>(double& rhs);
|
||||
|
||||
Serialization& operator<<(float rhs);
|
||||
Serialization& operator>>(float& rhs);
|
||||
|
||||
// string
|
||||
Serialization& operator<<(const std::string& rhs);
|
||||
Serialization& operator>>(std::string& rhs);
|
||||
|
||||
// vector
|
||||
template <typename T>
|
||||
Serialization& operator<<(std::vector<T> const& rhs) {
|
||||
*this << rhs.size();
|
||||
for (T const& t : rhs) {
|
||||
*this << t;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T>
|
||||
Serialization& operator>>(std::vector<T>& rhs) {
|
||||
rhs.clear();
|
||||
|
||||
int size = getSize();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
T t;
|
||||
*this >> t;
|
||||
rhs.push_back(t);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string readBytes(int size);
|
||||
void expectAndSkipComma();
|
||||
int getSize();
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
} // namespace ddkit
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
namespace ddkit {
|
||||
namespace base {
|
||||
|
||||
/// @brief wrapper for std::thread, including
|
||||
/// - clean synchronized start/stop/stopCommanded-mechanism
|
||||
/// - tracing with threadname, exception-logging on outermost level
|
||||
class Thread {
|
||||
|
||||
public:
|
||||
/// @param name 6-char-thread-name
|
||||
Thread(const std::string& name);
|
||||
virtual ~Thread();
|
||||
|
||||
void start();
|
||||
// void stop(); // call stopAndJoin instead
|
||||
void stopAndJoin();
|
||||
|
||||
bool isActive() const;
|
||||
void waitForStopCommanded();
|
||||
bool stopCommanded() const;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::unique_ptr<std::thread> m_thread;
|
||||
bool m_threadExecutionActive;
|
||||
|
||||
std::mutex m_mutexStart;
|
||||
std::condition_variable m_threadStarted;
|
||||
bool m_hasStarted;
|
||||
|
||||
std::mutex m_mutexStop;
|
||||
std::condition_variable m_threadStopped;
|
||||
bool m_stopCommanded;
|
||||
|
||||
virtual void run();
|
||||
virtual void onStop();
|
||||
|
||||
void startUp();
|
||||
|
||||
void waitForStarted();
|
||||
virtual void waitForReadyIf();
|
||||
|
||||
// no copying
|
||||
Thread(Thread const&) = delete;
|
||||
Thread(Thread&&) = delete;
|
||||
void operator=(Thread const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/Thread.hpp"
|
||||
#include <functional>
|
||||
|
||||
namespace ddkit {
|
||||
namespace base {
|
||||
|
||||
class ThreadInline final : public Thread {
|
||||
public:
|
||||
ThreadInline(const std::string& name, const std::function<void()>& function);
|
||||
~ThreadInline() override;
|
||||
|
||||
private:
|
||||
std::function<void()> m_function;
|
||||
|
||||
void run() override;
|
||||
|
||||
ThreadInline(ThreadInline const&) = delete;
|
||||
void operator=(ThreadInline const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/base/Thread.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace base {
|
||||
|
||||
/// @brief ThreadSync may be used instead of Thread, if 'start()' shall be 'synchronous', that is
|
||||
/// - the os-thread, which is calling 'start()' on this obj, is blocked until
|
||||
/// - the new os-thread is created and the intern-thread-function was started
|
||||
/// - the overridden 'run()'-method (Derivee from ThreadSync) is started
|
||||
/// - the implementation of that 'run'-method decided to call 'ready()'
|
||||
/// - (as first command, or after some initialization-steps, which went for some reason not in ctor, but run)
|
||||
class ThreadSync : public Thread {
|
||||
|
||||
public:
|
||||
ThreadSync(const std::string& name);
|
||||
virtual ~ThreadSync() override;
|
||||
|
||||
protected:
|
||||
void ready();
|
||||
|
||||
private:
|
||||
std::recursive_mutex m_mutex;
|
||||
std::condition_variable_any m_condition;
|
||||
|
||||
bool m_isReady; // did the thread call "ready()" for signaling "fully" starting up?
|
||||
|
||||
void waitForReadyIf() override; // called by Thread
|
||||
|
||||
ThreadSync(ThreadSync const&) = delete;
|
||||
void operator=(ThreadSync const&) = delete;
|
||||
};
|
||||
|
||||
|
||||
} // namespace base
|
||||
} // namespace ddkit
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#define DDKIT_VERSION_MAJOR 3
|
||||
#define DDKIT_VERSION_MINOR 9
|
||||
#define DDKIT_VERSION_PATCH 0
|
||||
|
||||
#define DDKIT_VERSION_ATLEAST(major, minor, patch) ((major >= DDKIT_VERSION_MAJOR) && (minor >= DDKIT_VERSION_MINOR) && (patch >= DDKIT_VERSION_PATCH))
|
||||
|
||||
namespace ddkit {
|
||||
namespace build_info {
|
||||
namespace version {
|
||||
const std::string string = "3.9.0";
|
||||
|
||||
const int major = 3;
|
||||
const int minor = 9;
|
||||
const int patch = 0;
|
||||
}
|
||||
|
||||
namespace conan {
|
||||
const std::string channel = "stable";
|
||||
const std::string package = "98937235a8ae97010a6498036572bf0d26e6de10";
|
||||
}
|
||||
|
||||
namespace dds {
|
||||
const std::string vendor = "cyclone";
|
||||
const std::string vendor_version = "20250204-conan-recipe-v3";
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// GENERATED CODE - do not edit (Generated by ddkit/genVendorWrap)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// this file (ActorInfo.hpp) wraps the corresponding vendor-generated C++-Header.
|
||||
// include it via -> #include "ddkit/idls/ActorInfo.hpp"
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ddkit/utils/Logger.hpp>
|
||||
#include <ddkit/utils/string.hpp>
|
||||
#include <ddkit/utils/container.hpp>
|
||||
|
||||
|
||||
// dds-vendor-specific header
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
#ifdef DDS_VENDOR_OPENSPLICE
|
||||
#include <ddkit/idls/vendor/ActorInfo_DCPS.hpp>
|
||||
#else
|
||||
#include <ddkit/idls/vendor/ActorInfo.hpp>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
// define ostream-operators (<<) for vendors not defining them theirselves
|
||||
#if defined(DDS_VENDOR_OPENSPLICE)
|
||||
namespace ddkit_intern {
|
||||
using ::ddkit::utils::container::operator<<;
|
||||
inline std::ostream& operator<<(std::ostream& s, Process const& rhs)
|
||||
{
|
||||
return s << "["
|
||||
<< "processId: " << (rhs.processId())
|
||||
<< ", hostName: " << (rhs.hostName())
|
||||
<< ", procName: " << (rhs.procName())
|
||||
<< "]";
|
||||
}
|
||||
|
||||
using ::ddkit::utils::container::operator<<;
|
||||
inline std::ostream& operator<<(std::ostream& s, Session const& rhs)
|
||||
{
|
||||
return s << "["
|
||||
<< "sessionId: " << (rhs.sessionId())
|
||||
<< ", process: " << (rhs.process())
|
||||
<< "]";
|
||||
}
|
||||
|
||||
using ::ddkit::utils::container::operator<<;
|
||||
inline std::ostream& operator<<(std::ostream& s, ActorInfo const& rhs)
|
||||
{
|
||||
return s << "["
|
||||
<< "actorId: " << (rhs.actorId())
|
||||
<< ", session: " << (rhs.session())
|
||||
<< ", sequenceId: " << (rhs.sequenceId())
|
||||
<< ", serviceName: " << (rhs.serviceName())
|
||||
<< ", domain: " << static_cast<int16_t>(rhs.domain())
|
||||
<< ", isService: " << (rhs.isService())
|
||||
<< ", moduleName: " << (rhs.moduleName())
|
||||
<< ", isReading: " << (rhs.isReading())
|
||||
<< ", openReaders: " << (rhs.openReaders())
|
||||
<< ", isWriting: " << (rhs.isWriting())
|
||||
<< ", openWriters: " << (rhs.openWriters())
|
||||
<< ", clientName: " << (rhs.clientName())
|
||||
<< "]";
|
||||
}
|
||||
|
||||
} // ddkit_intern
|
||||
|
||||
|
||||
|
||||
#endif // defined(DDS_VENDOR_OPENSPLICE)
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// GENERATED CODE - do not edit (Generated by ddkit/genVendorWrap)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// this file (TestTopic.hpp) wraps the corresponding vendor-generated C++-Header.
|
||||
// include it via -> #include "ddkit/idls/TestTopic.hpp"
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ddkit/utils/Logger.hpp>
|
||||
#include <ddkit/utils/string.hpp>
|
||||
#include <ddkit/utils/container.hpp>
|
||||
|
||||
|
||||
// dds-vendor-specific header
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
#ifdef DDS_VENDOR_OPENSPLICE
|
||||
#include <ddkit/idls/vendor/TestTopic_DCPS.hpp>
|
||||
#else
|
||||
#include <ddkit/idls/vendor/TestTopic.hpp>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
// define ostream-operators (<<) for vendors not defining them theirselves
|
||||
#if defined(DDS_VENDOR_OPENSPLICE)
|
||||
namespace ddkit_intern {
|
||||
using ::ddkit::utils::container::operator<<;
|
||||
inline std::ostream& operator<<(std::ostream& s, TestTopic const& rhs)
|
||||
{
|
||||
return s << "["
|
||||
<< "id: " << (rhs.id())
|
||||
<< ", val: " << (rhs.val())
|
||||
<< "]";
|
||||
}
|
||||
|
||||
using ::ddkit::utils::container::operator<<;
|
||||
inline std::ostream& operator<<(std::ostream& s, TestTopic2 const& rhs)
|
||||
{
|
||||
return s << "["
|
||||
<< "id: " << (rhs.id())
|
||||
<< ", val: " << (rhs.val())
|
||||
<< "]";
|
||||
}
|
||||
|
||||
} // ddkit_intern
|
||||
|
||||
|
||||
|
||||
#endif // defined(DDS_VENDOR_OPENSPLICE)
|
||||
|
||||
+1259
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,548 @@
|
||||
/****************************************************************
|
||||
|
||||
Generated by Eclipse Cyclone DDS IDL to CXX Translator
|
||||
File name: /data/jenkins/workspace/workspace/ddkit_release_v3-9-x/cnn_l_0/.conan/data/ddkit/3.9.0/jenkins/stable/build/98937235a8ae97010a6498036572bf0d26e6de10/src/ddkit/idls/TestTopic.idl
|
||||
Source: TestTopic.hpp
|
||||
Cyclone DDS: v0.11.0
|
||||
|
||||
*****************************************************************/
|
||||
#ifndef DDSCXX_TESTTOPIC_HPP_5D6BACE0D1D9ADC0287C638316554B9B
|
||||
#define DDSCXX_TESTTOPIC_HPP_5D6BACE0D1D9ADC0287C638316554B9B
|
||||
|
||||
#include <utility>
|
||||
#include <ostream>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ddkit_intern
|
||||
{
|
||||
class TestTopic
|
||||
{
|
||||
private:
|
||||
int32_t id_ = 0;
|
||||
int32_t val_ = 0;
|
||||
|
||||
public:
|
||||
TestTopic() = default;
|
||||
|
||||
explicit TestTopic(
|
||||
int32_t id,
|
||||
int32_t val) :
|
||||
id_(id),
|
||||
val_(val) { }
|
||||
|
||||
int32_t id() const { return this->id_; }
|
||||
int32_t& id() { return this->id_; }
|
||||
void id(int32_t _val_) { this->id_ = _val_; }
|
||||
int32_t val() const { return this->val_; }
|
||||
int32_t& val() { return this->val_; }
|
||||
void val(int32_t _val_) { this->val_ = _val_; }
|
||||
|
||||
bool operator==(const TestTopic& _other) const
|
||||
{
|
||||
(void) _other;
|
||||
return id_ == _other.id_ &&
|
||||
val_ == _other.val_;
|
||||
}
|
||||
|
||||
bool operator!=(const TestTopic& _other) const
|
||||
{
|
||||
return !(*this == _other);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, TestTopic const& rhs);
|
||||
|
||||
class TestTopic2
|
||||
{
|
||||
private:
|
||||
int32_t id_ = 0;
|
||||
int32_t val_ = 0;
|
||||
|
||||
public:
|
||||
TestTopic2() = default;
|
||||
|
||||
explicit TestTopic2(
|
||||
int32_t id,
|
||||
int32_t val) :
|
||||
id_(id),
|
||||
val_(val) { }
|
||||
|
||||
int32_t id() const { return this->id_; }
|
||||
int32_t& id() { return this->id_; }
|
||||
void id(int32_t _val_) { this->id_ = _val_; }
|
||||
int32_t val() const { return this->val_; }
|
||||
int32_t& val() { return this->val_; }
|
||||
void val(int32_t _val_) { this->val_ = _val_; }
|
||||
|
||||
bool operator==(const TestTopic2& _other) const
|
||||
{
|
||||
(void) _other;
|
||||
return id_ == _other.id_ &&
|
||||
val_ == _other.val_;
|
||||
}
|
||||
|
||||
bool operator!=(const TestTopic2& _other) const
|
||||
{
|
||||
return !(*this == _other);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, TestTopic2 const& rhs);
|
||||
|
||||
} //namespace ddkit_intern
|
||||
|
||||
#include "dds/topic/TopicTraits.hpp"
|
||||
#include "org/eclipse/cyclonedds/topic/datatopic.hpp"
|
||||
|
||||
namespace org {
|
||||
namespace eclipse {
|
||||
namespace cyclonedds {
|
||||
namespace topic {
|
||||
|
||||
template <> constexpr const char* TopicTraits<::ddkit_intern::TestTopic>::getTypeName()
|
||||
{
|
||||
return "ddkit_intern::TestTopic";
|
||||
}
|
||||
|
||||
#ifdef DDSCXX_HAS_TYPELIB
|
||||
template<> constexpr unsigned int TopicTraits<::ddkit_intern::TestTopic>::type_map_blob_sz() { return 242; }
|
||||
template<> constexpr unsigned int TopicTraits<::ddkit_intern::TestTopic>::type_info_blob_sz() { return 100; }
|
||||
template<> inline const uint8_t * TopicTraits<::ddkit_intern::TestTopic>::type_map_blob() {
|
||||
alignas(4) static const uint8_t blob[] = {
|
||||
0x4b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b,
|
||||
0x65, 0x3d, 0x6a, 0xef, 0x9a, 0xac, 0x32, 0x00, 0x33, 0x00, 0x00, 0x00, 0xf1, 0x51, 0x01, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x04, 0xb8, 0x0b, 0xb7, 0x74, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x3a, 0x6d, 0x02, 0x84, 0x00,
|
||||
0x76, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf2, 0xd7, 0xaf, 0xad, 0x2b, 0xe3, 0xe9, 0xf7,
|
||||
0x20, 0xd5, 0xec, 0x5e, 0xad, 0xb6, 0x6d, 0x00, 0x5e, 0x00, 0x00, 0x00, 0xf2, 0x51, 0x01, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x64, 0x64, 0x6b, 0x69,
|
||||
0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x3a, 0x3a, 0x54, 0x65, 0x73, 0x74, 0x54, 0x6f,
|
||||
0x70, 0x69, 0x63, 0x00, 0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x64, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x76, 0x61, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0xf2, 0xd7, 0xaf, 0xad, 0x2b, 0xe3, 0xe9, 0xf7, 0x20, 0xd5, 0xec, 0x5e,
|
||||
0xad, 0xb6, 0x6d, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b, 0x65, 0x3d, 0x6a, 0xef, 0x9a,
|
||||
0xac, 0x32, };
|
||||
return blob;
|
||||
}
|
||||
template<> inline const uint8_t * TopicTraits<::ddkit_intern::TestTopic>::type_info_blob() {
|
||||
alignas(4) static const uint8_t blob[] = {
|
||||
0x60, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x40, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b, 0x65, 0x3d, 0x6a, 0xef,
|
||||
0x9a, 0xac, 0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x40, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0xf2, 0xd7, 0xaf, 0xad, 0x2b, 0xe3, 0xe9, 0xf7, 0x20, 0xd5, 0xec, 0x5e,
|
||||
0xad, 0xb6, 0x6d, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, };
|
||||
return blob;
|
||||
}
|
||||
#endif //DDSCXX_HAS_TYPELIB
|
||||
|
||||
template <> constexpr const char* TopicTraits<::ddkit_intern::TestTopic2>::getTypeName()
|
||||
{
|
||||
return "ddkit_intern::TestTopic2";
|
||||
}
|
||||
|
||||
#ifdef DDSCXX_HAS_TYPELIB
|
||||
template<> constexpr unsigned int TopicTraits<::ddkit_intern::TestTopic2>::type_map_blob_sz() { return 246; }
|
||||
template<> constexpr unsigned int TopicTraits<::ddkit_intern::TestTopic2>::type_info_blob_sz() { return 100; }
|
||||
template<> inline const uint8_t * TopicTraits<::ddkit_intern::TestTopic2>::type_map_blob() {
|
||||
alignas(4) static const uint8_t blob[] = {
|
||||
0x4b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b,
|
||||
0x65, 0x3d, 0x6a, 0xef, 0x9a, 0xac, 0x32, 0x00, 0x33, 0x00, 0x00, 0x00, 0xf1, 0x51, 0x01, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x04, 0xb8, 0x0b, 0xb7, 0x74, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x3a, 0x6d, 0x02, 0x84, 0x00,
|
||||
0x7a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf2, 0xce, 0x3c, 0x46, 0x72, 0x20, 0xd5, 0x19,
|
||||
0x8d, 0x0a, 0x7c, 0x19, 0x4d, 0xa2, 0xc7, 0x00, 0x62, 0x00, 0x00, 0x00, 0xf2, 0x51, 0x01, 0x00,
|
||||
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x64, 0x64, 0x6b, 0x69,
|
||||
0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x3a, 0x3a, 0x54, 0x65, 0x73, 0x74, 0x54, 0x6f,
|
||||
0x70, 0x69, 0x63, 0x32, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x69, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x76, 0x61, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf2, 0xce, 0x3c, 0x46, 0x72, 0x20, 0xd5, 0x19,
|
||||
0x8d, 0x0a, 0x7c, 0x19, 0x4d, 0xa2, 0xc7, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b, 0x65,
|
||||
0x3d, 0x6a, 0xef, 0x9a, 0xac, 0x32, };
|
||||
return blob;
|
||||
}
|
||||
template<> inline const uint8_t * TopicTraits<::ddkit_intern::TestTopic2>::type_info_blob() {
|
||||
alignas(4) static const uint8_t blob[] = {
|
||||
0x60, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x40, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b, 0x65, 0x3d, 0x6a, 0xef,
|
||||
0x9a, 0xac, 0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x40, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0xf2, 0xce, 0x3c, 0x46, 0x72, 0x20, 0xd5, 0x19, 0x8d, 0x0a, 0x7c, 0x19,
|
||||
0x4d, 0xa2, 0xc7, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, };
|
||||
return blob;
|
||||
}
|
||||
#endif //DDSCXX_HAS_TYPELIB
|
||||
|
||||
} //namespace topic
|
||||
} //namespace cyclonedds
|
||||
} //namespace eclipse
|
||||
} //namespace org
|
||||
|
||||
namespace dds {
|
||||
namespace topic {
|
||||
|
||||
template <>
|
||||
struct topic_type_name<::ddkit_intern::TestTopic>
|
||||
{
|
||||
static std::string value()
|
||||
{
|
||||
return org::eclipse::cyclonedds::topic::TopicTraits<::ddkit_intern::TestTopic>::getTypeName();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct topic_type_name<::ddkit_intern::TestTopic2>
|
||||
{
|
||||
static std::string value()
|
||||
{
|
||||
return org::eclipse::cyclonedds::topic::TopicTraits<::ddkit_intern::TestTopic2>::getTypeName();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TOPIC_TYPE(::ddkit_intern::TestTopic)
|
||||
REGISTER_TOPIC_TYPE(::ddkit_intern::TestTopic2)
|
||||
|
||||
namespace org{
|
||||
namespace eclipse{
|
||||
namespace cyclonedds{
|
||||
namespace core{
|
||||
namespace cdr{
|
||||
|
||||
template<>
|
||||
const propvec &get_type_props<::ddkit_intern::TestTopic>();
|
||||
|
||||
namespace {
|
||||
static const volatile propvec &properties___ddkit_intern__TestTopic = get_type_props<::ddkit_intern::TestTopic>();
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
|
||||
bool write(T& streamer, const ::ddkit_intern::TestTopic& instance, const entity_properties_t *props) {
|
||||
(void)instance;
|
||||
member_id_set member_ids;
|
||||
if (!streamer.start_struct(*props))
|
||||
return false;
|
||||
auto prop = streamer.first_entity(props);
|
||||
while (prop) {
|
||||
switch (prop->m_id) {
|
||||
case 0:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!write(streamer, instance.id()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
case 1:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!write(streamer, instance.val()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
prop = streamer.next_entity(prop);
|
||||
}
|
||||
return streamer.finish_struct(*props, member_ids);
|
||||
}
|
||||
|
||||
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
|
||||
bool write(S& str, const ::ddkit_intern::TestTopic& instance, key_mode key) {
|
||||
const auto &props = get_type_props<::ddkit_intern::TestTopic>();
|
||||
str.set_mode(cdr_stream::stream_mode::write, key);
|
||||
return write(str, instance, props.data());
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
|
||||
bool read(T& streamer, ::ddkit_intern::TestTopic& instance, const entity_properties_t *props) {
|
||||
(void)instance;
|
||||
member_id_set member_ids;
|
||||
if (!streamer.start_struct(*props))
|
||||
return false;
|
||||
auto prop = streamer.first_entity(props);
|
||||
while (prop) {
|
||||
switch (prop->m_id) {
|
||||
case 0:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!read(streamer, instance.id()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
case 1:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!read(streamer, instance.val()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
prop = streamer.next_entity(prop);
|
||||
}
|
||||
return streamer.finish_struct(*props, member_ids);
|
||||
}
|
||||
|
||||
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
|
||||
bool read(S& str, ::ddkit_intern::TestTopic& instance, key_mode key) {
|
||||
const auto &props = get_type_props<::ddkit_intern::TestTopic>();
|
||||
str.set_mode(cdr_stream::stream_mode::read, key);
|
||||
return read(str, instance, props.data());
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
|
||||
bool move(T& streamer, const ::ddkit_intern::TestTopic& instance, const entity_properties_t *props) {
|
||||
(void)instance;
|
||||
member_id_set member_ids;
|
||||
if (!streamer.start_struct(*props))
|
||||
return false;
|
||||
auto prop = streamer.first_entity(props);
|
||||
while (prop) {
|
||||
switch (prop->m_id) {
|
||||
case 0:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!move(streamer, instance.id()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
case 1:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!move(streamer, instance.val()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
prop = streamer.next_entity(prop);
|
||||
}
|
||||
return streamer.finish_struct(*props, member_ids);
|
||||
}
|
||||
|
||||
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
|
||||
bool move(S& str, const ::ddkit_intern::TestTopic& instance, key_mode key) {
|
||||
const auto &props = get_type_props<::ddkit_intern::TestTopic>();
|
||||
str.set_mode(cdr_stream::stream_mode::move, key);
|
||||
return move(str, instance, props.data());
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
|
||||
bool max(T& streamer, const ::ddkit_intern::TestTopic& instance, const entity_properties_t *props) {
|
||||
(void)instance;
|
||||
member_id_set member_ids;
|
||||
if (!streamer.start_struct(*props))
|
||||
return false;
|
||||
auto prop = streamer.first_entity(props);
|
||||
while (prop) {
|
||||
switch (prop->m_id) {
|
||||
case 0:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!max(streamer, instance.id()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
case 1:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!max(streamer, instance.val()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
prop = streamer.next_entity(prop);
|
||||
}
|
||||
return streamer.finish_struct(*props, member_ids);
|
||||
}
|
||||
|
||||
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
|
||||
bool max(S& str, const ::ddkit_intern::TestTopic& instance, key_mode key) {
|
||||
const auto &props = get_type_props<::ddkit_intern::TestTopic>();
|
||||
str.set_mode(cdr_stream::stream_mode::max, key);
|
||||
return max(str, instance, props.data());
|
||||
}
|
||||
|
||||
template<>
|
||||
const propvec &get_type_props<::ddkit_intern::TestTopic2>();
|
||||
|
||||
namespace {
|
||||
static const volatile propvec &properties___ddkit_intern__TestTopic2 = get_type_props<::ddkit_intern::TestTopic2>();
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
|
||||
bool write(T& streamer, const ::ddkit_intern::TestTopic2& instance, const entity_properties_t *props) {
|
||||
(void)instance;
|
||||
member_id_set member_ids;
|
||||
if (!streamer.start_struct(*props))
|
||||
return false;
|
||||
auto prop = streamer.first_entity(props);
|
||||
while (prop) {
|
||||
switch (prop->m_id) {
|
||||
case 0:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!write(streamer, instance.id()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
case 1:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!write(streamer, instance.val()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
prop = streamer.next_entity(prop);
|
||||
}
|
||||
return streamer.finish_struct(*props, member_ids);
|
||||
}
|
||||
|
||||
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
|
||||
bool write(S& str, const ::ddkit_intern::TestTopic2& instance, key_mode key) {
|
||||
const auto &props = get_type_props<::ddkit_intern::TestTopic2>();
|
||||
str.set_mode(cdr_stream::stream_mode::write, key);
|
||||
return write(str, instance, props.data());
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
|
||||
bool read(T& streamer, ::ddkit_intern::TestTopic2& instance, const entity_properties_t *props) {
|
||||
(void)instance;
|
||||
member_id_set member_ids;
|
||||
if (!streamer.start_struct(*props))
|
||||
return false;
|
||||
auto prop = streamer.first_entity(props);
|
||||
while (prop) {
|
||||
switch (prop->m_id) {
|
||||
case 0:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!read(streamer, instance.id()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
case 1:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!read(streamer, instance.val()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
prop = streamer.next_entity(prop);
|
||||
}
|
||||
return streamer.finish_struct(*props, member_ids);
|
||||
}
|
||||
|
||||
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
|
||||
bool read(S& str, ::ddkit_intern::TestTopic2& instance, key_mode key) {
|
||||
const auto &props = get_type_props<::ddkit_intern::TestTopic2>();
|
||||
str.set_mode(cdr_stream::stream_mode::read, key);
|
||||
return read(str, instance, props.data());
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
|
||||
bool move(T& streamer, const ::ddkit_intern::TestTopic2& instance, const entity_properties_t *props) {
|
||||
(void)instance;
|
||||
member_id_set member_ids;
|
||||
if (!streamer.start_struct(*props))
|
||||
return false;
|
||||
auto prop = streamer.first_entity(props);
|
||||
while (prop) {
|
||||
switch (prop->m_id) {
|
||||
case 0:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!move(streamer, instance.id()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
case 1:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!move(streamer, instance.val()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
prop = streamer.next_entity(prop);
|
||||
}
|
||||
return streamer.finish_struct(*props, member_ids);
|
||||
}
|
||||
|
||||
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
|
||||
bool move(S& str, const ::ddkit_intern::TestTopic2& instance, key_mode key) {
|
||||
const auto &props = get_type_props<::ddkit_intern::TestTopic2>();
|
||||
str.set_mode(cdr_stream::stream_mode::move, key);
|
||||
return move(str, instance, props.data());
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
|
||||
bool max(T& streamer, const ::ddkit_intern::TestTopic2& instance, const entity_properties_t *props) {
|
||||
(void)instance;
|
||||
member_id_set member_ids;
|
||||
if (!streamer.start_struct(*props))
|
||||
return false;
|
||||
auto prop = streamer.first_entity(props);
|
||||
while (prop) {
|
||||
switch (prop->m_id) {
|
||||
case 0:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!max(streamer, instance.id()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
case 1:
|
||||
if (!streamer.start_member(*prop))
|
||||
return false;
|
||||
if (!max(streamer, instance.val()))
|
||||
return false;
|
||||
if (!streamer.finish_member(*prop, member_ids))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
prop = streamer.next_entity(prop);
|
||||
}
|
||||
return streamer.finish_struct(*props, member_ids);
|
||||
}
|
||||
|
||||
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
|
||||
bool max(S& str, const ::ddkit_intern::TestTopic2& instance, key_mode key) {
|
||||
const auto &props = get_type_props<::ddkit_intern::TestTopic2>();
|
||||
str.set_mode(cdr_stream::stream_mode::max, key);
|
||||
return max(str, instance, props.data());
|
||||
}
|
||||
|
||||
} //namespace cdr
|
||||
} //namespace core
|
||||
} //namespace cyclonedds
|
||||
} //namespace eclipse
|
||||
} //namespace org
|
||||
|
||||
#endif // DDSCXX_TESTTOPIC_HPP_5D6BACE0D1D9ADC0287C638316554B9B
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace utils {
|
||||
namespace callback {
|
||||
|
||||
template<class Actor, typename... Args>
|
||||
class Wrapper;
|
||||
|
||||
class Base {
|
||||
|
||||
public:
|
||||
virtual ~Base(){}
|
||||
|
||||
template<class Actor, typename... Args>
|
||||
void tryToInvoke(void (Actor::*func)(Args...), Args&&... args) {
|
||||
auto cb = dynamic_cast<Wrapper<Actor, Args...>*>(this);
|
||||
if(cb && cb->isFunction(func)){
|
||||
cb->invoke(args...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class Actor, typename... Args>
|
||||
class Wrapper : public Base {
|
||||
|
||||
public:
|
||||
using ActorType = Actor;
|
||||
using CallbackType = std::function<void(Args...)>;
|
||||
using ActorFunctionType = void (Actor::*)(Args...);
|
||||
|
||||
Wrapper() = delete;
|
||||
virtual ~Wrapper(){}
|
||||
|
||||
Wrapper(ActorFunctionType func, CallbackType cb)
|
||||
: m_actorFunction(func)
|
||||
, m_callback(cb)
|
||||
{
|
||||
}
|
||||
|
||||
bool isFunction(ActorFunctionType func){
|
||||
return m_actorFunction == func;
|
||||
}
|
||||
|
||||
void invoke(Args... args){
|
||||
m_callback(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Base;
|
||||
|
||||
ActorFunctionType m_actorFunction;
|
||||
CallbackType m_callback;
|
||||
};
|
||||
|
||||
template<class Actor, typename... Args>
|
||||
Wrapper<Actor, Args...>* Callback(void (Actor::*pm)(Args...), std::function<void(Args...)> cb){
|
||||
return new Wrapper<Actor, Args...>(pm, cb);
|
||||
}
|
||||
|
||||
template<class Actor, typename... Args, typename Fn>
|
||||
Wrapper<Actor, Args...>* Callback(void (Actor::*pm)(Args...), const Fn& callback){
|
||||
return new Wrapper<Actor, Args...>(pm, std::function<void(Args...)>(callback));
|
||||
}
|
||||
|
||||
} // callback
|
||||
} // utils
|
||||
namespace callback = ddkit::utils::callback;
|
||||
} // ddkit
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace ddkit {
|
||||
namespace utils {
|
||||
namespace exceptions {
|
||||
|
||||
class GlobalHandler {
|
||||
|
||||
public:
|
||||
template<typename Exception> static void registerHandler(std::function<void(Exception&)> handler){
|
||||
instance().m_registeredHandlers.push_back([handler](std::exception_ptr exceptionPtr){
|
||||
try {
|
||||
std::rethrow_exception(exceptionPtr);
|
||||
} catch (Exception& e) {
|
||||
handler(e);
|
||||
} catch (...){
|
||||
// NO OP
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void registerHandler(std::function<void(std::exception_ptr)> handler){
|
||||
instance().m_registeredHandlers.push_back(handler);
|
||||
}
|
||||
|
||||
private:
|
||||
std::terminate_handler m_previousHandler;
|
||||
std::vector<std::function<void(std::exception_ptr)>> m_registeredHandlers;
|
||||
|
||||
GlobalHandler();
|
||||
void handleException(const std::exception_ptr&);
|
||||
|
||||
static GlobalHandler& instance();
|
||||
static void terminateHandler();
|
||||
|
||||
};
|
||||
|
||||
} // namespace exceptions
|
||||
} // namespace utils
|
||||
} // namespace ddkit
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef __GNUG__
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
//#define DDKIT_ENABLE_LIFETIME_LOGGER
|
||||
|
||||
namespace ddkit {
|
||||
namespace utils {
|
||||
namespace log {
|
||||
|
||||
|
||||
template <typename Type>
|
||||
class LifetimeLogger {
|
||||
public:
|
||||
LifetimeLogger() {
|
||||
#ifdef DDKIT_ENABLE_LIFETIME_LOGGER
|
||||
std::cerr << "Constructor of:\t" << typeName() << " @ " << this << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
~LifetimeLogger() {
|
||||
#ifdef DDKIT_ENABLE_LIFETIME_LOGGER
|
||||
std::cerr << "Destructor of: \t" << typeName() << " @ " << this << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
std::string typeName() const {
|
||||
#ifdef __GNUG__
|
||||
const char* mangled = typeid(Type).name();
|
||||
|
||||
int status = 0;
|
||||
char* name = abi::__cxa_demangle(mangled, nullptr, nullptr, &status);
|
||||
if(status == 0) {
|
||||
std::string demangledName(name);
|
||||
delete name;
|
||||
return demangledName;
|
||||
}
|
||||
return mangled;
|
||||
#else
|
||||
return typeid(Type).name();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace log
|
||||
} // namespace utils
|
||||
} // namespace ddkit
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
|
||||
#include "ddkit/utils/Logger.hpp"
|
||||
|
||||
namespace ddkit {
|
||||
namespace utils {
|
||||
namespace log {
|
||||
namespace sinks {
|
||||
|
||||
// writes all lines to std::ostream after applying ANSI color codes
|
||||
class OStreamSink : public Sink {
|
||||
|
||||
public:
|
||||
OStreamSink(const base::IConfig& config, std::ostream& stream);
|
||||
void write(Level level, const std::string& prefix, const std::string& line) override;
|
||||
|
||||
private:
|
||||
std::mutex m_writeMutex;
|
||||
bool m_doColorize;
|
||||
std::ostream& m_stream;
|
||||
static const Registrar<OStreamSink> s_registrarCerr;
|
||||
static const Registrar<OStreamSink> s_registrarCout;
|
||||
};
|
||||
|
||||
// writes all lines to logfile
|
||||
class FileSink : public Sink {
|
||||
|
||||
public:
|
||||
FileSink(const base::IConfig& config);
|
||||
void write(Level level, const std::string& prefix, const std::string& line) override;
|
||||
|
||||
private:
|
||||
void openFile();
|
||||
void rotateLog();
|
||||
void incrementFileRecursive(size_t count); // moves m_file<count> to m_file<count+1>
|
||||
|
||||
// log rotate settings
|
||||
bool m_rotateOnStartup;
|
||||
size_t m_rotateOnFileSize;
|
||||
size_t m_rotateOnLineCount;
|
||||
size_t m_rotateKeptFileCount;
|
||||
|
||||
size_t m_currentLinesInFile;
|
||||
|
||||
std::mutex m_writeMutex;
|
||||
std::mutex m_logRotateMutex;
|
||||
std::string m_filename;
|
||||
std::ofstream m_fh;
|
||||
static const Registrar<FileSink> s_registrar;
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
} // namespace log
|
||||
} // namespace utils
|
||||
} // namespace ddkit
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/utils/container.hpp"
|
||||
#include "ddkit/utils/system.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
// platforms either define __FUNCSIG__ (MSVC), or __PRETTY_FUNCTION__ (gcc, clang)
|
||||
#ifdef _WIN32
|
||||
#define DDKIT_LOG_FUNCSIG __FUNCSIG__
|
||||
#else
|
||||
#define DDKIT_LOG_FUNCSIG __PRETTY_FUNCTION__
|
||||
#endif
|
||||
|
||||
#define DDKIT_LOG_LOCATION (ddkit::utils::system::filename(std::string(__FILE__)) + ":" + __LINE__)
|
||||
#define DDKIT_LOG_LOCATION_STREAM ddkit::utils::system::filename(std::string(__FILE__)) << ":" << __LINE__ << ":" << DDKIT_LOG_FUNCSIG
|
||||
#define DDKIT_LOG_VAR_VALUE(val) #val << "==" << (val)
|
||||
|
||||
// Only for trace, there would be anyway a macro needed for line
|
||||
#define DDKIT_LOG_TRACE ddkit::utils::log::trace() << "(" << DDKIT_LOG_LOCATION_STREAM << ") "
|
||||
|
||||
namespace ddkit {
|
||||
namespace base {
|
||||
|
||||
class IConfig;
|
||||
class Config;
|
||||
}
|
||||
|
||||
namespace utils {
|
||||
namespace log {
|
||||
|
||||
enum class Level {
|
||||
None = 0x0, // 0b00000000
|
||||
Fatal = 0x1, // 0b00000001
|
||||
Error = 0x3, // 0b00000011
|
||||
Warn = 0x7, // 0b00000111
|
||||
Info = 0xF, // 0b00001111
|
||||
// ?? = 0x1F, // 0b00011111 RESERVED
|
||||
Debug = 0x3F, // 0b00111111
|
||||
// ?? = 0x7F, // 0b01111111 RESERVED
|
||||
Trace = 0xFF, // 0b11111111
|
||||
};
|
||||
|
||||
class Sink;
|
||||
typedef std::shared_ptr<Sink> SinkPtr;
|
||||
|
||||
class Logger {
|
||||
|
||||
using SinkFactoryFunction = std::function<SinkPtr(const base::IConfig&)>;
|
||||
|
||||
public:
|
||||
static void loadConfig(const base::Config&);
|
||||
static void registerSinkType(const std::string& id, const SinkFactoryFunction& factory);
|
||||
static void installSink(const std::string& id, const base::IConfig&);
|
||||
static void installSink(SinkPtr);
|
||||
static void write(Level, const std::string&);
|
||||
static void uninstallAllSinks();
|
||||
static Level getHighestUsedLevel();
|
||||
private:
|
||||
Logger();
|
||||
Logger(const Logger&) = delete;
|
||||
static Logger& instance();
|
||||
static std::string getPrefix(Level);
|
||||
|
||||
// shared_ptr/SinkPtr is used to circumvent the issue of having a collection of pure virtual class
|
||||
std::vector<SinkPtr> m_sinks;
|
||||
std::map<std::string, SinkFactoryFunction> m_sinkTypes;
|
||||
|
||||
// stored for performance reasons, aids in aborting early in LineBuilder if the log level isnt used
|
||||
Level mHighestLevel;
|
||||
};
|
||||
|
||||
class Sink {
|
||||
|
||||
public:
|
||||
template<class Type> class Registrar;
|
||||
Sink(const base::IConfig&);
|
||||
virtual ~Sink(){}
|
||||
virtual void write(Level level, const std::string& prefix, const std::string& line) = 0;
|
||||
|
||||
void setLevel(Level);
|
||||
void setLevel(const std::string&);
|
||||
Level getLevel() const;
|
||||
|
||||
private:
|
||||
Sink() = delete;
|
||||
|
||||
protected:
|
||||
Level m_level;
|
||||
};
|
||||
|
||||
template<class Type> class Sink::Registrar {
|
||||
|
||||
public:
|
||||
Registrar() = delete;
|
||||
// Registrar<FileSink>("file")
|
||||
Registrar(const std::string& id){
|
||||
Logger::registerSinkType(id, [](const base::IConfig& config){
|
||||
return std::make_shared<Type>(config);
|
||||
});
|
||||
}
|
||||
|
||||
// Registrar<OStreamSink>("cerr", std::cerr)
|
||||
template<class Param> Registrar(const std::string& id, Param& param){
|
||||
auto pRef = std::ref(param);
|
||||
Logger::registerSinkType(id, [pRef](const base::IConfig& config){
|
||||
return std::make_shared<Type>(config, pRef.get());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Stores a number of strings and writes them to log on destruction
|
||||
class LineBuilder {
|
||||
|
||||
public:
|
||||
LineBuilder(Level);
|
||||
LineBuilder() = delete;
|
||||
LineBuilder(const LineBuilder&) = delete;
|
||||
LineBuilder(LineBuilder&&);
|
||||
~LineBuilder();
|
||||
LineBuilder& operator<<(const std::string&);
|
||||
LineBuilder& operator<<(bool);
|
||||
|
||||
template<typename T> LineBuilder& operator<<(const T& value){
|
||||
if(Logger::getHighestUsedLevel() < m_level) return *this; // early abort for performance gains
|
||||
|
||||
m_line << value << " ";
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> LineBuilder& operator<<(const std::vector<T>& vec){
|
||||
if(Logger::getHighestUsedLevel() < m_level) return *this; // early abort for performance gains
|
||||
|
||||
m_line << "[";
|
||||
for(auto it = vec.begin(); it != vec.end(); it++){
|
||||
*this << *it;
|
||||
if(vec.end() - it != 1){ // all except for the last element
|
||||
m_line << ", ";
|
||||
}
|
||||
}
|
||||
*this << "] ";
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
Level m_level;
|
||||
std::ostringstream m_line;
|
||||
};
|
||||
|
||||
LineBuilder fatal();
|
||||
LineBuilder error();
|
||||
LineBuilder warn();
|
||||
LineBuilder info();
|
||||
LineBuilder debug();
|
||||
LineBuilder trace();
|
||||
|
||||
} // namespace log
|
||||
} // namespace utils
|
||||
|
||||
namespace log = ddkit::utils::log;
|
||||
|
||||
} // namespace ddkit
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "ddkit/utils/Logger.hpp"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#define DDKIT_THROW_ON_FALSE(cond) \
|
||||
if (!(cond)) { \
|
||||
/*raise(SIGTRAP); */ \
|
||||
std::string msg = std::string("Assertion \"" #cond "\" failed in ") + __FILE__ + ":" + std::to_string(__LINE__); \
|
||||
ddkit::log::fatal() << msg; \
|
||||
throw std::logic_error(msg); \
|
||||
}
|
||||
|
||||
#define DDKIT_THROW_ON_FALSE_INFO(cond, info) \
|
||||
if (!(cond)) { \
|
||||
/*raise(SIGTRAP);*/ \
|
||||
std::string msg = std::string("Assertion \"" #cond "\" failed in ") + __FILE__ + ":" + std::to_string(__LINE__); \
|
||||
ddkit::log::fatal() << msg << " :" << std::string(info); \
|
||||
throw std::logic_error(msg + " :" + std::string(info)); \
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <memory>
|
||||
|
||||
namespace ddkit {
|
||||
namespace utils {
|
||||
namespace container {
|
||||
|
||||
template <typename Container, typename Value>
|
||||
bool contains(Container container, Value value) {
|
||||
return std::find(container.begin(), container.end(), value) != container.end();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> set2vector(std::set<T> p_set) {
|
||||
std::vector<T> r_vec;
|
||||
std::copy(p_set.begin(), p_set.end(), std::back_inserter(r_vec));
|
||||
return r_vec;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::set<T> vector2set(std::vector<T> p_vec) {
|
||||
std::set<T> r_set;
|
||||
std::copy(p_vec.begin(), p_vec.end(), std::inserter(r_set, r_set.begin()));
|
||||
return r_set;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::set<T> set_difference(typename std::set<T> const& minuend, typename std::set<T> const& subtrahend) {
|
||||
std::set<T> diff;
|
||||
std::set_difference(
|
||||
minuend.begin(),
|
||||
minuend.end(),
|
||||
subtrahend.begin(),
|
||||
subtrahend.end(),
|
||||
std::inserter(diff, diff.end()));
|
||||
return diff;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
typename std::vector<T> vector_difference(typename std::vector<T> const& minuend, typename std::vector<T> const& subtrahend) {
|
||||
std::vector<T> diff;
|
||||
|
||||
std::copy_if(minuend.begin(), minuend.end(), std::back_inserter(diff), [subtrahend](const T& element) {
|
||||
return !contains(subtrahend, element);
|
||||
});
|
||||
return diff;
|
||||
}
|
||||
|
||||
inline std::string quotify(const std::string& input) { return "\"" + input+ "\""; }
|
||||
template<typename T> T quotify(T t) { return t; }
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& s, std::vector<T> rhs) {
|
||||
bool isFirst = true;
|
||||
s << "[";
|
||||
for (auto const& i : rhs) {
|
||||
if (isFirst) isFirst = false;
|
||||
else s << ", ";
|
||||
s << quotify<T>(i);
|
||||
}
|
||||
s << "]";
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
std::ostream& operator<<(std::ostream& s, std::pair<T, U> rhs) {
|
||||
return s << rhs.first << ":" << quotify<U>(rhs.second);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
std::ostream& operator<<(std::ostream& s, std::map<T, U> rhs) {
|
||||
bool isFirst = true;
|
||||
s << "{";
|
||||
for (auto const& i : rhs) {
|
||||
if (isFirst) isFirst = false;
|
||||
else s << ", ";
|
||||
s << i;
|
||||
}
|
||||
s << "}";
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& s, std::set<T> rhs) {
|
||||
bool isFirst = true;
|
||||
s << "[";
|
||||
for (auto const& i : rhs) {
|
||||
if (isFirst) isFirst = false;
|
||||
else s << ", ";
|
||||
s << quotify<T>(i);
|
||||
}
|
||||
s << "]";
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& s, std::weak_ptr<T> rhs) {
|
||||
if(rhs.expired()){
|
||||
s << "<expired>";
|
||||
} else {
|
||||
s << rhs.lock();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
} // container
|
||||
} // utils
|
||||
using ddkit::utils::container::operator<<;
|
||||
} // ddkit
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
namespace ddkit {
|
||||
namespace utils {
|
||||
namespace types {
|
||||
|
||||
template <typename T>
|
||||
class Optional {
|
||||
|
||||
private:
|
||||
std::vector<T> &vec;
|
||||
|
||||
public:
|
||||
Optional(std::vector<T> &val) : vec(val) {}
|
||||
|
||||
Optional() = delete;
|
||||
|
||||
T& value() {
|
||||
if(vec.size()) {
|
||||
return vec[0];
|
||||
} else {
|
||||
throw std::out_of_range( "optional is empty" );
|
||||
}
|
||||
}
|
||||
|
||||
T value_or(T defVal) {
|
||||
return vec.size() ? vec[0] : (defVal);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (vec.size()) {
|
||||
vec.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void set(const T &val) {
|
||||
if (vec.size()) {
|
||||
vec[0] = val;
|
||||
} else {
|
||||
vec.push_back(val);
|
||||
}
|
||||
}
|
||||
|
||||
bool has_value() const {
|
||||
return vec.size() ? true : false;
|
||||
}
|
||||
|
||||
std::vector<T> &operator*() {
|
||||
return vec[0];
|
||||
}
|
||||
|
||||
std::vector<T> *operator->() {
|
||||
return vec[0];
|
||||
}
|
||||
|
||||
Optional operator=(const T &val) {
|
||||
set(val);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return has_value();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ddkit {
|
||||
namespace utils {
|
||||
namespace string {
|
||||
|
||||
bool beginsWith(const std::string& text, const std::string& prefix);
|
||||
bool endsWith(const std::string& text, const std::string& suffix);
|
||||
bool contains(const std::string& container, const std::string& containee);
|
||||
|
||||
void removePrefix(std::string& line, const std::string& prefix);
|
||||
void removePrefixIf(std::string& line, const std::string& prefix);
|
||||
void removeSuffix(std::string& line, const std::string& suffix);
|
||||
void removeSuffixIf(std::string& line, const std::string& suffix);
|
||||
|
||||
std::string trimLeft(const std::string& text);
|
||||
std::string trimRight(const std::string& text);
|
||||
std::string trim(const std::string& text);
|
||||
|
||||
std::string toLower(const std::string& text);
|
||||
std::string toUpper(const std::string& text);
|
||||
std::string toFirstUpper(const std::string& text);
|
||||
|
||||
std::string replace(std::string text, const std::string& from, const std::string& to);
|
||||
std::vector<std::string> split(const std::string& text, char delim);
|
||||
std::string join(const std::vector<std::string>&, const std::string& delimiter);
|
||||
|
||||
bool isInt(const std::string& text);
|
||||
int toInt(const std::string& text);
|
||||
bool isInt64(const std::string& text);
|
||||
int64_t toInt64(const std::string& text);
|
||||
|
||||
} // namespace string
|
||||
} // namespace utils
|
||||
} // namespace ddkit
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ddkit {
|
||||
namespace utils {
|
||||
namespace system {
|
||||
|
||||
void sleep(int secs); // sleep seconds (instead of unix-sleep)
|
||||
void msSleep(int milliSecs); // sleep milliseconds (instead of unix-sleep)
|
||||
std::string getEnv(const std::string& var);
|
||||
std::string getEnv(const std::string& var, const std::string& defaultVal);
|
||||
bool setEnv(const std::string& name, const std::string& value);
|
||||
std::string dirname(std::string text); // "path/to/file.cpp" -> "path/to/"
|
||||
std::string filename(std::string text); // "path/to/file.cpp" -> "file" / "path/to/file.hpp" -> "file.hpp"
|
||||
std::string filenameBase(std::string text); // "path/to/file.xyz" -> "file.cpp" -> "file"
|
||||
int getProcessId();
|
||||
std::string getProcessName(); // "some_name"
|
||||
std::string getProcessNameWithPath(); // "/user/local/bin/some_name.exe"
|
||||
std::string getHostname();
|
||||
|
||||
std::string threadIdCurrent();
|
||||
|
||||
void blockSignals(); // blocks SIGINT/SIGHUP/SIGKILL for current thread. does nothing on windows
|
||||
void waitForSignal(); // waits for SIGINT/SIGHUP/SIGKILL, or windows ctrl-c
|
||||
|
||||
bool isFileReadable(const std::string& filename); // does a file exist and does open succeed?
|
||||
bool renameFile(const std::string& oldName, const std::string& newName);
|
||||
bool deleteFile(const std::string& name);
|
||||
void setNativeThreadName(const std::string& name);
|
||||
std::string getNativeThreadName();
|
||||
|
||||
} // namespace system
|
||||
} // namespace utils
|
||||
} // namespace ddkit
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
|
||||
namespace ddkit {
|
||||
namespace utils {
|
||||
namespace time {
|
||||
|
||||
int64_t getCurrentUnixTimestamp();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user