context classes, runtime classes, and related infrastructure

refs #81
This commit is contained in:
Klaus Basan
2014-01-02 00:52:56 +00:00
committed by Mathew Sutcliffe
parent 34774bd005
commit 1f2a88e502
20 changed files with 2641 additions and 49 deletions

View File

@@ -0,0 +1,91 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="blackcore.contextnetwork">
<signal name="statusMessage">
<arg name="message" type="(sii((iii)(iiii)i))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BlackMisc::CStatusMessage"/>
</signal>
<signal name="changedAtcStationsOnline">
</signal>
<signal name="changedAtcStationsBooked">
</signal>
<signal name="changedAircraftsInRange">
</signal>
<signal name="connectionTerminated">
</signal>
<signal name="connectionStatusChanged">
<arg name="from" type="u" direction="out"/>
<arg name="to" type="u" direction="out"/>
</signal>
<signal name="textMessagesReceived">
<arg name="textMessages" type="(a((s)(s)s(dd(s))))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BlackMisc::Network::CTextMessageList"/>
</signal>
<method name="readAtcBookingsFromSource">
</method>
<method name="getAtcStationsOnline">
<arg type="(a((s)(dd(s))(ssss)((dd(s))(dd(s))(dd(s)))(dd(s))(dd(s))b((iii)(iiii)i)((iii)(iiii)i)(si((iii)(iiii)i))(si((iii)(iiii)i))))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::Aviation::CAtcStationList"/>
</method>
<method name="getAtcStationsBooked">
<arg type="(a((s)(dd(s))(ssss)((dd(s))(dd(s))(dd(s)))(dd(s))(dd(s))b((iii)(iiii)i)((iii)(iiii)i)(si((iii)(iiii)i))(si((iii)(iiii)i))))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::Aviation::CAtcStationList"/>
</method>
<method name="getAircraftsInRange">
<arg type="(a((s)(ssss)(((dd(s))(dd(s))(dd(s)))(dd(s)i)(dd(s)i)(dd(s))(dd(s))(dd(s))((iii)(iiii)i))(s(dd(s))(dd(s))i)(s(dd(s))(dd(s))i)(sii)(sssss)(dd(s))))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::Aviation::CAircraftList"/>
</method>
<method name="getOwnAircraft">
<arg type="((s)(ssss)(((dd(s))(dd(s))(dd(s)))(dd(s)i)(dd(s)i)(dd(s))(dd(s))(dd(s))((iii)(iiii)i))(s(dd(s))(dd(s))i)(s(dd(s))(dd(s))i)(sii)(sssss)(dd(s)))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::Aviation::CAircraft"/>
</method>
<method name="connectToNetwork">
<arg type="(a(sii((iii)(iiii)i)))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::CStatusMessages"/>
</method>
<method name="disconnectFromNetwork">
<arg type="(a(sii((iii)(iiii)i)))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::CStatusMessages"/>
</method>
<method name="isConnected">
<arg type="b" direction="out"/>
</method>
<method name="setOwnAircraft">
<arg type="(a(sii((iii)(iiii)i)))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::CStatusMessages"/>
<arg name="aircraft" type="((s)(ssss)(((dd(s))(dd(s))(dd(s)))(dd(s)i)(dd(s)i)(dd(s))(dd(s))(dd(s))((iii)(iiii)i))(s(dd(s))(dd(s))i)(s(dd(s))(dd(s))i)(sii)(sssss)(dd(s)))" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BlackMisc::Aviation::CAircraft"/>
</method>
<method name="updateOwnPosition">
<arg name="position" type="((dd(s))(dd(s))(dd(s)))" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BlackMisc::Geo::CCoordinateGeodetic"/>
<arg name="altitude" type="(dd(s)i)" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="BlackMisc::Aviation::CAltitude"/>
</method>
<method name="updateOwnSituation">
<arg name="situation" type="(((dd(s))(dd(s))(dd(s)))(dd(s)i)(dd(s)i)(dd(s))(dd(s))(dd(s))((iii)(iiii)i))" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BlackMisc::Aviation::CAircraftSituation"/>
</method>
<method name="updateOwnCockpit">
<arg name="com1" type="(s(dd(s))(dd(s))i)" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BlackMisc::Aviation::CComSystem"/>
<arg name="com2" type="(s(dd(s))(dd(s))i)" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="BlackMisc::Aviation::CComSystem"/>
<arg name="transponder" type="(sii)" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="BlackMisc::Aviation::CTransponder"/>
</method>
<method name="sendTextMessages">
<arg name="textMessages" type="(a((s)(s)s(dd(s))))" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BlackMisc::Network::CTextMessageList"/>
</method>
<method name="getMetar">
<arg type="(si((iii)(iiii)i))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::Aviation::CInformationMessage"/>
<arg name="airportIcaoCode" type="s" direction="in"/>
</method>
<method name="ping">
<arg type="x" direction="out"/>
<arg name="token" type="x" direction="in"/>
</method>
</interface>
</node>

View File

@@ -0,0 +1,19 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="blackcore.contextsettings">
<signal name="changedNetworkSettings">
</signal>
<method name="getNetworkSettings">
<arg type="((sssi(ssss))(a(sssi(ssss))))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::Settings::CSettingsNetwork"/>
</method>
<method name="value">
<arg type="(a(sii))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="BlackMisc::CStatusMessages"/>
<arg name="path" type="s" direction="in"/>
<arg name="command" type="s" direction="in"/>
<arg name="value" type="v" direction="in"/>
<arg name="unifiedBlackMetaType" type="i" direction="in"/>
</method>
</interface>
</node>

View File

@@ -1,7 +1,7 @@
include (../../externals.pri)
# GUI is required for the matrix classes
QT += network dbus
QT += network dbus xml
TARGET = blackcore
TEMPLATE = lib
@@ -17,9 +17,24 @@ precompile_header:!isEmpty(PRECOMPILED_HEADER) {
DEFINES += USING_PCH
}
# Causes nmake to run qdbusxml2cpp to automatically generate the dbus adaptor and interface classes,
# then automatically adds them to the sources to compile
# !! Make sure the plugin is available as release build and known QT_PLUGIN_PATH
# QDBUSXML2CPP_INTERFACE_HEADER_FLAGS = -i blackmisc/blackmiscfreefunctions.h -i blackmisc/blackmiscallvalueclasses.h
QDBUSXML2CPP_ADAPTOR_HEADER_FLAGS = -i blackmisc/blackmiscfreefunctions.h -i blackmisc/blackmiscallvalueclasses.h
DBUS_ADAPTORS += blackcore.contextnetwork.xml
DBUS_ADAPTORS += blackcore.contextsettings.xml
# DBUS_INTERFACES += blackcore.contextnetwork.xml
DEFINES += LOG_IN_FILE
HEADERS += *.h
SOURCES += *.cpp
win32:!win32-g++*: PRE_TARGETDEPS += ../../lib/blackmisc.lib
else: PRE_TARGETDEPS += ../../lib/libblackmisc.a
DESTDIR = ../../lib
OTHER_FILES += readme.txt blackcore.contextnetwork.xml blackcore.contextsettings.xml

View File

@@ -0,0 +1,398 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "context_network.h"
#include "coreruntime.h"
#include "blackmisc/avatcstationlist.h"
#include <QtXml/QDomElement>
using namespace BlackMisc;
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Network;
using namespace BlackMisc::Geo;
namespace BlackCore
{
/*
* Init this context
*/
CContextNetwork::CContextNetwork(CCoreRuntime *parent) :
IContextNetwork(parent),
m_atcStationsOnline(), m_atcStationsBooked(), m_aircraftsInRange(),
m_network(nullptr), m_ownAircraft(),
m_metarCache()
{
// 1. Init by "network driver"
this->m_network = new NetworkVatlib(this);
// 2. Init own aircraft
this->initOwnAircraft();
// 3. Init network access driver for XML data (bookings)
this->m_networkManager = new QNetworkAccessManager(this);
this->connect(this->m_networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(psAtcBookingsRead(QNetworkReply *)));
this->m_atcBookingTimer = new QTimer(this);
this->connect(this->m_atcBookingTimer, SIGNAL(timeout()), this, SLOT(readAtcBookingsFromSource()));
this->m_atcBookingTimer->start(15 * 1000);
// 4. connect signals and slots
bool connect = this->connect(this->m_network, SIGNAL(connectionStatusChanged(Cvatlib_Network::connStatus, Cvatlib_Network::connStatus)),
this, SLOT(psFsdConnectionStatusChanged(Cvatlib_Network::connStatus, Cvatlib_Network::connStatus)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect connectionStatusChanged");
connect = this->connect(this->m_network, SIGNAL(terminate()),
this, SLOT(psFsdConnectionTerminated()));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect terminate");
connect = this->connect(this->m_network, SIGNAL(atcPositionUpdate(BlackMisc::Aviation::CCallsign, BlackMisc::PhysicalQuantities::CFrequency, BlackMisc::Geo::CCoordinateGeodetic, BlackMisc::PhysicalQuantities::CLength)),
this, SLOT(psFsdAtcPositionUpdate(BlackMisc::Aviation::CCallsign, BlackMisc::PhysicalQuantities::CFrequency, BlackMisc::Geo::CCoordinateGeodetic, BlackMisc::PhysicalQuantities::CLength)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect atcPositionUpdate");
connect = this->connect(this->m_network, SIGNAL(atisQueryReplyReceived(BlackMisc::Aviation::CCallsign, QString)),
this, SLOT(psFsdAtisQueryReceived(BlackMisc::Aviation::CCallsign, QString)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect atis");
connect = this->connect(this->m_network, SIGNAL(metarReceived(QString)),
this, SLOT(psFsdMetarReceived(QString)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect metar");
connect = this->connect(this->m_network, SIGNAL(nameQueryReplyReceived(BlackMisc::Aviation::CCallsign, QString)),
this, SLOT(psFsdNameQueryReplyReceived(BlackMisc::Aviation::CCallsign, QString)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect name reply");
connect = this->connect(this->m_network, SIGNAL(exception(QString, bool)),
this, SLOT(psVatlibExceptionMessage(QString, bool)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect exception");
connect = this->connect(this->m_network, SIGNAL(aircraftInfoReceived(BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftIcao)),
this, SLOT(psFsdAircraftInfoReceived(BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftIcao)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect aircraft info");
connect = this->connect(this->m_network, SIGNAL(pilotDisconnected(BlackMisc::Aviation::CCallsign)),
this, SLOT(psFsdPilotDisconnected(BlackMisc::Aviation::CCallsign)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect pilot disconnected");
connect = this->connect(this->m_network, SIGNAL(aircraftPositionUpdate(BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituation, BlackMisc::Aviation::CTransponder)),
this, SLOT(psFsdAircraftPositionUpdate(BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituation, BlackMisc::Aviation::CTransponder)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect aircraft position update");
connect = this->connect(this->m_network, SIGNAL(frequencyQueryReplyReceived(BlackMisc::Aviation::CCallsign, BlackMisc::PhysicalQuantities::CFrequency)),
this, SLOT(psFsdFrequencyReceived(BlackMisc::Aviation::CCallsign, BlackMisc::PhysicalQuantities::CFrequency)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect frequency update");
connect = this->connect(this->m_network, SIGNAL(textMessagesReceived(BlackMisc::Network::CTextMessageList)),
this, SLOT(psFsdTextMessageReceived(BlackMisc::Network::CTextMessageList)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect text message");
// relay status message
connect = this->connect(this->m_network, SIGNAL(statusMessage(BlackMisc::CStatusMessage)),
this, SIGNAL(statusMessage(BlackMisc::CStatusMessage)));
Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect status message");
}
/*
* Cleanup
*/
CContextNetwork::~CContextNetwork()
{
if (this->isConnected()) this->disconnectFromNetwork();
this->disconnect(this);
this->disconnect(this->m_network);
}
/*
* Init own aircraft
*/
void CContextNetwork::initOwnAircraft()
{
Q_ASSERT(this->getRuntime());
Q_ASSERT(this->getRuntime()->getIContextSettings());
this->m_ownAircraft.initComSystems();
this->m_ownAircraft.initTransponder();
CAircraftSituation situation(
CCoordinateGeodetic(
CLatitude::fromWgs84("N 049° 18' 17"),
CLongitude::fromWgs84("E 008° 27' 05"),
CLength(0, CLengthUnit::m())),
CAltitude(312, CAltitude::MeanSeaLevel, CLengthUnit::ft())
);
this->m_ownAircraft.setSituation(situation);
this->m_ownAircraft.setPilot(this->getRuntime()->getIContextSettings()->getNetworkSettings().getCurrentNetworkServer().getUser());
// TODO: This would need to come from somewhere (mappings)
// Own callsign, plane ICAO status, model used
this->m_ownAircraft.setCallsign(CCallsign("BLACK"));
this->m_ownAircraft.setIcaoInfo(CAircraftIcao("C172", "L1P", "GA", "GA", "0000ff"));
}
/*
* Connect to network
*/
CStatusMessages CContextNetwork::connectToNetwork()
{
qDebug() << Q_FUNC_INFO;
CStatusMessages msgs;
CServer currentServer = this->getRuntime()->getIContextSettings()->getNetworkSettings().getCurrentNetworkServer();
if (!currentServer.getUser().isValid())
{
msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "Invalid user credentials"));
}
//else if (!this->m_network->isDisconnected())
//{
// msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "Already connected"));
//}
else
{
this->m_ownAircraft.setPilot(currentServer.getUser());
this->m_network->setServer(currentServer);
//this->m_network->setOwnAircraft(this->m_ownAircraft);
this->m_network->initiateConnection();
QString msg = "Connection pending ";
msg.append(" ").append(currentServer.getAddress()).append(" ").append(QString::number(currentServer.getPort()));
msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, msg));
}
return msgs;
}
/*
* Disconnect from network
*/
CStatusMessages CContextNetwork::disconnectFromNetwork()
{
qDebug() << Q_FUNC_INFO;
CStatusMessages msgs;
//if (this->m_network->isDisconnected())
//{
// msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "Already disconnected"));
//}
//else
{
this->m_network->terminateConnection();
this->m_aircraftsInRange.clear();
this->m_atcStationsBooked.clear();
this->m_atcStationsOnline.clear();
this->m_metarCache.clear();
msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, "Connection terminating"));
}
return msgs;
}
/*
* Connected
*/
bool CContextNetwork::isConnected() const
{
return false;
}
/*
* Own's plane position update
*/
void CContextNetwork::sendOwnAircraftCheckedPositionUpdateToNetwork() const
{
// TODO: Would this logic go into network_vatlib?
// 1. Check not sending to many updates
// 2. Send as pull update to intermediate update
// 3. Same position, no update?
// ...
// this->log(Q_FUNC_INFO, this->m_ownAircraft.toQString());
// this->m_network->sendAircraftUpdate(this->m_ownAircraft);
}
/*
* Own Aircraft
*/
CStatusMessages CContextNetwork::setOwnAircraft(const BlackMisc::Aviation::CAircraft &aircraft)
{
this->log(Q_FUNC_INFO, aircraft.toQString());
CStatusMessages msgs;
//if (this->m_network->isDisconnected())
//{
// this->m_ownAircraft = aircraft;
//}
//else
{
msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "Cannot set plane info, network already connected"));
}
return msgs;
}
/*
* Own Aircraft details
*/
CStatusMessages CContextNetwork::sendOwnAircraftDetails()
{
#if 0
CStatusMessages msgs;
if (this->m_network->isDisconnected() && false)
{
msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "Cannot send plane info, network not connected"));
}
else if (!this->m_ownAircraft.isValidForLogin())
{
msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "Cannot send plane info, own aircraft is invalid"));
}
else
{
// TODO: really sending plane info ??
// NOPE: this->m_network->sendAircraftInfo(this->m_ownAircraft);
this->sendOwnAircraftCheckedPositionUpdateToNetwork();
QString m("Aircraft send ");
m.append(this->m_ownAircraft.toQString(true));
msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, m));
}
return msgs;
#endif // 0
return CStatusMessages();
}
/*
* Own position
*/
void CContextNetwork::updateOwnPosition(const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::Aviation::CAltitude &altitude)
{
if (position == this->m_ownAircraft.getPosition() && altitude == this->m_ownAircraft.getAltitude()) return;
this->m_ownAircraft.setPosition(position);
this->m_ownAircraft.setAltitude(altitude);
this->sendOwnAircraftCheckedPositionUpdateToNetwork();
}
/*
* Update own situation
*/
void CContextNetwork::updateOwnSituation(const BlackMisc::Aviation::CAircraftSituation &situation)
{
if (situation == this->m_ownAircraft.getSituation()) return;
this->m_ownAircraft.setSituation(situation);
this->sendOwnAircraftCheckedPositionUpdateToNetwork();
}
/*
* Own cockpit data
*/
void CContextNetwork::updateOwnCockpit(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2, const BlackMisc::Aviation::CTransponder &transponder)
{
bool changed = false;
if (com1 != this->m_ownAircraft.getCom1System())
{
this->m_ownAircraft.setCom1System(com1);
changed = true;
}
if (com2 != this->m_ownAircraft.getCom2System())
{
this->m_ownAircraft.setCom2System(com2);
changed = true;
}
if (transponder != this->m_ownAircraft.getTransponder())
{
this->m_ownAircraft.setTransponder(transponder);
changed = true;
}
if (!changed) return;
//this->m_network->updateOwnCockpit(com1, com2, transponder);
}
/*
* Own aircraft
*/
CAircraft CContextNetwork::getOwnAircraft() const
{
this->log(Q_FUNC_INFO, this->m_ownAircraft.toQString());
return this->m_ownAircraft;
}
/*
* Send text messages
*/
void CContextNetwork::sendTextMessages(const CTextMessageList &textMessages)
{
this->log(Q_FUNC_INFO, textMessages.toQString());
this->m_network->sendTextMessages(textMessages);
}
/*
* Connection terminated
*/
void CContextNetwork::psFsdConnectionTerminated()
{
emit this->statusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, "connection terminated"));
emit this->connectionTerminated();
}
/*
* Connection status changed
*/
void CContextNetwork::psFsdConnectionStatusChanged(Cvatlib_Network::connStatus from, Cvatlib_Network::connStatus to)
{
ConnectionStatus fromCs = static_cast<ConnectionStatus>(from);
ConnectionStatus toCs = static_cast<ConnectionStatus>(to);
CStatusMessages msgs;
// send 1st position
if (toCs == CContextNetwork::ConnectionStatusConnected)
{
msgs = this->sendOwnAircraftDetails();
}
// send as message
QString m("connection status changed ");
m.append(this->connectionStatusToString(fromCs)).
append(" ").
append(this->connectionStatusToString(toCs));
qDebug() << m;
msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork,
toCs == ConnectionStatusError ? CStatusMessage::SeverityError : CStatusMessage::SeverityInfo, m));
emit this->statusMessage(msgs.at(0));
// send as own signal
emit this->connectionStatusChanged(fromCs, toCs);
}
/*
* Name query
*/
void CContextNetwork::psFsdNameQueryReplyReceived(const CCallsign &callsign, const QString &realname)
{
this->log(Q_FUNC_INFO, callsign.toQString(), realname);
if (realname.isEmpty()) return;
CValueMap vm(CAtcStation::IndexControllerRealname, realname);
this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsign, vm);
this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsign, vm);
vm = CValueMap(CAircraft::IndexPilotRealname, realname);
this->m_aircraftsInRange.applyIf(&CAircraft::getCallsign, callsign, vm);
}
/*
* Ping, is DBus alive?
*/
qint64 CContextNetwork::ping(qint64 token) const
{
return token;
}
/*
* Exception to status message
*/
void CContextNetwork::psVatlibExceptionMessage(const QString &message, bool fatal)
{
CStatusMessage msg(CStatusMessage::TypeTrafficNetwork,
fatal ? CStatusMessage::SeverityError : CStatusMessage::SeverityWarning, message);
emit this->statusMessage(msg);
}
} // namespace

View File

@@ -0,0 +1,354 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BLACKCORE_CONTEXTNETWORK_H
#define BLACKCORE_CONTEXTNETWORK_H
#include "blackcore/dbus_server.h"
#include "blackcore/network_vatlib.h"
#include "blackcore/context_network_interface.h"
#include "blackmisc/avallclasses.h"
#include "blackmisc/statusmessage.h"
#include "blackmisc/statusmessages.h"
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTimer>
#include <QMap>
#define BLACKCORE_CONTEXTNETWORK_INTERFACENAME "blackcore.contextnetwork"
namespace BlackCore
{
class CCoreRuntime;
/*!
* \brief Network context
*/
class CContextNetwork : public IContextNetwork
{
// Register by same name, make signals sender independent
// http://dbus.freedesktop.org/doc/dbus-faq.html#idp48032144
Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTNETWORK_INTERFACENAME)
Q_OBJECT
public:
/*!
* \brief With link to server
* \param server
*/
CContextNetwork(CCoreRuntime *parent);
/*!
* \brief Destructor
*/
virtual ~CContextNetwork();
/*!
* \brief Register myself in DBus
* \param server
*/
void registerWithDBus(CDBusServer *server)
{
server->addObject(IContextNetwork::ServicePath(), this);
}
/*!
* \brief Runtime
* \return
*/
const CCoreRuntime *getRuntime() const
{
return reinterpret_cast<CCoreRuntime *>(this->parent());
}
/*!
* \brief Using local objects?
* \return
*/
virtual bool usingLocalObjects() const { return true; }
public slots:
/*!
* \brief Read ATC bookings
* \return
*/
virtual void readAtcBookingsFromSource() const;
/*!
* \brief The "central" ATC list with online ATC controllers
* \return
*/
// If I make this &getAtcStations XML is not generated correctly
// needs to be crosschecked with the latest version of Qt
virtual const BlackMisc::Aviation::CAtcStationList getAtcStationsOnline() const
{
this->log(Q_FUNC_INFO);
return m_atcStationsOnline;
}
/*!
* \brief ATC list, with booked controllers
* \return
*/
// If I make this &getAtcStations XML is not generated correctly
virtual const BlackMisc::Aviation::CAtcStationList getAtcStationsBooked() const
{
this->log(Q_FUNC_INFO);
return m_atcStationsBooked;
}
/*!
* \brief Aircraft list
* \return
*/
// If I make this &getAtcStations XML is not generated correctly
virtual const BlackMisc::Aviation::CAircraftList getAircraftsInRange() const
{
this->log(Q_FUNC_INFO);
return m_aircraftsInRange;
}
/*!
* \brief Connect to Network
* \return
*/
virtual BlackMisc::CStatusMessages connectToNetwork();
/*!
* \brief Disconnect from network
* \return
*/
virtual BlackMisc::CStatusMessages disconnectFromNetwork();
/*!
* \brief Network connected?
* \return
*/
virtual bool isConnected() const;
/*!
* \brief Set own aircraft
* \param aircraft
* \return
*/
virtual BlackMisc::CStatusMessages setOwnAircraft(const BlackMisc::Aviation::CAircraft &aircraft);
/*!
* \brief Update own position
* \param position
* \param altitude
*/
virtual void updateOwnPosition(const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::Aviation::CAltitude &altitude);
/*!
* \brief Update own situation
* \param situation
*/
virtual void updateOwnSituation(const BlackMisc::Aviation::CAircraftSituation &situation);
/*!
* \brief Update own cockpit
* \param com1
* \param com2
* \param transponder
*/
virtual void updateOwnCockpit(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2, const BlackMisc::Aviation::CTransponder &transponder);
/*!
* \brief Get own aircraft
* \return
*/
virtual BlackMisc::Aviation::CAircraft getOwnAircraft() const;
/*!
* \brief Text messages (also private chat messages)
* \param textMessage
*/
virtual void sendTextMessages(const BlackMisc::Network::CTextMessageList &textMessages);
/*!
* \brief Request METAR
* \param airportIcaoCode
*/
virtual BlackMisc::Aviation::CInformationMessage getMetar(const QString &airportIcaoCode);
/*!
* \brief Used to check if network is alive
* \param token
* \return
*/
virtual qint64 ping(qint64 token) const;
private:
BlackMisc::Aviation::CAtcStationList m_atcStationsOnline;
BlackMisc::Aviation::CAtcStationList m_atcStationsBooked;
BlackMisc::Aviation::CAircraftList m_aircraftsInRange;
BlackCore::INetwork *m_network;
BlackMisc::Aviation::CAircraft m_ownAircraft;
QMap<QString, BlackMisc::Aviation::CInformationMessage> m_metarCache;
// for reading XML
QNetworkAccessManager *m_networkManager;
QTimer *m_atcBookingTimer;
QDateTime m_atcBookingsUpdateTimestamp;
/*!
* \brief Replace value by new values, but keep object itself intact
* \param newStations
*/
void setAtcStationsBooked(const BlackMisc::Aviation::CAtcStationList &newStations);
/*!
* \brief Replace value by new values, but keep object itself intact
* \param newStations
*/
void setAtcStationsOnline(const BlackMisc::Aviation::CAtcStationList &newStations);
/*!
* \brief The "central" ATC list with online ATC controllers
* \return
*/
BlackMisc::Aviation::CAtcStationList &atcStationsOnline()
{
return m_atcStationsOnline;
}
/*!
* \brief ATC list, with booked controllers
* \return
*/
BlackMisc::Aviation::CAtcStationList &atcStationsBooked()
{
return m_atcStationsBooked;
}
/*!
* \brief Check position update before sending to network
*/
void sendOwnAircraftCheckedPositionUpdateToNetwork() const;
/*!
* \brief Own aircraft details
* \param aircraft
* \return
*/
BlackMisc::CStatusMessages sendOwnAircraftDetails();
/*!
* \brief Init my very onw aircraft
*/
void initOwnAircraft();
private slots:
/*!
* \brief Terminated connection
*/
void psFsdConnectionTerminated();
/*!
* \brief Connection status changed
* \param from
* \param to
*/
void psFsdConnectionStatusChanged(Cvatlib_Network::connStatus from, Cvatlib_Network::connStatus to);
/*!
* \brief ATC position update
* \param callsign
* \param frequency
* \param position
* \param range
*/
void psFsdAtcPositionUpdate(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &frequency, const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::PhysicalQuantities::CLength &range);
/*!
* \brief Controller disconnected
* \param callsign
*/
void psFsdAtcControllerDisconnected(const BlackMisc::Aviation::CCallsign &callsign);
/*!
* \brief ATIS received
* \param callsign
* \param atisMessage
*/
void psFsdAtisQueryReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &atisMessage);
/*!
* \brief METAR received
* \param metarMessage
*/
void psFsdMetarReceived(const QString &metarMessage);
/*!
* \brief Realnname recevied
* \param callsign
* \param realname
*/
void psFsdNameQueryReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &realname);
/*!
* \brief Plane info received
* \param callsign
* \param icaoData
*/
void psFsdAircraftInfoReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftIcao &icaoData);
/*!
* \brief Aircraft position update
* \param callsign
* \param situation
* \param transponder
*/
void psFsdAircraftPositionUpdate(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Aviation::CTransponder &transponder);
/*!
* \brief Pilot disconnected
* \param callsign
*/
void psFsdPilotDisconnected(const BlackMisc::Aviation::CCallsign &callsign);
/*!
* \brief Frequency received
* \param callsign
* \param frequency
*/
void psFsdFrequencyReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &frequency);
/*!
* \brief Radio text message received
* \param callsign
* \param message
* \param frequencies
*/
void psFsdTextMessageReceived(const BlackMisc::Network::CTextMessageList &messages);
/*!
* \brief Bookings via XML read
* \param nwReply
* TODO: encapsulate reading from WWW in some class
*/
void psAtcBookingsRead(QNetworkReply *nwReply);
/*!
* \brief Exception message
* \param message
* \param fatal
*/
void psVatlibExceptionMessage(const QString &message, bool fatal);
};
}
// Declaring BlackCore::CContextNetwork * crashed when reading data
Q_DECLARE_METATYPE(BlackCore::CContextNetwork::ConnectionStatus)
#endif // guard

View File

@@ -0,0 +1,101 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "context_network.h"
#include "coreruntime.h"
#include "blackmisc/predicates.h"
using namespace BlackMisc;
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Network;
using namespace BlackMisc::Geo;
namespace BlackCore
{
/*
* Aircraft info received
*/
void CContextNetwork::psFsdAircraftInfoReceived(const CCallsign &callsign, const CAircraftIcao &icaoData)
{
this->log(Q_FUNC_INFO, callsign.toQString(), icaoData.toQString());
CAircraftList aircraftsWithCallsign = this->m_aircraftsInRange.findByCallsign(callsign);
if (aircraftsWithCallsign.isEmpty())
{
// new aircraft
CAircraft aircraft;
aircraft.setCallsign(callsign);
aircraft.setIcaoInfo(icaoData);
aircraft.calculcateDistanceToPlane(this->m_ownAircraft.getPosition());
this->m_aircraftsInRange.insert(aircraft);
emit this->m_network->sendFrequencyQuery(callsign);
emit this->m_network->sendNameQuery(callsign);
emit this->changedAircraftsInRange();
}
else
{
// update
CValueMap vm(CAircraft::IndexIcao, icaoData.toQVariant());
this->m_aircraftsInRange.applyIf(BlackMisc::Predicates::MemberEqual<CAircraft>(&CAircraft::getCallsign, callsign), vm);
emit this->changedAircraftsInRange();
}
}
/*
* Aircraft update received
*/
void CContextNetwork::psFsdAircraftPositionUpdate(const CCallsign &callsign, const CAircraftSituation &situation, const CTransponder &transponder)
{
this->log(Q_FUNC_INFO, callsign.toQString(), situation.toQString(), transponder.toQString());
CAircraftList list = this->m_aircraftsInRange.findByCallsign(callsign);
if (list.isEmpty())
{
// new aircraft
CAircraft aircraft;
aircraft.setCallsign(callsign);
aircraft.setSituation(situation);
aircraft.setTransponder(transponder);
aircraft.calculcateDistanceToPlane(this->m_ownAircraft.getPosition());
this->m_aircraftsInRange.insert(aircraft);
emit this->m_network->sendFrequencyQuery(callsign);
emit this->m_network->sendNameQuery(callsign);
emit this->m_network->requestAircraftInfo(callsign);
emit this->changedAircraftsInRange();
}
else
{
// update
CValueMap vm;
vm.addValue(CAircraft::IndexTransponder, transponder);
vm.addValue(CAircraft::IndexSituation, situation);
this->m_aircraftsInRange.applyIf(BlackMisc::Predicates::MemberEqual<CAircraft>(&CAircraft::getCallsign, callsign), vm);
emit this->changedAircraftsInRange();
}
}
/*
* Pilot disconnected
*/
void CContextNetwork::psFsdPilotDisconnected(const CCallsign &callsign)
{
this->log(Q_FUNC_INFO, callsign.toQString());
this->m_aircraftsInRange.removeIf(&CAircraft::getCallsign, callsign);
}
/*
* Frequency received
*/
void CContextNetwork::psFsdFrequencyReceived(const CCallsign &callsign, const CFrequency &frequency)
{
this->log(Q_FUNC_INFO, callsign.toQString(), frequency.toQString());
// update
CValueMap vm(CAircraft::IndexFrequencyCom1, frequency.toQVariant());
this->m_aircraftsInRange.applyIf(BlackMisc::Predicates::MemberEqual<CAircraft>(&CAircraft::getCallsign, callsign), vm);
emit this->changedAircraftsInRange();
}
} // namespace

View File

@@ -0,0 +1,238 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "context_network.h"
#include "coreruntime.h"
#include "blackmisc/avatcstationlist.h"
#include "blackmisc/predicates.h"
#include <QMetaEnum>
#include <QUrl>
#include <QNetworkRequest>
#include <QXmlStreamReader>
#include <QtXml/QDomElement>
using namespace BlackMisc;
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Network;
using namespace BlackMisc::Geo;
namespace BlackCore
{
/*
* Read bookings
*/
void CContextNetwork::readAtcBookingsFromSource() const
{
QUrl url("http://vatbook.euroutepro.com/xml2.php");
QNetworkRequest request(url);
this->m_networkManager->get(request);
}
/*
* Booked stations
*/
void CContextNetwork::setAtcStationsBooked(const BlackMisc::Aviation::CAtcStationList &newStations)
{
this->m_atcStationsBooked = newStations;
}
/*
* Online stations
*/
void CContextNetwork::setAtcStationsOnline(const BlackMisc::Aviation::CAtcStationList &newStations)
{
this->m_atcStationsOnline = newStations;
}
/*
* Request METAR
*/
BlackMisc::Aviation::CInformationMessage CContextNetwork::getMetar(const QString &airportIcaoCode)
{
CInformationMessage metar;
QString icao = airportIcaoCode.trimmed().toUpper();
if (icao.length() != 4) return metar;
if (this->m_metarCache.contains(icao)) metar = this->m_metarCache[icao];
if (metar.isEmpty() || metar.timeDiffReceivedMs() > 10 * 1000)
{
// outdated, or not in cache at all
this->m_network->requestMetar(airportIcaoCode.trimmed().toUpper());
// with this little trick we try to make an asynchronous signal / slot
// based approach a synchronous return value
QTime waitForMetar = QTime::currentTime().addMSecs(1000);
while (QTime::currentTime() < waitForMetar)
{
// process some other events and hope network answer is received already
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
if (m_metarCache.contains(icao))
{
metar = this->m_metarCache[icao];
break;
}
}
}
return metar;
}
/*
* ATC Position update
*/
void CContextNetwork::psFsdAtcPositionUpdate(const CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &frequency, const CCoordinateGeodetic &position, const BlackMisc::PhysicalQuantities::CLength &range)
{
this->log(Q_FUNC_INFO, callsign.toQString(), frequency.toQString(), position.toQString(), range.toQString());
CAtcStationList stationsWithCallsign = this->m_atcStationsOnline.findByCallsign(callsign);
if (stationsWithCallsign.isEmpty())
{
// new station
CAtcStation station;
station.setCallsign(callsign);
station.setRange(range);
station.setFrequency(frequency);
station.setPosition(position);
station.setOnline(true);
station.calculcateDistanceToPlane(this->m_ownAircraft.getPosition());
this->m_atcStationsOnline.insert(station);
emit this->changedAtcStationsOnline();
emit this->m_network->sendAtisQuery(callsign); // request ATIS
emit this->m_network->sendNameQuery(callsign);
}
else
{
// update
CValueMap values;
values.addValue(CAtcStation::IndexFrequency, frequency);
values.addValue(CAtcStation::IndexPosition, position);
values.addValue(CAtcStation::IndexRange, range);
this->m_atcStationsOnline.applyIf(BlackMisc::Predicates::MemberEqual<CAtcStation>(&CAtcStation::getCallsign, callsign), values);
emit this->changedAtcStationsOnline();
}
}
/*
* ATC Controller disconnected
*/
void CContextNetwork::psFsdAtcControllerDisconnected(const CCallsign &callsign)
{
this->log(Q_FUNC_INFO, callsign.toQString());
this->m_atcStationsOnline.removeIf(&CAtcStation::getCallsign, callsign);
emit this->changedAtcStationsOnline();
this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsign, CValueMap(CAtcStation::IndexIsOnline, QVariant(false)));
}
/*
* ATIS received
*/
void CContextNetwork::psFsdAtisQueryReceived(const CCallsign &callsign, const QString &atisMessage)
{
this->log(Q_FUNC_INFO, callsign.toQString(), atisMessage);
CValueMap vm(CAtcStation::IndexAtisMessage, atisMessage);
this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsign, vm);
this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsign, vm);
}
/*
* Metar received
*/
void CContextNetwork::psFsdMetarReceived(const QString &metarMessage)
{
this->log(Q_FUNC_INFO, metarMessage);
if (metarMessage.length() < 10) return; // invalid
const QString icaoCode = metarMessage.left(4).toUpper();
const QString icaoCodeTower = icaoCode + "_TWR";
CCallsign callsignTower(icaoCodeTower);
CInformationMessage metar(CInformationMessage::METAR, metarMessage);
// add METAR to existing stations
CValueMap vm(CAtcStation::IndexMetar, metar.toQVariant());
this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsignTower, vm);
this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsignTower, vm);
this->m_metarCache.insert(icaoCode, metar);
}
/*
* Bookings read from XML
* TODO: encapsulate reading from WWW in some class
*/
void CContextNetwork::psAtcBookingsRead(QNetworkReply *nwReply)
{
if (nwReply->error() == QNetworkReply::NoError)
{
QString xmlData = nwReply->readAll();
QDomDocument doc;
if (doc.setContent(xmlData))
{
QDomNode atc = doc.elementsByTagName("atcs").at(0);
QDomNodeList bookingNodes = atc.toElement().elementsByTagName("booking");
int size = bookingNodes.size();
CSequence<CAtcStation> stations;
for (int i = 0; i < size; i++)
{
QDomNode bookingNode = bookingNodes.at(i);
QDomNodeList bookingNodeValues = bookingNode.childNodes();
CAtcStation bookedStation;
CUser user;
for (int v = 0; v < bookingNodeValues.size(); v++)
{
QDomNode bookingNodeValue = bookingNodeValues.at(v);
QString name = bookingNodeValue.nodeName().toLower();
QString value = bookingNodeValue.toElement().text();
if (name == "id")
{
// could be used as unique key
}
else if (name == "callsign")
{
bookedStation.setCallsign(CCallsign(value));
}
else if (name == "name")
{
user.setRealname(value);
}
else if (name == "cid")
{
user.setId(value);
}
else if (name == "time_end")
{
QDateTime t = QDateTime::fromString(value, "yyyy-MM-dd HH:mm:ss");
bookedStation.setBookedUntilUtc(t);
}
else if (name == "time_start")
{
QDateTime t = QDateTime::fromString(value, "yyyy-MM-dd HH:mm:ss");
bookedStation.setBookedFromUtc(t);
}
}
// time checks
QDateTime now = QDateTime::currentDateTimeUtc();
if (now.msecsTo(bookedStation.getBookedUntilUtc()) < (1000 * 60 * 15)) continue; // until n mins in past
if (now.msecsTo(bookedStation.getBookedFromUtc()) > (1000 * 60 * 60 * 24)) continue; // to far in the future, n hours
// booking does not have position, so distance cannot be calculated
// bookedStation.calculcateDistanceToPlane(this->m_ownAircraft.getPosition());
bookedStation.setController(user);
// consolidate and append
this->m_atcStationsOnline.mergeWithBooking(bookedStation);
stations.insert(bookedStation);
}
nwReply->close();
nwReply->deleteLater();
// set the new values
if (this->getAtcStationsBooked() != stations)
{
this->atcStationsBooked() = stations;
emit this->changedAtcStationsBooked();
}
} // node
} // content
} // method
} // namespace

View File

@@ -0,0 +1,194 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "blackcore/context_network_interface.h"
#include <QObject>
#include <QMetaEnum>
#include <QDBusConnection>
namespace BlackCore
{
/*
* Constructor for DBus
*/
IContextNetwork::IContextNetwork(const QString &serviceName, QDBusConnection &connection, QObject *parent) : QObject(parent), m_dBusInterface(0)
{
this->m_dBusInterface = new BlackMisc::CGenericDBusInterface(
serviceName , IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
connection, this);
this->relaySignals(serviceName, connection);
}
/*
* Workaround for signals, not working without, but why?
*/
void IContextNetwork::relaySignals(const QString &serviceName, QDBusConnection &connection)
{
connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
"connectionStatusChanged", this, SIGNAL(connectionStatusChanged(uint, uint)));
connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
"changedAtcStationsBooked", this, SIGNAL(changedAtcStationsBooked()));
connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
"changedAtcStationsOnline", this, SIGNAL(changedAtcStationsOnline()));
connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
"connectionTerminated", this, SIGNAL(connectionTerminated()));
connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
"statusMessage", this, SIGNAL(statusMessage(BlackMisc::CStatusMessage)));
connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
"textMessagesReceived", this, SIGNAL(textMessagesReceived(BlackMisc::Network::CTextMessageList)));
}
/*
* Clear text of status
*/
QString IContextNetwork::connectionStatusToString(ConnectionStatus status) const
{
int index = metaObject()->indexOfEnumerator("ConnectionStatus");
QMetaEnum metaEnum = metaObject()->enumerator(index);
return metaEnum.valueToKey(status);
}
/*
* Relay to DBus
*/
void IContextNetwork::readAtcBookingsFromSource() const
{
this->m_dBusInterface->callDBus(QLatin1Literal("readAtcBookingsFromSource"));
}
/*
* Relay to DBus
*/
const BlackMisc::Aviation::CAtcStationList IContextNetwork::getAtcStationsOnline() const
{
return this->m_dBusInterface->callDBusRet<BlackMisc::Aviation::CAtcStationList>(QLatin1Literal("getAtcStationsOnline"));
}
/*
* Relay to DBus
*/
const BlackMisc::Aviation::CAtcStationList IContextNetwork::getAtcStationsBooked() const
{
return this->m_dBusInterface->callDBusRet<BlackMisc::Aviation::CAtcStationList>(QLatin1Literal("getAtcStationsBooked"));
}
/*
* Relay to DBus
*/
const BlackMisc::Aviation::CAircraftList IContextNetwork::getAircraftsInRange() const
{
return this->m_dBusInterface->callDBusRet<BlackMisc::Aviation::CAircraftList>(QLatin1Literal("getAircraftsInRange"));
}
/*
* Relay to DBus
*/
BlackMisc::Aviation::CAircraft IContextNetwork::getOwnAircraft() const
{
return this->m_dBusInterface->callDBusRet<BlackMisc::Aviation::CAircraft>(QLatin1Literal("getOwnAircraft"));
}
/*
* Relay to DBus
*/
BlackMisc::CStatusMessages IContextNetwork::connectToNetwork()
{
return this->m_dBusInterface->callDBusRet<BlackMisc::CStatusMessages>(QLatin1Literal("connectToNetwork"));
}
/*
* Relay to DBus
*/
BlackMisc::CStatusMessages IContextNetwork::disconnectFromNetwork()
{
return this->m_dBusInterface->callDBusRet<BlackMisc::CStatusMessages>(QLatin1Literal("disconnectFromNetwork"));
}
/*
* Relay to DBus
*/
bool IContextNetwork::isConnected() const
{
qint64 token = QDateTime::currentMSecsSinceEpoch();
if (this->ping(token) != token) return false; // Core cannot be reached
return this->m_dBusInterface->callDBusRet<bool>(QLatin1Literal("isConnected"));
}
/*
* Relay to DBus
*/
BlackMisc::CStatusMessages IContextNetwork::setOwnAircraft(const BlackMisc::Aviation::CAircraft &aircraft)
{
return this->m_dBusInterface->callDBusRet<BlackMisc::CStatusMessages>(QLatin1Literal("setOwnAircraft"), aircraft);
}
/*
* Relay to DBus
*/
void IContextNetwork::updateOwnPosition(const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::Aviation::CAltitude &altitude)
{
this->m_dBusInterface->callDBus(QLatin1Literal("updateOwnPosition"), position, altitude);
}
/*
* Relay to DBus
*/
void IContextNetwork::updateOwnSituation(const BlackMisc::Aviation::CAircraftSituation &situation)
{
this->m_dBusInterface->callDBus(QLatin1Literal("updateOwnSituation"), situation);
}
/*
* Relay to DBus
*/
void IContextNetwork::updateOwnCockpit(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2, const BlackMisc::Aviation::CTransponder &transponder)
{
this->m_dBusInterface->callDBus(QLatin1Literal("updateOwnCockpit"), com1, com2, transponder);
}
/*
* Relay to DBus
*/
void IContextNetwork::sendTextMessages(const BlackMisc::Network::CTextMessageList &textMessages)
{
this->m_dBusInterface->callDBus(QLatin1Literal("sendTextMessages"), textMessages);
}
/*
* Relay to DBus
*/
BlackMisc::Aviation::CInformationMessage IContextNetwork::getMetar(const QString &airportIcaoCode)
{
return this->m_dBusInterface->callDBusRet<BlackMisc::Aviation::CInformationMessage>(QLatin1Literal("requestMetar"), airportIcaoCode);
}
/*
* Ping, is DBus alive?
*/
qint64 IContextNetwork::ping(qint64 token) const
{
return this->m_dBusInterface->callDBusRet<qint64>(QLatin1Literal("ping"), token);
}
/*
* Logging
*/
void IContextNetwork::log(const QString &method, const QString &m1, const QString &m2, const QString &m3, const QString &m4) const
{
if (m1.isEmpty())
qDebug() << " LOG: " << method;
else if (m2.isEmpty())
qDebug() << " LOG: " << method << m1;
else if (m3.isEmpty())
qDebug() << " LOG: " << method << m1 << m2;
else if (m4.isEmpty())
qDebug() << " LOG: " << method << m1 << m2 << m3;
else
qDebug() << " LOG: " << method << m1 << m2 << m3 << m4;
}
} // namespace

View File

@@ -0,0 +1,267 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BLACKCORE_CONTEXTNETWORK_INTERFACE_H
#define BLACKCORE_CONTEXTNETWORK_INTERFACE_H
#include "blackmisc/avallclasses.h"
#include "blackmisc/statusmessage.h"
#include "blackmisc/statusmessages.h"
#include "blackmisc/nwtextmessagelist.h"
#include "blackmisc/genericdbusinterface.h"
#include "blackcore/network_vatlib.h"
#include <QObject>
#include <QDBusAbstractInterface>
#define BLACKCORE_CONTEXTNETWORK_INTERFACENAME "blackcore.contextnetwork"
#define BLACKCORE_CONTEXTNETWORK_SERVICEPATH "/network"
// SERVICENAME must contain at least one ".", otherwise generation fails
// as this is interpreted in the way comain.somename
namespace BlackCore
{
/*!
* \brief The IContextNetwork class
*/
class IContextNetwork : public QObject
{
Q_OBJECT
Q_ENUMS(ConnectionStatus)
Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTNETWORK_INTERFACENAME)
public:
/*!
* \brief Service name
* \return
*/
static const QString &InterfaceName()
{
static QString s(BLACKCORE_CONTEXTNETWORK_INTERFACENAME);
return s;
}
/*!
* \brief Service path
* \return
*/
static const QString &ServicePath()
{
static QString s(BLACKCORE_CONTEXTNETWORK_SERVICEPATH);
return s;
}
/*!
* \brief Qt compliant status
*/
enum ConnectionStatus
{
ConnectionStatusIdle = static_cast<uint>(Cvatlib_Network::connStatus_Idle),
ConnectionStatusConnected = static_cast<uint>(Cvatlib_Network::connStatus_Connected),
ConnectionStatusConnecting = static_cast<uint>(Cvatlib_Network::connStatus_Connecting),
ConnectionStatusDisconnected = static_cast<uint>(Cvatlib_Network::connStatus_Disconnected),
ConnectionStatusError = static_cast<uint>(Cvatlib_Network::connStatus_Error)
};
/*!
* \brief DBus version constructor
* \param serviceName
* \param connection
* \param parent
*/
IContextNetwork(const QString &serviceName, QDBusConnection &connection, QObject *parent = 0);
/*!
* Destructor
*/
~IContextNetwork() {}
/*!
* \brief Using local objects?
* \return
*/
virtual bool usingLocalObjects() const { return false; }
private:
BlackMisc::CGenericDBusInterface *m_dBusInterface;
/*!
* Relay connection signals to local signals
* No idea why this has to be wired and is not done automatically
* \param connection
*/
void relaySignals(const QString &serviceName, QDBusConnection &connection);
protected:
/*!
* \brief IContextNetwork
* \param parent
*/
IContextNetwork(QObject *parent = 0) : QObject(parent), m_dBusInterface(0) {}
/*!
* Connection status as cleartext
*/
QString connectionStatusToString(ConnectionStatus status) const;
/*!
* \brief Helper for logging, likely to be removed / changed
* \param method
* \param m1
* \param m2
* \param m3
* \param m4
*/
void log(const QString &method, const QString &m1 = "", const QString &m2 = "", const QString &m3 = "", const QString &m4 = "") const;
signals:
/*!
* \brief ATC station list has been changed
* \param message
*/
void statusMessage(const BlackMisc::CStatusMessage &message);
/*!
* \brief List has been changed
*/
void changedAtcStationsOnline();
/*!
* \brief ATC station list has been changed
*/
void changedAtcStationsBooked();
/*!
* \brief Aircraft list has been changed
*/
void changedAircraftsInRange();
/*!
* \brief Terminated connection
*/
void connectionTerminated();
/*!
* \brief Connection status changed
* \param from
* \param to
*/
// If I use the enum, adaptor / interface are not created correctly
void connectionStatusChanged(uint from, uint to);
/*!
* \brief Text messages (also private chat messages)
* \param textMessage
*/
void textMessagesReceived(const BlackMisc::Network::CTextMessageList &textMessages);
public slots:
/*!
* \brief Read ATC bookings
* \return
*/
virtual void readAtcBookingsFromSource() const;
/*!
* \brief The "central" ATC list with online ATC controllers
* \return
*/
// If I make this &getAtcStations XML is not generated correctly
virtual const BlackMisc::Aviation::CAtcStationList getAtcStationsOnline() const;
/*!
* \brief ATC list, with booked controllers
* \return
*/
virtual const BlackMisc::Aviation::CAtcStationList getAtcStationsBooked() const;
/*!
* \brief Aircraft list
* \return
*/
virtual const BlackMisc::Aviation::CAircraftList getAircraftsInRange() const;
/*!
* \brief Get own aircraft
* \return
*/
virtual BlackMisc::Aviation::CAircraft getOwnAircraft() const;
/*!
* \brief Connect to Network
* \return
*/
virtual BlackMisc::CStatusMessages connectToNetwork();
/*!
* \brief Disconnect from network
* \return
*/
virtual BlackMisc::CStatusMessages disconnectFromNetwork();
/*!
* \brief Network connected?
* \return
*/
virtual bool isConnected() const;
/*!
* Set own aircraft
* \param aircraft
* \return
*/
virtual BlackMisc::CStatusMessages setOwnAircraft(const BlackMisc::Aviation::CAircraft &aircraft);
/*!
* \brief Own position, be aware height is terrain height
* \param Position
* \param altitude
* \return
*/
virtual void updateOwnPosition(const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::Aviation::CAltitude &altitude);
/*!
* \brief Complete situation update
* \param Situation
* \return
*/
virtual void updateOwnSituation(const BlackMisc::Aviation::CAircraftSituation &situation);
/*!
* \brief Update own cockpit
* \param com1
* \param com2
* \param transponder
*/
virtual void updateOwnCockpit(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2, const BlackMisc::Aviation::CTransponder &transponder);
/*!
* \brief Text messages (radio and private chat messages)
* \param textMessage
*/
virtual void sendTextMessages(const BlackMisc::Network::CTextMessageList &textMessages);
/*!
* \brief Get METAR, if not available request it
* \param airportIcaoCode
* \return
*/
virtual BlackMisc::Aviation::CInformationMessage getMetar(const QString &airportIcaoCode);
/*!
* \brief Ping
* \param token
* \return
*/
virtual qint64 ping(qint64 token) const;
};
}
#endif // guard

View File

@@ -0,0 +1,27 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "context_network.h"
#include "coreruntime.h"
using namespace BlackMisc;
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Network;
using namespace BlackMisc::Geo;
namespace BlackCore
{
/*
* Radio text message received
*/
void CContextNetwork::psFsdTextMessageReceived(const CTextMessageList &messages)
{
if (messages.isEmpty()) return;
this->log(Q_FUNC_INFO, messages.toQString());
this->textMessagesReceived(messages); // relay
}
} // namespace

View File

@@ -0,0 +1,61 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "context_settings.h"
#include "coreruntime.h"
#include "blackmisc/settingutilities.h"
using namespace BlackMisc::Settings;
using namespace BlackMisc::Network;
using namespace BlackMisc;
namespace BlackCore
{
/*
* Init this context
*/
CContextSettings::CContextSettings(CCoreRuntime *parent) : IContextSettings(parent), m_settingsNetwork()
{
// create some dummy settings
// this would actually be reading the settings from disk ..
this->m_settingsNetwork.setCurrentNetworkServer(
CServer("Testserver", "Client project testserver", "vatsim-germany.org", 6809,
CUser("guest", "Guest Client project", "", "guest")));
this->m_settingsNetwork.addTrafficNetworkServer(this->m_settingsNetwork.getCurrentNetworkServer());
this->m_settingsNetwork.addTrafficNetworkServer(
CServer("Europe C2", "Real VATSIM Server", "88.198.19.202", 6809,
CUser("vatsimid", "Black Client", "", "vatsimpw"))
);
}
/*
* Network settings
*/
BlackMisc::Settings::CSettingsNetwork CContextSettings::getNetworkSettings() const
{
return this->m_settingsNetwork;
}
/*
* Pass value
*/
BlackMisc::CStatusMessages CContextSettings::value(const QString &path, const QString &command, const QVariant &value)
{
Q_ASSERT(path.length() > 3);
Q_ASSERT(path.indexOf('/') >= 0);
QString nextLevelPath = CSettingUtilities::removeLeadingPath(path);
BlackMisc::CStatusMessages msgs = CSettingUtilities::wrongPathMessages(path);
bool changed = false;
if (path.startsWith(IContextSettings::PathNetworkSettings()))
{
msgs = this->m_settingsNetwork.value(nextLevelPath, command, value, changed);
if (changed) emit this->changedNetworkSettings();
}
return msgs;
}
} // namespace

View File

@@ -0,0 +1,83 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BLACKCORE_CONTEXTSETTINGS_H
#define BLACKCORE_CONTEXTSETTINGS_H
#include "blackcore/dbus_server.h"
#include "blackcore/context_settings_interface.h"
#include "blackmisc/statusmessage.h"
#include "blackmisc/statusmessages.h"
#include <QObject>
#define BLACKCORE_CONTEXTSETTINGS_INTERFACENAME "blackcore.contextsettings"
namespace BlackCore
{
class CCoreRuntime;
/*!
* \brief Network context
*/
class CContextSettings : public IContextSettings
{
// Register by same name, make signals sender independent
// http://dbus.freedesktop.org/doc/dbus-faq.html#idp48032144
Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTSETTINGS_INTERFACENAME)
Q_OBJECT
public:
/*!
* Context
* \param parent
*/
CContextSettings(CCoreRuntime *parent);
/*!
* Destructor
*/
virtual ~CContextSettings() {}
/*!
* \brief Register myself in DBus
* \param server
*/
void registerWithDBus(CDBusServer *server)
{
server->addObject(IContextSettings::ServicePath(), this);
}
/*!
* \brief Runtime
* \return
*/
const CCoreRuntime *getRuntime() const
{
return reinterpret_cast<CCoreRuntime *>(this->parent());
}
public slots:
/*!
* \brief Network settings
* \return
*/
virtual BlackMisc::Settings::CSettingsNetwork getNetworkSettings() const;
/*!
* \brief Validate
* \param path
* \param value
* \return
*/
virtual BlackMisc::CStatusMessages value(const QString &path, const QString &command, const QVariant &value);
private:
BlackMisc::Settings::CSettingsNetwork m_settingsNetwork;
};
}
#endif // guard

View File

@@ -0,0 +1,70 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "blackcore/context_settings_interface.h"
#include "blackmisc/blackmiscfreefunctions.h"
#include <QObject>
#include <QMetaEnum>
#include <QDBusConnection>
namespace BlackCore
{
/*
* Constructor for DBus
*/
IContextSettings::IContextSettings(const QString &serviceName, QDBusConnection &connection, QObject *parent) : QObject(parent), m_dBusInterface(0)
{
this->m_dBusInterface = new BlackMisc::CGenericDBusInterface(
serviceName , IContextSettings::ServicePath(), IContextSettings::InterfaceName(),
connection, this);
this->relaySignals(serviceName, connection);
}
/*
* Workaround for unreliable signals
*/
void IContextSettings::relaySignals(const QString &serviceName, QDBusConnection &connection)
{
connection.connect(serviceName, IContextSettings::ServicePath(), IContextSettings::InterfaceName(),
"changedNetworkSettings", this, SIGNAL(changedNetworkSettings()));
}
/*
* Relay to DBus
*/
BlackMisc::Settings::CSettingsNetwork IContextSettings::getNetworkSettings() const
{
return this->m_dBusInterface->callDBusRet<BlackMisc::Settings::CSettingsNetwork>(QLatin1Literal("getNetworkSettings"));
}
/*
* Relay to DBus
*/
BlackMisc::CStatusMessages IContextSettings::value(const QString &path, const QString &command, const QVariant &value)
{
int type = value.userType() - BlackMisc::firstBlackMetaType();
return this->m_dBusInterface->callDBusRet<BlackMisc::CStatusMessages>(QLatin1Literal("value"), path, command, QDBusVariant(value), type);
}
/*
* DBus version of value
*/
BlackMisc::CStatusMessages IContextSettings::value(const QString &path, const QString &command, QDBusVariant value, int unifiedBlackMetaType)
{
QVariant qv = value.variant();
if (qv.canConvert<QDBusArgument>())
{
// convert from QDBusArgument
int type = BlackMisc::firstBlackMetaType() + unifiedBlackMetaType; // unify
qv = BlackMisc::fixQVariantFromDbusArgument(qv, type);
}
// when called locally, this will call the virtual method
// of the concrete implementation in context_settings
return this->value(path, command, qv);
}
} // namespace

View File

@@ -0,0 +1,136 @@
/* Copyright (C) 2013 VATSIM Community / authors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BLACKCORE_CONTEXTSETTINGS_INTERFACE_H
#define BLACKCORE_CONTEXTSETTINGS_INTERFACE_H
#include "blackmisc/statusmessages.h"
#include "blackmisc/genericdbusinterface.h"
#include "blackmisc/settingutilities.h"
#include "blackmisc/setnetwork.h"
#include <QObject>
#include <QVariant>
#include <QDBusAbstractInterface>
#define BLACKCORE_CONTEXTSETTINGS_INTERFACENAME "blackcore.contextsettings"
#define BLACKCORE_CONTEXTSETTINGS_SERVICEPATH "/settings"
// SERVICENAME must contain at least one ".", otherwise generation fails
// as this is interpreted in the way comain.somename
namespace BlackCore
{
/*!
* \brief The IContextSettings class
*/
class IContextSettings : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTSETTINGS_INTERFACENAME)
public:
/*!
* \brief Service name
* \return
*/
static const QString &InterfaceName()
{
static QString s(BLACKCORE_CONTEXTSETTINGS_INTERFACENAME);
return s;
}
/*!
* \brief Service path
* \return
*/
static const QString &ServicePath()
{
static QString s(BLACKCORE_CONTEXTSETTINGS_SERVICEPATH);
return s;
}
/*!
* \brief Path
* \return
*/
static const QString &PathNetworkSettings()
{
static QString s("network");
return s;
}
/*!
* \brief DBus version constructor
* \param serviceName
* \param connection
* \param parent
*/
IContextSettings(const QString &serviceName, QDBusConnection &connection, QObject *parent = 0);
/*!
* Destructor
*/
~IContextSettings() {}
private:
BlackMisc::CGenericDBusInterface *m_dBusInterface;
/*!
* \brief Relay connection signals to local signals
* No idea why this has to be wired and is not done automatically
* \param connection
*/
void relaySignals(const QString &serviceName, QDBusConnection &connection);
protected:
/*!
* \brief IContextSettings
* \param parent
*/
IContextSettings(QObject *parent = 0) : QObject(parent), m_dBusInterface(0) {}
signals:
/*!
* \brief Settings have been changed
*/
void changedNetworkSettings();
public slots:
/*!
* \brief Network settings
* \return
*/
virtual BlackMisc::Settings::CSettingsNetwork getNetworkSettings() const;
/*!
* \brief Handle value
* \param path
* \param command
* \param value
* \return
*/
virtual BlackMisc::CStatusMessages value(const QString &path, const QString &command, const QVariant &value);
/*!
* Basically an unwanted signature as this is different from the "local" signature and
* contains explicit DBus types (a: QDbusArgument, b: type for conversion).
* If this can be removed, fine.
*
* \brief value
* \param path
* \param command
* \param value
* \param unifiedBlackMetaType
* \return
*/
virtual BlackMisc::CStatusMessages value(const QString &path, const QString &command, QDBusVariant value, int unifiedBlackMetaType);
};
}
#endif // guard

View File

@@ -0,0 +1,42 @@
#include "blackcore/coreruntime.h"
#include "blackmisc/blackmiscfreefunctions.h"
#include "blackmisc/nwserver.h"
namespace BlackCore
{
/*
* Constructor
*/
CCoreRuntime::CCoreRuntime(bool withDbus, QObject *parent) :
QObject(parent), m_init(false), m_dbusServer(nullptr), m_contextNetwork(nullptr), m_settings(nullptr)
{
this->init(withDbus);
}
/*
* Init runtime
*/
void CCoreRuntime::init(bool withDbus)
{
if (m_init) return;
BlackMisc::registerMetadata();
BlackMisc::initResources();
// TODO: read settings
if (withDbus)
{
QString dBusAddress = "session";
this->m_dbusServer = new CDBusServer(dBusAddress, this);
}
// contexts
this->m_settings = new CContextSettings(this);
if (withDbus) this->m_settings->registerWithDBus(this->m_dbusServer);
this->m_contextNetwork = new CContextNetwork(this);
if (withDbus) this->m_contextNetwork->registerWithDBus(this->m_dbusServer); // complete object after init
// flag
m_init = true;
}
}

View File

@@ -0,0 +1,90 @@
#ifndef BLACKCORE_CORERUNTIME_H
#define BLACKCORE_CORERUNTIME_H
#include <QObject>
#include "dbus_server.h"
#include "context_network.h"
#include "context_settings.h"
namespace BlackCore
{
/*!
* \brief The CCoreRuntime class
*/
class CCoreRuntime : public QObject
{
Q_OBJECT
private:
bool m_init; /*!< flag */
CDBusServer *m_dbusServer;
CContextNetwork *m_contextNetwork;
CContextSettings *m_settings;
/*!
* \brief Init
* \param withDbus
*/
void init(bool withDbus);
public:
/*!
* \brief Constructor
* \param withDbus
* \param parent
*/
CCoreRuntime(bool withDbus = true, QObject *parent = nullptr);
/*!
* \brief Destructor
*/
virtual ~CCoreRuntime() {}
/*!
* \brief DBus server
* \return
*/
const CDBusServer *getDBusServer() const
{
return this->m_dbusServer;
}
/*!
* \brief Context for network
* \return
*/
IContextNetwork *getIContextNetwork()
{
return this->m_contextNetwork;
}
/*!
* \brief Context for network
* \return
*/
const IContextNetwork *getIContextNetwork() const
{
return this->m_contextNetwork;
}
/*!
* \brief Settings
* \return
*/
IContextSettings *getIContextSettings()
{
return this->m_settings;
}
/*!
* \brief Settings
* \return
*/
const IContextSettings *getIContextSettings() const
{
return this->m_settings;
}
};
}
#endif // guard

View File

@@ -4,53 +4,155 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <QDebug>
#include <QMetaClassInfo>
#include "dbus_server.h"
namespace BlackCore
{
const QString CDBusServer::ServiceName = QString(BLACKCORE_DBUSERVER_SERVICENAME);
/*
* Constructor
* Remark, without the default "unix:tmpdir=/tmp" any refereal to address crashes
* see http://download.froglogic.com/public/qt5-squishcoco-report/QtBase/source_241_preprocessed.html
*/
CDBusServer::CDBusServer(const QString &address, QObject *parent) :
QObject(parent), m_busServer(address, parent)
QObject(parent), m_busServer(CDBusServer::isP2P(address) ? address : "unix:tmpdir=/tmp" , parent), m_serverMode(CDBusServer::SERVERMODE_P2P)
{
if (!m_busServer.isConnected())
if (address.isEmpty() || address.toLower() == "session")
{
qWarning() << m_busServer.lastError().message();
// we use a session bus connection instead of a real P2P connection
this->m_serverMode = CDBusServer::SERVERMODE_SESSIONBUS;
QDBusConnection con = QDBusConnection::sessionBus();
if (!con.registerService(CDBusServer::ServiceName))
{
qFatal("Cannot register DBus service");
}
this->newConnection(con);
}
else if (address.toLower() == "system")
{
// we use a system bus connection instead of a real P2P connection
this->m_serverMode = CDBusServer::SERVERMODE_SYSTEMBUS;
QDBusConnection con = QDBusConnection::systemBus();
if (!con.registerService(CDBusServer::ServiceName))
{
qFatal("Cannot register DBus service");
}
this->newConnection(con);
}
else
{
qDebug() << "Server listening on address: " << m_busServer.address();
this->m_serverMode = CDBusServer::SERVERMODE_P2P;
// Note: P2P has no service name
if (!m_busServer.isConnected())
{
qWarning() << m_busServer.lastError().message();
}
else
{
qDebug() << "Server listening on address: " << m_busServer.address();
}
connect(&m_busServer, &QDBusServer::newConnection, this, &CDBusServer::newConnection);
}
connect(&m_busServer, &QDBusServer::newConnection, this, &CDBusServer::newConnection);
}
void CDBusServer::newConnection(const QDBusConnection & connection)
/*
* Check for P2P address
*/
bool CDBusServer::isP2P(const QString &address)
{
QMap<QString, QObject*>::ConstIterator i = m_objects.begin();
return !(address.isEmpty() || address.toLower() == "session" || address.toLower() == "system");
}
/*
* Class info
*/
const QString CDBusServer::getClassInfo(QObject *object)
{
if (!object) return "";
const QMetaObject *mo = object->metaObject();
if (mo->classInfoCount() < 1) return "";
for (int i = 0; i < mo->classInfoCount(); i++)
{
QMetaClassInfo ci = mo->classInfo(i);
QString name(ci.name());
if (name == "D-Bus Interface") return QString(ci.value());
}
return "";
}
/*
* Connection established
*/
bool CDBusServer::newConnection(const QDBusConnection &connection)
{
QMap<QString, QObject *>::ConstIterator i = m_objects.begin();
QDBusConnection newConnection(connection);
m_DBusConnections.insert(newConnection.name(), newConnection);
bool success = true;
qDebug() << "New Connection from: " << newConnection.name();
while (i != m_objects.end())
{
qDebug() << "Adding " << i.key() << "to the new connection.";
newConnection.registerObject(i.key(), i.value());
qDebug() << "Adding " << i.key() << CDBusServer::getClassInfo(i.value()) << "to the new connection.";
bool ok = newConnection.registerObject(i.key(), i.value(), CDBusServer::RegisterOptions());
Q_ASSERT_X(ok, "CDBusServer::newConnection", "Registration failed");
if (!ok) success = false;
++i;
}
return success;
}
void CDBusServer::addObject(const QString &name, QObject *object)
/*
* Add the objects
*/
void CDBusServer::addObject(const QString &path, QObject *object)
{
m_objects.insert(name, object);
if (!object) return;
m_objects.insert(path, object); // this will be added when connection is established
if (this->m_serverMode == CDBusServer::SERVERMODE_P2P) return;
bool success = false;
if (this->m_serverMode == CDBusServer::SERVERMODE_SESSIONBUS)
{
success = QDBusConnection::sessionBus().registerObject(path, object, CDBusServer::RegisterOptions());
qDebug() << "Adding " << path << CDBusServer::getClassInfo(object) << "to the session bus.";
if (!success) qDebug() << "Error, no success with registration" << this->lastError().message();
}
else if (this->m_serverMode == CDBusServer::SERVERMODE_SYSTEMBUS)
{
success = QDBusConnection::systemBus().registerObject(path, object, CDBusServer::RegisterOptions());
qDebug() << "Adding " << path << CDBusServer::getClassInfo(object) << "to the system bus.";
if (!success) qDebug() << "Error, no success with registration" << this->lastError().message();
}
else
{
Q_ASSERT_X(false, "CDBusServer::addObject", "Wrong server mode");
}
// Q_ASSERT_X(success, "CDBusServer::addObject", "Registration failed");
}
void CDBusServer::printError()
/*
* Print last error message
*/
void CDBusServer::printError() const
{
qWarning() << m_busServer.lastError().name();
}
/*
* Last error
*/
QDBusError CDBusServer::lastError() const
{
return this->m_busServer.lastError();
}
} // namespace BlackCore

View File

@@ -6,6 +6,7 @@
#ifndef BLACKCORE_DBUSSERVER_H
#define BLACKCORE_DBUSSERVER_H
#include "blackmisc/valueobject.h" // for qHash overload, include before Qt stuff due GCC issue
#include <QObject>
#include <QtDBus/QDBusServer>
#include <QtDBus/QDBusError>
@@ -13,52 +14,147 @@
#include <QStringList>
#include <QMap>
namespace BlackCore {
#define BLACKCORE_DBUSERVER_SERVICENAME "org.vatsim.pilotClient"
/*!
* \brief Custom DBusServer
* \details This class implements a custom DBusServer for DBus peer connections
*/
namespace BlackCore
{
/*!
* \brief Custom DBusServer
* \details This class implements a custom DBusServer for DBus peer connections
*/
class CDBusServer : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.vatsim.pilotClient")
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", BLACKCORE_DBUSERVER_SERVICENAME)
private:
QDBusServer m_busServer; //!< QDBusServer implementation
public:
static const QString ServiceName;
QMap<QString, QObject*> m_objects; //!< Mapping of all exposed objects
/*!
* \brief Server mode, normally P2P, but can be changed for debugging / testing
*/
enum ServerMode
{
SERVERMODE_P2P,
SERVERMODE_SESSIONBUS,
SERVERMODE_SYSTEMBUS
};
QMap<QString, QDBusConnection> m_DBusConnections; //!< Mapping of all DBusConnection objects
private:
QDBusServer m_busServer; //!< QDBusServer implementation
ServerMode m_serverMode;
QMap<QString, QObject *> m_objects; //!< Mapping of all exposed objects
QMap<QString, QDBusConnection> m_DBusConnections; //!< Mapping of all DBusConnection objects
public:
/*!
* \brief Check if address means a real server with P2P connection
* \param address
* \return
*/
static bool isP2P(const QString &address);
/*!
* \brief Constructor
* \param parent
*/
/*!
* \brief Get the class info
* \param object
* \return
*/
static const QString getClassInfo(QObject *object);
/*!
* \brief Register options with connection
* \return
*/
static const QDBusConnection::RegisterOptions &RegisterOptions()
{
static QDBusConnection::RegisterOptions opt = QDBusConnection::ExportAdaptors | QDBusConnection::ExportAllSignals | QDBusConnection::ExportAllSlots;
return opt;
}
public:
/*!
* \brief Constructor
* \param parent
*/
CDBusServer(const QString &address, QObject *parent = 0);
/*!
* \brief Adds a QObject to be exposed to DBus
* \param name
* \param object
*/
void addObject(const QString &name, QObject *object);
/*!
* \brief Adds a QObject to be exposed to DBus
* \param name
* \param object
*/
void addObject(const QString &name, QObject *object);
void printError();
/*!
* \brief printError
*/
void printError() const;
public slots:
/*!
* \brief Last error
* \return
*/
QDBusError lastError() const;
/*!
* \brief Called when a new DBus client has connected
* \param connection
*/
void newConnection(const QDBusConnection & connection);
signals:
};
/*!
* \brief Connected?
* \return
*/
bool isConnected() const
{
return this->m_busServer.isConnected();
}
/*!
* \brief address
* \return
*/
QString address() const
{
return this->m_busServer.address();
}
/*!
* \brief Connection by name
* \param connectionName
* \return
*/
const QDBusConnection getDbusConnection(const QString &connectionName) const
{
return this->m_DBusConnections.value(connectionName, CDBusServer::defaultConnection());
}
/*!
* \brief Get DBbus connections
* \return
*/
const QList<QDBusConnection> getDbusConnections() const
{
// http://stackoverflow.com/questions/1124340/any-ideas-why-qhash-and-qmap-return-const-t-instead-of-const-t
return this->m_DBusConnections.values();
}
/*!
* \brief Default connection
* \return
*/
static const QDBusConnection &defaultConnection()
{
static QDBusConnection defaultConnection("default");
return defaultConnection;
}
private slots:
/*!
* \brief Called when a new DBus client has connected
* \param connection
* \return
*/
bool newConnection(const QDBusConnection &connection);
};
}
#endif // DBUSSERVER_H
#endif // guard

27
src/blackcore/readme.txt Normal file
View File

@@ -0,0 +1,27 @@
Starting: dbus-daemon.exe --session
- blocks CMD (sometimes daemon continues to run when pressing CTRL/C)
- does not start without directory session.d, i.e. ..\Qt\Qt5.1.0DBus\qtbase\etc\dbus-1\session.d
!!! The includes are set in the qmake file, there are the header files
!!! which are used in the interface
/// qdbuscpp2xml context_network.h -x blackmisc_cpp2xml.dll -o blackcore.contextnetwork.xml
qdbuscpp2xml context_network_interface.h -x blackmisc_cpp2xml.dll -o blackcore.contextnetwork.xml
qdbuscpp2xml context_settings_interface.h -x blackmisc_cpp2xml.dll -o blackcore.contextsettings.xml
Set search path for plugins: env.var. QT_PLUGIN_PATH
Done automatically (qmake), but if required manually
Interface:
qdbusxml2cpp -i blackmisc/blackmiscfreefunctions.h -i blackmisc/blackmiscallvalueclasses.h -p contextnetwork_interface.h: H:\Projects\Qt\VatsimClient\client\src\blackcore\blackcore.contextnetwork.xml
qdbusxml2cpp -i contextnetwork_interface.h -p :contextnetwork_interface.cpp H:\Projects\Qt\VatsimClient\client\src\blackcore\blackcore.contextnetwork.xml
The : indicates generation of cpp file
Adaptor:
qdbusxml2cpp -i blackmisc/blackmiscfreefunctions.h -i blackmisc/blackmiscallvalueclasses.h -a contextnetwork_adaptor.h blackcore.contextnetwork.xml
qdbusxml2cpp -i context_adaptor.h -a :contextnetwork_adaptor.cpp blackcore.contextnetwork.xml
Manually:
<signal name="statusMessage">
<signal name="textMessagesReceived">