Add DBus P2P support to XSwiftBus

ref T291
This commit is contained in:
Roland Winklmeier
2018-07-26 22:32:53 +02:00
committed by Klaus Basan
parent fd45de89d9
commit 488ff96ce6
10 changed files with 324 additions and 40 deletions

View File

@@ -34,10 +34,10 @@ namespace BlackMisc
static const QString &humanReadable() { static const QString name("XSwiftBus"); return name; } static const QString &humanReadable() { static const QString name("XSwiftBus"); return name; }
//! \copydoc BlackMisc::TSettingTrait::defaultValue //! \copydoc BlackMisc::TSettingTrait::defaultValue
static QString defaultValue() { return BlackMisc::CDBusServer::sessionBusAddress(); } static QString defaultValue() { return "tcp:host=127.0.0.1,port=45001"; }
//! \copydoc BlackMisc::TSettingTrait::defaultValue //! \copydoc BlackMisc::TSettingTrait::defaultValue
static bool isValid(const QString &dBusAddress) { return BlackMisc::CDBusServer::isSessionOrSystemAddress(dBusAddress); } static bool isValid(const QString &dBusAddress) { return BlackMisc::CDBusServer::isSessionOrSystemAddress(dBusAddress) || BlackMisc::CDBusServer::isQtDBusAddress(dBusAddress); }
}; };
} // ns } // ns
} // ns } // ns

View File

@@ -54,6 +54,8 @@
#include "blackmisc/logmessage.h" #include "blackmisc/logmessage.h"
#include "blackconfig/buildconfig.h" #include "blackconfig/buildconfig.h"
#include "dbus/dbus.h"
#include <QColor> #include <QColor>
#include <QDBusServiceWatcher> #include <QDBusServiceWatcher>
#include <QString> #include <QString>
@@ -289,12 +291,29 @@ namespace BlackSimPlugin
bool CSimulatorXPlane::connectTo() bool CSimulatorXPlane::connectTo()
{ {
if (isConnected()) { return true; } if (isConnected()) { return true; }
m_dBusConnection = QDBusConnection::sessionBus(); // TODO make this configurable QString dbusAddress = m_xswiftbusServerSetting.getThreadLocal();
if (BlackMisc::CDBusServer::isSessionOrSystemAddress(dbusAddress))
{
m_dBusConnection = connectionFromString(dbusAddress);
m_dbusMode = Session;
}
else if (BlackMisc::CDBusServer::isQtDBusAddress(dbusAddress))
{
m_dBusConnection = QDBusConnection::connectToPeer(dbusAddress, "xswiftbus");
if (! m_dBusConnection.isConnected()) { return false; }
m_dbusMode = P2P;
}
m_serviceProxy = new CXSwiftBusServiceProxy(m_dBusConnection, this); m_serviceProxy = new CXSwiftBusServiceProxy(m_dBusConnection, this);
m_trafficProxy = new CXSwiftBusTrafficProxy(m_dBusConnection, this); m_trafficProxy = new CXSwiftBusTrafficProxy(m_dBusConnection, this);
m_weatherProxy = new CXSwiftBusWeatherProxy(m_dBusConnection, this); m_weatherProxy = new CXSwiftBusWeatherProxy(m_dBusConnection, this);
bool ok = false; bool ok = false;
bool s = m_dBusConnection.connect(QString(), DBUS_PATH_LOCAL, DBUS_INTERFACE_LOCAL,
"Disconnected", this, SLOT(serviceUnregistered()));
Q_ASSERT(s);
if (m_serviceProxy->isValid() && m_trafficProxy->isValid() && m_weatherProxy->isValid() && m_trafficProxy->initialize()) if (m_serviceProxy->isValid() && m_trafficProxy->isValid() && m_weatherProxy->isValid() && m_trafficProxy->initialize())
{ {
emitOwnAircraftModelChanged(m_serviceProxy->getAircraftModelPath(), m_serviceProxy->getAircraftModelFilename(), m_serviceProxy->getAircraftLivery(), emitOwnAircraftModelChanged(m_serviceProxy->getAircraftModelPath(), m_serviceProxy->getAircraftModelFilename(), m_serviceProxy->getAircraftLivery(),
@@ -337,6 +356,7 @@ namespace BlackSimPlugin
void CSimulatorXPlane::serviceUnregistered() void CSimulatorXPlane::serviceUnregistered()
{ {
if (m_dbusMode == P2P) { m_dBusConnection.disconnectFromPeer(m_dBusConnection.name()); }
m_dBusConnection = QDBusConnection { "default" }; m_dBusConnection = QDBusConnection { "default" };
if (m_watcher) { m_watcher->setConnection(m_dBusConnection); } if (m_watcher) { m_watcher->setConnection(m_dBusConnection); }
delete m_serviceProxy; delete m_serviceProxy;
@@ -428,7 +448,6 @@ namespace BlackSimPlugin
{ {
if (str == CDBusServer::sessionBusAddress()) { return QDBusConnection::sessionBus(); } if (str == CDBusServer::sessionBusAddress()) { return QDBusConnection::sessionBus(); }
if (str == CDBusServer::systemBusAddress()) { return QDBusConnection::systemBus(); } if (str == CDBusServer::systemBusAddress()) { return QDBusConnection::systemBus(); }
Q_UNREACHABLE(); Q_UNREACHABLE();
return QDBusConnection("NO CONNECTION"); return QDBusConnection("NO CONNECTION");
} }
@@ -897,9 +916,8 @@ namespace BlackSimPlugin
{ {
if (m_trafficProxy) { m_trafficProxy->cleanup(); } if (m_trafficProxy) { m_trafficProxy->cleanup(); }
// works for session/system bus if (m_dbusMode == P2P) { QDBusConnection::disconnectFromPeer(m_dBusConnection.name()); }
// see CCoreFacade::initDBusConnection for P2P else { QDBusConnection::disconnectFromBus(m_dBusConnection.name()); }
QDBusConnection::disconnectFromBus(m_dBusConnection.name());
} }
m_dBusConnection = QDBusConnection { "default" }; m_dBusConnection = QDBusConnection { "default" };
} }
@@ -1067,21 +1085,29 @@ namespace BlackSimPlugin
} }
CSimulatorXPlaneListener::CSimulatorXPlaneListener(const CSimulatorPluginInfo &info): ISimulatorListener(info) CSimulatorXPlaneListener::CSimulatorXPlaneListener(const CSimulatorPluginInfo &info): ISimulatorListener(info)
{ } {
constexpr int QueryInterval = 5 * 1000; // 5 seconds
m_timer.setInterval(QueryInterval);
m_timer.setObjectName(this->objectName().append(":m_timer"));
connect(&m_timer, &QTimer::timeout, this, &CSimulatorXPlaneListener::checkConnectionViaPeer);
}
void CSimulatorXPlaneListener::startImpl() void CSimulatorXPlaneListener::startImpl()
{ {
if (m_watcher) { return; } // already started QString dbusAddress = m_xswiftbusServerSetting.getThreadLocal();
if (isXSwiftBusRunning())
if (BlackMisc::CDBusServer::isSessionOrSystemAddress(dbusAddress))
{ {
emit simulatorStarted(getPluginInfo()); checkConnectionViaBus(dbusAddress);
}
else if (BlackMisc::CDBusServer::isQtDBusAddress(dbusAddress))
{
m_timer.start();
} }
else else
{ {
CLogMessage(this).debug() << "Watching XSwiftBus on" << m_xswiftbusServerSetting.getThreadLocal(); CLogMessage(this).warning("Invalid DBus address. Not listening for X-Plane connections!");
m_conn = CSimulatorXPlane::connectionFromString(m_xswiftbusServerSetting.getThreadLocal()); return;
m_watcher = new QDBusServiceWatcher(xswiftbusServiceName(), m_conn, QDBusServiceWatcher::WatchForRegistration, this);
connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &CSimulatorXPlaneListener::serviceRegistered);
} }
} }
@@ -1092,20 +1118,53 @@ namespace BlackSimPlugin
delete m_watcher; delete m_watcher;
m_watcher = nullptr; m_watcher = nullptr;
} }
m_timer.stop();
} }
bool CSimulatorXPlaneListener::isXSwiftBusRunning() const void CSimulatorXPlaneListener::checkConnectionViaBus(const QString &address)
{ {
QDBusConnection conn = CSimulatorXPlane::connectionFromString(m_xswiftbusServerSetting.getThreadLocal()); if (m_watcher) { return; }
CXSwiftBusServiceProxy *service = new CXSwiftBusServiceProxy(conn); m_conn = CSimulatorXPlane::connectionFromString(address);
CXSwiftBusTrafficProxy *traffic = new CXSwiftBusTrafficProxy(conn); CXSwiftBusServiceProxy *service = new CXSwiftBusServiceProxy(m_conn);
CXSwiftBusTrafficProxy *traffic = new CXSwiftBusTrafficProxy(m_conn);
bool result = service->isValid() && traffic->isValid(); bool result = service->isValid() && traffic->isValid();
service->deleteLater(); service->deleteLater();
traffic->deleteLater(); traffic->deleteLater();
return result; if (result)
{
emit simulatorStarted(getPluginInfo());
m_conn.disconnectFromBus(m_conn.name());
}
else
{
m_watcher = new QDBusServiceWatcher(xswiftbusServiceName(), m_conn, QDBusServiceWatcher::WatchForRegistration, this);
connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &CSimulatorXPlaneListener::serviceRegistered);
}
}
void CSimulatorXPlaneListener::checkConnectionViaPeer()
{
m_conn = QDBusConnection::connectToPeer(m_xswiftbusServerSetting.getThreadLocal(), "xswiftbus");
if (! m_conn.isConnected())
{
// This is required to cleanup the connection in QtDBus
m_conn.disconnectFromPeer(m_conn.name());
return;
}
CXSwiftBusServiceProxy *service = new CXSwiftBusServiceProxy(m_conn);
CXSwiftBusTrafficProxy *traffic = new CXSwiftBusTrafficProxy(m_conn);
bool result = service->isValid() && traffic->isValid();
service->deleteLater();
traffic->deleteLater();
if (result) { emit simulatorStarted(getPluginInfo()); }
m_conn.disconnectFromPeer(m_conn.name());
} }
void CSimulatorXPlaneListener::serviceRegistered(const QString &serviceName) void CSimulatorXPlaneListener::serviceRegistered(const QString &serviceName)
@@ -1114,6 +1173,7 @@ namespace BlackSimPlugin
{ {
emit simulatorStarted(getPluginInfo()); emit simulatorStarted(getPluginInfo());
} }
m_conn.disconnectFromBus(m_conn.name());
} }
void CSimulatorXPlaneListener::xSwiftBusServerSettingChanged() void CSimulatorXPlaneListener::xSwiftBusServerSettingChanged()

View File

@@ -162,10 +162,18 @@ namespace BlackSimPlugin
} }
//! @} //! @}
private slots:
void serviceUnregistered();
private: private:
enum DBusMode
{
Session,
P2P
};
using QDoubleList = QList<double>; using QDoubleList = QList<double>;
void serviceUnregistered();
void setAirportsInRange(const QStringList &icaoCodes, const QStringList &names, const BlackMisc::CSequence<double> &lats, const BlackMisc::CSequence<double> &lons, const BlackMisc::CSequence<double> &alts); void setAirportsInRange(const QStringList &icaoCodes, const QStringList &names, const BlackMisc::CSequence<double> &lats, const BlackMisc::CSequence<double> &lons, const BlackMisc::CSequence<double> &alts);
void emitOwnAircraftModelChanged(const QString &path, const QString &filename, const QString &livery, const QString &icao, void emitOwnAircraftModelChanged(const QString &path, const QString &filename, const QString &livery, const QString &icao,
const QString &modelString, const QString &name, const QString &description); const QString &modelString, const QString &name, const QString &description);
@@ -215,6 +223,8 @@ namespace BlackSimPlugin
//! Dsiconnect from DBus //! Dsiconnect from DBus
void disconnectFromDBus(); void disconnectFromDBus();
DBusMode m_dbusMode;
BlackMisc::CSettingReadOnly<BlackMisc::Simulation::Settings::TXSwiftBusServer> m_xswiftbusServerSetting { this };
static constexpr qint64 TimeoutAdding = 10000; static constexpr qint64 TimeoutAdding = 10000;
QDBusConnection m_dBusConnection { "default" }; QDBusConnection m_dBusConnection { "default" };
QDBusServiceWatcher *m_watcher { nullptr }; QDBusServiceWatcher *m_watcher { nullptr };
@@ -264,12 +274,16 @@ namespace BlackSimPlugin
virtual void stopImpl() override; virtual void stopImpl() override;
private: private:
//! Check if XSwiftBus service is already registered //! Check if XSwiftBus service is already registered on the bus
bool isXSwiftBusRunning() const; void checkConnectionViaBus(const QString &address);
//! Check if XSwiftBus service is available via P2P address
void checkConnectionViaPeer();
void serviceRegistered(const QString &serviceName); void serviceRegistered(const QString &serviceName);
void xSwiftBusServerSettingChanged(); void xSwiftBusServerSettingChanged();
QTimer m_timer { this };
QDBusConnection m_conn { "default" }; QDBusConnection m_conn { "default" };
QDBusServiceWatcher *m_watcher { nullptr }; QDBusServiceWatcher *m_watcher { nullptr };
BlackMisc::CSettingReadOnly<BlackMisc::Simulation::Settings::TXSwiftBusServer> m_xswiftbusServerSetting { this, &CSimulatorXPlaneListener::xSwiftBusServerSettingChanged }; BlackMisc::CSettingReadOnly<BlackMisc::Simulation::Settings::TXSwiftBusServer> m_xswiftbusServerSetting { this, &CSimulatorXPlaneListener::xSwiftBusServerSettingChanged };

View File

@@ -11,6 +11,11 @@ CONFIG += blackmisc blackcore blackgui blackconfig
DEPENDPATH += . $$SourceRoot/src DEPENDPATH += . $$SourceRoot/src
INCLUDEPATH += . $$SourceRoot/src INCLUDEPATH += . $$SourceRoot/src
unix:!macx {
INCLUDEPATH *= /usr/include/dbus-1.0
INCLUDEPATH *= /usr/lib/x86_64-linux-gnu/dbus-1.0/include
}
SOURCES += *.cpp SOURCES += *.cpp
HEADERS += *.h HEADERS += *.h
DISTFILES += simulatorxplane.json DISTFILES += simulatorxplane.json

View File

@@ -24,6 +24,12 @@ namespace XSwiftBus
dbus_threads_init_default(); dbus_threads_init_default();
} }
CDBusConnection::CDBusConnection(DBusConnection *connection)
{
dbus_connection_ref(connection);
// Don't exit application, if the connection is disconnected
dbus_connection_set_exit_on_disconnect(connection, false);
m_connection.reset(connection);
} }
CDBusConnection::~CDBusConnection() CDBusConnection::~CDBusConnection()

View File

@@ -34,9 +34,12 @@ namespace XSwiftBus
//! Bus type //! Bus type
enum BusType { SessionBus }; enum BusType { SessionBus };
//! Constructor //! Default constructor
CDBusConnection(); CDBusConnection();
//! Constructor
CDBusConnection(DBusConnection *connection);
//! Destructor //! Destructor
~CDBusConnection(); ~CDBusConnection();

View File

@@ -0,0 +1,86 @@
#include <utility>
/* Copyright (C) 2018
* 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 and at http://www.swift-project.org/license.html. 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.
*/
#include "dbusserver.h"
#include "dbusobject.h"
#include "utils.h"
#include <algorithm>
#include <cassert>
#include <memory>
namespace XSwiftBus
{
CDBusServer::CDBusServer()
{
dbus_threads_init_default();
}
CDBusServer::~CDBusServer()
{
close();
}
bool CDBusServer::listen(const std::string &address)
{
DBusError error;
dbus_error_init(&error);
m_server.reset(dbus_server_listen(address.c_str(), &error));
dbus_server_set_new_connection_function(m_server.get(), onNewConnection, this, nullptr);
return true;
}
bool CDBusServer::isConnected() const
{
return dbus_server_get_is_connected(m_server.get());
}
void CDBusServer::close()
{
dbus_server_disconnect(m_server.get());
}
void CDBusServer::setDispatcher(CDBusDispatcher *dispatcher)
{
assert(dispatcher);
m_dispatcher = dispatcher;
dbus_server_set_watch_functions(
m_server.get(),
dispatcher->m_watchCallbacks.add,
dispatcher->m_watchCallbacks.remove,
dispatcher->m_watchCallbacks.toggled,
&dispatcher->m_watchCallbacks, nullptr);
dbus_server_set_timeout_functions(
m_server.get(),
dispatcher->m_timeoutCallbacks.add,
dispatcher->m_timeoutCallbacks.remove,
dispatcher->m_timeoutCallbacks.toggled,
&dispatcher->m_timeoutCallbacks, nullptr);
}
void CDBusServer::onNewConnection(DBusServer *, DBusConnection *conn)
{
INFO_LOG("onNewConnection");
auto dbusConnection = std::make_shared<CDBusConnection>(conn);
m_newConnectionFunc(dbusConnection);
}
void CDBusServer::onNewConnection(DBusServer *server, DBusConnection *conn, void *data)
{
auto *obj = static_cast<CDBusServer *>(data);
return obj->onNewConnection(server, conn);
}
}

View File

@@ -0,0 +1,84 @@
/* Copyright (C) 2018
* 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 and at http://www.swift-project.org/license.html. 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.
*/
#ifndef BLACKSIM_XSWIFTBUS_DBUSSERVER_H
#define BLACKSIM_XSWIFTBUS_DBUSSERVER_H
#include "dbusmessage.h"
#include "dbuserror.h"
#include "dbuscallbacks.h"
#include "dbusdispatcher.h"
#include <event2/event.h>
#include <dbus/dbus.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <memory>
#include <functional>
namespace XSwiftBus
{
class CDBusObject;
//! DBus connection
class CDBusServer : public IDispatchable
{
public:
//! New connection handler function
using NewConnectionFunc = std::function<void(std::shared_ptr<CDBusConnection>)>;
//! Constructor
CDBusServer();
//! Destructor
~CDBusServer();
//! Set the dispatcher
void setDispatcher(CDBusDispatcher *dispatcher);
//! Connect to bus
bool listen(const std::string &address);
//! Is connected?
bool isConnected() const;
void dispatch() {}
//! Close connection
void close();
//! Get the last error
CDBusError lastError() const { return m_lastError; }
//! Set the function to be used for handling new connections.
void setNewConnectionFunc(const NewConnectionFunc &func)
{
m_newConnectionFunc = func;
}
private:
void onNewConnection(DBusServer *server, DBusConnection *conn);
static void onNewConnection(DBusServer *server, DBusConnection *conn, void *data);
struct DBusServerDeleter
{
void operator()(DBusServer *obj) const { dbus_server_unref(obj); }
};
std::unique_ptr<DBusServer, DBusServerDeleter> m_server;
CDBusError m_lastError;
CDBusDispatcher *m_dispatcher;
NewConnectionFunc m_newConnectionFunc;
};
}
#endif // guard

View File

@@ -36,13 +36,13 @@ namespace XSwiftBus
m_planeViewSubMenu = m_menu.subMenu("Follow Plane View"); m_planeViewSubMenu = m_menu.subMenu("Follow Plane View");
planeViewOwnAircraftMenuItem = m_planeViewSubMenu.item("Own Aircraft", [this] { switchToOwnAircraftView(); }); planeViewOwnAircraftMenuItem = m_planeViewSubMenu.item("Own Aircraft", [this] { switchToOwnAircraftView(); });
m_dbusThread = std::thread([this]() /*m_dbusThread = std::thread([this]()
{ {
while(!m_shouldStop) while(!m_shouldStop)
{ {
m_dbusConnection->runBlockingEventLoop(); m_dbusConnection->runBlockingEventLoop();
} }
}); });*/
XPLMRegisterFlightLoopCallback(flightLoopCallback, -1, this); XPLMRegisterFlightLoopCallback(flightLoopCallback, -1, this);
} }
@@ -67,25 +67,47 @@ namespace XSwiftBus
m_traffic->setPlaneViewMenu(m_planeViewSubMenu); m_traffic->setPlaneViewMenu(m_planeViewSubMenu);
// Todo: retry if it fails if (m_useDBusP2P)
bool success = m_dbusConnection->connect(CDBusConnection::SessionBus);
if (!success)
{ {
// Print error m_dbusP2PServer = std::make_unique<CDBusServer>();
return;
// FIXME: make listen address configurable
m_dbusP2PServer->listen("tcp:host=127.0.0.1,port=45000");
m_dbusP2PServer->setDispatcher(&m_dbusDispatcher);
m_dbusP2PServer->setNewConnectionFunc([this](const std::shared_ptr<CDBusConnection> &conn)
{
m_dbusConnection = conn;
m_dbusConnection->setDispatcher(&m_dbusDispatcher);
m_service->setDBusConnection(m_dbusConnection);
m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath());
m_traffic->setDBusConnection(m_dbusConnection);
m_traffic->registerDBusObjectPath(m_traffic->InterfaceName(), m_traffic->ObjectPath());
m_weather->setDBusConnection(m_dbusConnection);
m_weather->registerDBusObjectPath(m_weather->InterfaceName(), m_weather->ObjectPath());
});
} }
else
{
// Todo: retry if it fails
bool success = m_dbusConnection->connect(CDBusConnection::SessionBus);
m_dbusConnection->setDispatcher(&m_dbusDispatcher); if (!success)
m_dbusConnection->requestName(xswiftbusServiceName()); {
// Print error
return;
}
m_service->setDBusConnection(m_dbusConnection); m_dbusConnection->setDispatcher(&m_dbusDispatcher);
m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath()); m_dbusConnection->requestName(xswiftbusServiceName());
m_traffic->setDBusConnection(m_dbusConnection);
m_traffic->registerDBusObjectPath(m_traffic->InterfaceName(), m_traffic->ObjectPath());
m_weather->setDBusConnection(m_dbusConnection);
m_weather->registerDBusObjectPath(m_weather->InterfaceName(), m_weather->ObjectPath());
m_service->setDBusConnection(m_dbusConnection);
m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath());
m_traffic->setDBusConnection(m_dbusConnection);
m_traffic->registerDBusObjectPath(m_traffic->InterfaceName(), m_traffic->ObjectPath());
m_weather->setDBusConnection(m_dbusConnection);
m_weather->registerDBusObjectPath(m_weather->InterfaceName(), m_weather->ObjectPath());
}
INFO_LOG("XSwiftBus started."); INFO_LOG("XSwiftBus started.");
} }

View File

@@ -23,6 +23,7 @@
#include "dbusconnection.h" #include "dbusconnection.h"
#include "dbusdispatcher.h" #include "dbusdispatcher.h"
#include "dbusserver.h"
#include "datarefs.h" #include "datarefs.h"
#include "XPLM/XPLMCamera.h" #include "XPLM/XPLMCamera.h"
#include "menus.h" #include "menus.h"
@@ -55,6 +56,7 @@ namespace XSwiftBus
private: private:
CDBusDispatcher m_dbusDispatcher; CDBusDispatcher m_dbusDispatcher;
std::unique_ptr<CDBusServer> m_dbusP2PServer;
std::shared_ptr<CDBusConnection> m_dbusConnection; std::shared_ptr<CDBusConnection> m_dbusConnection;
std::unique_ptr<CService> m_service; std::unique_ptr<CService> m_service;
std::unique_ptr<CTraffic> m_traffic; std::unique_ptr<CTraffic> m_traffic;
@@ -72,6 +74,8 @@ namespace XSwiftBus
std::thread m_dbusThread; std::thread m_dbusThread;
bool m_shouldStop = false; bool m_shouldStop = false;
bool m_useDBusP2P = true;
void startServer(CDBusConnection::BusType bus); void startServer(CDBusConnection::BusType bus);
void switchToOwnAircraftView(); void switchToOwnAircraftView();