383 lines
16 KiB
C++
383 lines
16 KiB
C++
#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
|