Adds further ext deps as-is binaries copies from customers env.
Qt6 Migration CI / migrate (push) Canceled after 0s

This commit is contained in:
torsten committed 2026-10-23 16:13:31 +00:00
1 parent 48129fdab2
commit 48d9b9bd49
3700 files changed
+2132394

No files matched your search

+99
View File
@@ -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
+56
View File
@@ -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
+29
View File
@@ -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
+382
View File
@@ -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
+36
View File
@@ -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
View File
@@ -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
+22
View File
@@ -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
View File
@@ -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
+38
View File
@@ -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
+33
View File
@@ -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
View File
@@ -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
+70
View File
@@ -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
View File
@@ -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
+59
View File
@@ -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
View File
@@ -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