mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-05 17:28:15 +08:00
Issue #15 Added IDataLink, an interface for registering observers and mutators,
and CDataLinkLocal, an implementation for sharing state within a single process
This commit is contained in:
44
src/blackmisc/sharedstate/datalink.cpp
Normal file
44
src/blackmisc/sharedstate/datalink.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/* Copyright (C) 2017
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
|
||||
* or distributed except according to the terms contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#include "blackmisc/sharedstate/datalink.h"
|
||||
#include "blackmisc/promise.h"
|
||||
#include "blackmisc/variant.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace SharedState
|
||||
{
|
||||
void CDataLinkConnectionWatcher::setStatus(bool status)
|
||||
{
|
||||
if (status != m_connected)
|
||||
{
|
||||
m_connected = status;
|
||||
if (m_connected) { emit connected(); }
|
||||
else { emit disconnected(); }
|
||||
}
|
||||
}
|
||||
|
||||
IDataLink::~IDataLink() = default;
|
||||
|
||||
IDataLink::IDataLink()
|
||||
{
|
||||
qRegisterMetaType<CPromise<CVariant>>();
|
||||
}
|
||||
|
||||
QString IDataLink::getChannelName(const QObject *object)
|
||||
{
|
||||
const QMetaObject *meta = object->parent()->metaObject();
|
||||
const char *info = meta->classInfo(meta->indexOfClassInfo("SharedStateChannel")).value();
|
||||
const QString name = object->parent()->objectName();
|
||||
return name.isEmpty() ? QString(info) : (info % QLatin1Char(':') % name);
|
||||
}
|
||||
}
|
||||
}
|
||||
111
src/blackmisc/sharedstate/datalink.h
Normal file
111
src/blackmisc/sharedstate/datalink.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/* Copyright (C) 2017
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
|
||||
* or distributed except according to the terms contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_SHAREDSTATE_DATALINK_H
|
||||
#define BLACKMISC_SHAREDSTATE_DATALINK_H
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include "blackmisc/promise.h"
|
||||
#include "blackmisc/variant.h"
|
||||
#include <QObject>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaClassInfo>
|
||||
#include <QStringBuilder>
|
||||
|
||||
/*!
|
||||
* \defgroup SharedState Utilities for sharing state between multiple objects
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Put this macro in the private section of a class to set the channel of its child endpoints.
|
||||
* \ingroup SharedState
|
||||
*/
|
||||
#define BLACK_SHARED_STATE_CHANNEL(ID) Q_CLASSINFO("SharedStateChannel", ID)
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace SharedState
|
||||
{
|
||||
class IDataLink;
|
||||
class CPassiveMutator;
|
||||
class CActiveMutator;
|
||||
class CPassiveObserver;
|
||||
class CActiveObserver;
|
||||
|
||||
/*!
|
||||
* Observe the connection state of an IDataLink.
|
||||
*/
|
||||
class CDataLinkConnectionWatcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
//! True if connected to the transport layer.
|
||||
bool isConnected() const { return m_connected; }
|
||||
|
||||
signals:
|
||||
//! Connection established.
|
||||
void connected();
|
||||
|
||||
//! Connection dropped.
|
||||
void disconnected();
|
||||
|
||||
private:
|
||||
friend class IDataLink;
|
||||
CDataLinkConnectionWatcher() = default;
|
||||
void setStatus(bool connected);
|
||||
bool m_connected = false;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Interface that provides a transport mechanism for sharing state.
|
||||
* \ingroup SharedState
|
||||
*/
|
||||
class BLACKMISC_EXPORT IDataLink
|
||||
{
|
||||
public:
|
||||
//! Constructor.
|
||||
IDataLink();
|
||||
|
||||
//! Destructor.
|
||||
virtual ~IDataLink() = 0;
|
||||
|
||||
//! Get a connection status watcher.
|
||||
CDataLinkConnectionWatcher *watcher() { return &m_watcher; }
|
||||
|
||||
//! Register a mutator with this transport mechanism.
|
||||
//! @{
|
||||
virtual void publish(const CPassiveMutator *mutator) = 0;
|
||||
virtual void publish(const CActiveMutator *mutator) = 0;
|
||||
//! @}
|
||||
|
||||
//! Register an observer with this transport mechanism.
|
||||
//! @{
|
||||
virtual void subscribe(const CPassiveObserver *observer) = 0;
|
||||
virtual void subscribe(const CActiveObserver *observer) = 0;
|
||||
//! @}
|
||||
|
||||
protected:
|
||||
//! Set the connection status visible through the watcher.
|
||||
void setConnectionStatus(bool connected) { m_watcher.setStatus(connected); }
|
||||
|
||||
//! Get the channel name for child endpoints of the given object.
|
||||
static QString getChannelName(const QObject *object);
|
||||
|
||||
private:
|
||||
CDataLinkConnectionWatcher m_watcher;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_INTERFACE(BlackMisc::SharedState::IDataLink, "BlackMisc::SharedState::IDataLink")
|
||||
Q_DECLARE_METATYPE(BlackMisc::CPromise<BlackMisc::CVariant>)
|
||||
|
||||
#endif
|
||||
89
src/blackmisc/sharedstate/datalinklocal.cpp
Normal file
89
src/blackmisc/sharedstate/datalinklocal.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/* Copyright (C) 2017
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
|
||||
* or distributed except according to the terms contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#include "blackmisc/sharedstate/datalinklocal.h"
|
||||
#include "blackmisc/sharedstate/activeobserver.h"
|
||||
#include "blackmisc/sharedstate/activemutator.h"
|
||||
#include "blackmisc/promise.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace SharedState
|
||||
{
|
||||
CDataLinkLocal::CDataLinkLocal(QObject *parent) : QObject(parent)
|
||||
{
|
||||
setConnectionStatus(true);
|
||||
}
|
||||
|
||||
CDataLinkLocal::~CDataLinkLocal()
|
||||
{
|
||||
setConnectionStatus(false);
|
||||
}
|
||||
|
||||
void CDataLinkLocal::publish(const CPassiveMutator *mutator)
|
||||
{
|
||||
connect(mutator, &CPassiveMutator::eventPosted, this, [this, channel = getChannelName(mutator)](const CVariant ¶m) { dispatchEvent(param, channel); });
|
||||
}
|
||||
|
||||
void CDataLinkLocal::publish(const CActiveMutator *mutator)
|
||||
{
|
||||
publish(static_cast<const CPassiveMutator *>(mutator));
|
||||
|
||||
auto &channel = getChannel(mutator);
|
||||
Q_ASSERT_X(! channel.activeMutator, Q_FUNC_INFO, "Tried to publish two active mutators on one channel");
|
||||
channel.activeMutator = mutator->weakRef();
|
||||
}
|
||||
|
||||
void CDataLinkLocal::subscribe(const CPassiveObserver *observer)
|
||||
{
|
||||
getChannel(observer).passiveObservers.push_back(observer->weakRef());
|
||||
}
|
||||
|
||||
void CDataLinkLocal::subscribe(const CActiveObserver *observer)
|
||||
{
|
||||
subscribe(static_cast<const CPassiveObserver *>(observer));
|
||||
|
||||
connect(observer, &CActiveObserver::requestPosted, this, [this, channel = getChannelName(observer)](const CVariant ¶m, CPromise<CVariant> reply)
|
||||
{
|
||||
reply.chainResult(handleRequest(param, channel));
|
||||
});
|
||||
}
|
||||
|
||||
void CDataLinkLocal::dispatchEvent(const CVariant ¶m, const QString &channel)
|
||||
{
|
||||
for (const auto &observerWeak : as_const(getChannel(channel).passiveObservers))
|
||||
{
|
||||
auto observer = observerWeak.lock();
|
||||
if (observer && observer->eventSubscription().matches(param))
|
||||
{
|
||||
observer->handleEvent(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<CVariant> CDataLinkLocal::handleRequest(const CVariant ¶m, const QString &channel)
|
||||
{
|
||||
auto mutator = getChannel(channel).activeMutator.lock();
|
||||
if (mutator) { return mutator->handleRequest(param); }
|
||||
return {};
|
||||
}
|
||||
|
||||
CDataLinkLocal::Channel &CDataLinkLocal::getChannel(const QString &name)
|
||||
{
|
||||
QMutexLocker lock(&m_channelsMutex);
|
||||
return m_channels[name];
|
||||
}
|
||||
|
||||
CDataLinkLocal::Channel &CDataLinkLocal::getChannel(const QObject *object)
|
||||
{
|
||||
return getChannel(getChannelName(object));
|
||||
}
|
||||
}
|
||||
}
|
||||
64
src/blackmisc/sharedstate/datalinklocal.h
Normal file
64
src/blackmisc/sharedstate/datalinklocal.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2017
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
|
||||
* or distributed except according to the terms contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_SHAREDSTATE_DATALINKLOCAL_H
|
||||
#define BLACKMISC_SHAREDSTATE_DATALINKLOCAL_H
|
||||
|
||||
#include "blackmisc/sharedstate/datalink.h"
|
||||
#include "blackmisc/variant.h"
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include <QMutex>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace SharedState
|
||||
{
|
||||
/*!
|
||||
* A transport mechanism using signals and slots in the local process.
|
||||
* \ingroup SharedState
|
||||
*/
|
||||
class BLACKMISC_EXPORT CDataLinkLocal : public QObject, public IDataLink
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(BlackMisc::SharedState::IDataLink)
|
||||
|
||||
public:
|
||||
//! Constructor.
|
||||
CDataLinkLocal(QObject *parent = nullptr);
|
||||
|
||||
//! Destructor.
|
||||
virtual ~CDataLinkLocal() override;
|
||||
|
||||
virtual void publish(const CPassiveMutator *mutator) override;
|
||||
virtual void publish(const CActiveMutator *mutator) override;
|
||||
virtual void subscribe(const CPassiveObserver *observer) override;
|
||||
virtual void subscribe(const CActiveObserver *observer) override;
|
||||
|
||||
private:
|
||||
struct Channel
|
||||
{
|
||||
QWeakPointer<const CActiveMutator> activeMutator;
|
||||
QVector<QWeakPointer<const CPassiveObserver>> passiveObservers;
|
||||
};
|
||||
|
||||
void dispatchEvent(const CVariant ¶m, const QString &channel);
|
||||
QFuture<CVariant> handleRequest(const CVariant ¶m, const QString &channel);
|
||||
Channel &getChannel(const QString &name);
|
||||
Channel &getChannel(const QObject *object);
|
||||
|
||||
QMap<QString, Channel> m_channels;
|
||||
mutable QMutex m_channelsMutex { QMutex::Recursive };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user