Files
pilotclient/src/blackcore/corefacade.cpp
Klaus Basan 96913c6dc1 refs #485, load settings in core facade
Idea: settings will be automatically available
2016-03-18 01:08:18 +00:00

407 lines
17 KiB
C++

/* Copyright (C) 2013
* 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 "blackcore/contextallimpl.h"
#include "blackcore/contextallproxies.h"
#include "blackcore/contextallempties.h"
#include "blackcore/registermetadata.h"
#include "blackmisc/network/server.h"
#include "blackmisc/statusmessagelist.h"
#include "blackmisc/registermetadata.h"
#include "blackmisc/stringutils.h"
#include "blackmisc/logmessage.h"
#include <QMap>
#include <QDebug>
using namespace BlackMisc;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Simulation;
namespace BlackCore
{
CCoreFacade::CCoreFacade(const CCoreFacadeConfig &config, QObject *parent) : QObject(parent)
{
this->init(config);
}
void CCoreFacade::init(const CCoreFacadeConfig &config)
{
if (m_init) { return; }
QMap<QString, int> times;
QTime time;
registerMetadata();
// either use explicit setting or last value
QString dbusAddress;
if (config.hasDBusAddress())
{
dbusAddress = config.getDBusAddress();
m_dbusServerAddress.set(dbusAddress);
}
else
{
dbusAddress = m_dbusServerAddress.get();
}
// DBus
if (config.requiresDBusSever()) { this->initDBusServer(dbusAddress); }
if (config.requiresDBusConnection())
{
this->initDBusConnection(dbusAddress);
if (!this->m_dbusConnection.isConnected())
{
QString notConnected("DBus connection failed:");
QString e = this->m_dbusConnection.lastError().message();
if (!e.isEmpty()) notConnected.append(" ").append(e);
Q_ASSERT_X(false, "CRuntime::init", notConnected.toUtf8().constData());
CLogMessage(this).error(notConnected);
}
}
times.insert("DBus", time.restart());
// contexts
this->m_contextApplication = IContextApplication::create(this, config.getModeApplication(), this->m_dbusServer, this->m_dbusConnection);
times.insert("Application", time.restart());
this->m_contextAudio = IContextAudio::create(this, config.getModeAudio(), this->m_dbusServer, this->m_dbusConnection);
times.insert("Audio", time.restart());
this->m_contextOwnAircraft = IContextOwnAircraft::create(this, config.getModeOwnAircraft(), this->m_dbusServer, this->m_dbusConnection);
times.insert("Own aircraft", time.restart());
this->m_contextNetwork = IContextNetwork::create(this, config.getModeNetwork(), this->m_dbusServer, this->m_dbusConnection);
times.insert("Network", time.restart());
this->m_contextSimulator = IContextSimulator::create(this, config.getModeSimulator(), this->m_dbusServer, this->m_dbusConnection);
times.insert("Simulator", time.restart());
// checks --------------
// 1. own aircraft and simulator should reside in same location
Q_ASSERT(!this->m_contextSimulator || (this->m_contextOwnAircraft->isUsingImplementingObject() == this->m_contextSimulator->isUsingImplementingObject()));
// 2. own aircraft and network should reside in same location
Q_ASSERT(!this->m_contextNetwork || (this->m_contextOwnAircraft->isUsingImplementingObject() == this->m_contextNetwork->isUsingImplementingObject()));
// post inits, wiring things among context (e.g. signal slots)
time.restart();
this->initPostSetup(times);
times.insert("Post setup", time.restart());
CLogMessage(this).info("Init times: %1") << qmapToString(times);
// flag
m_init = true;
}
bool CCoreFacade::hasRemoteApplicationContext() const
{
Q_ASSERT(this->m_contextApplication);
return !this->m_contextApplication->isUsingImplementingObject();
}
void CCoreFacade::registerMetadata()
{
BlackMisc::registerMetadata();
BlackCore::registerMetadata();
}
bool CCoreFacade::parseCommandLine(const QString &commandLine, const CIdentifier &originator)
{
bool handled = false;
if (this->getIContextAudio()) { handled = handled || this->getIContextAudio()->parseCommandLine(commandLine, originator); }
if (this->getIContextNetwork()) { handled = handled || this->getIContextNetwork()->parseCommandLine(commandLine, originator); }
if (this->getIContextOwnAircraft()) { handled = handled || this->getIContextOwnAircraft()->parseCommandLine(commandLine, originator); }
return handled;
}
void CCoreFacade::initDBusServer(const QString &dBusAddress)
{
if (this->m_dbusServer) { return; }
Q_ASSERT(!dBusAddress.isEmpty());
this->m_dbusServer = new CDBusServer(dBusAddress, this);
CLogMessage(this).info("DBus server on address: %1") << dBusAddress;
}
void CCoreFacade::initPostSetup(QMap<QString, int> &times)
{
bool c = false;
Q_UNUSED(c); // for release version
QTime time;
time.start();
times.insert("Post setup, connects first", time.restart());
// local simulator?
if (this->m_contextSimulator && this->m_contextSimulator->isUsingImplementingObject())
{
// only connect if network runs locally, no round trips
if (this->m_contextNetwork && this->m_contextNetwork->isUsingImplementingObject())
{
c = connect(this->m_contextNetwork, &IContextNetwork::textMessagesReceived,
this->getCContextSimulator(), &CContextSimulator::ps_textMessagesReceived);
Q_ASSERT(c);
// use readyForModelMatching instead of CAirspaceMonitor::addedAircraft, as it contains client information
// ready for model matching is sent delayed when all information are available
c = connect(this->m_contextNetwork, &IContextNetwork::readyForModelMatching,
this->getCContextSimulator(), &CContextSimulator::ps_addRemoteAircraft);
Q_ASSERT(c);
c = connect(this->m_contextNetwork, &IContextNetwork::removedAircraft,
this->getCContextSimulator(), &CContextSimulator::ps_removedRemoteAircraft);
Q_ASSERT(c);
c = connect(this->m_contextNetwork, &IContextNetwork::changedRemoteAircraftModel,
this->getCContextSimulator(), &CContextSimulator::ps_changedRemoteAircraftModel);
Q_ASSERT(c);
c = connect(this->m_contextNetwork, &IContextNetwork::changedRemoteAircraftEnabled,
this->getCContextSimulator(), &CContextSimulator::ps_changedRemoteAircraftEnabled);
Q_ASSERT(c);
c = connect(this->getCContextSimulator(), &CContextSimulator::renderRestrictionsChanged,
this->getCContextNetwork(), &CContextNetwork::ps_simulatorRenderRestrictionsChanged);
Q_ASSERT(c);
}
// only if own aircraft runs locally
if (this->m_contextOwnAircraft && this->m_contextOwnAircraft->isUsingImplementingObject())
{
c = connect(this->m_contextOwnAircraft, &IContextOwnAircraft::changedAircraftCockpit,
this->getCContextSimulator(), &CContextSimulator::ps_updateSimulatorCockpitFromContext);
Q_ASSERT(c);
c = connect(this->getCContextSimulator(), &CContextSimulator::ownAircraftModelChanged,
this->getCContextOwnAircraft(), &CContextOwnAircraft::ps_changedSimulatorModel);
Q_ASSERT(c);
}
// settings
if (this->getIContextApplication()) {
this->getIContextApplication()->loadSettings();
}
// times
times.insert("Post setup, sim.connects", time.restart());
}
// only where network and(!) own aircraft run locally
// -> in the core or an all local implementation
if (this->m_contextNetwork && this->m_contextOwnAircraft && this->m_contextNetwork->isUsingImplementingObject() && this->m_contextOwnAircraft->isUsingImplementingObject())
{
c = this->connect(this->m_contextNetwork, &IContextNetwork::changedAtcStationOnlineConnectionStatus,
this->getCContextOwnAircraft(), &CContextOwnAircraft::ps_changedAtcStationOnlineConnectionStatus);
Q_ASSERT(c);
times.insert("Post setup, connects network", time.restart());
}
// fake signals to work around setting values in audio context for local audio with remote core
if (this->m_contextAudio && this->m_contextAudio->isUsingImplementingObject())
{
Q_ASSERT(this->m_contextApplication);
Q_ASSERT(this->m_contextOwnAircraft);
c = this->connect(this->m_contextApplication, &IContextApplication::fakedSetComVoiceRoom,
this->getCContextAudio(), &CContextAudio::setComVoiceRooms);
Q_ASSERT(c);
c = this->connect(this->m_contextOwnAircraft, &IContextOwnAircraft::changedCallsign, this->getCContextAudio(), &IContextAudio::setOwnCallsignForRooms);
Q_ASSERT(c);
times.insert("Post setup, connects audio", time.restart());
}
}
void CCoreFacade::gracefulShutdown()
{
if (!this->m_init) return;
this->m_init = false;
// disable all signals towards runtime
disconnect(this);
// unregister all from DBus
if (this->m_dbusServer) { this->m_dbusServer->removeAllObjects(); }
// handle contexts
if (this->getIContextSimulator())
{
disconnect(this->getIContextSimulator());
if (this->getIContextSimulator()->isUsingImplementingObject())
{
// shutdown the plugins
this->getCContextSimulator()->gracefulShutdown();
}
this->getIContextSimulator()->deleteLater();
QDBusConnection defaultConnection("default");
this->m_contextSimulator = IContextSimulator::create(this, CCoreFacadeConfig::NotUsed, nullptr, defaultConnection);
}
// log off from network, if connected
if (this->getIContextNetwork())
{
disconnect(this->getIContextNetwork());
this->getIContextNetwork()->disconnectFromNetwork();
if (this->m_contextNetwork->isUsingImplementingObject())
{
this->getCContextNetwork()->gracefulShutdown(); // for threads
}
this->getIContextNetwork()->deleteLater();
// replace by dummy object avoiding nullptr issues during shutdown phase
QDBusConnection defaultConnection("default");
this->m_contextNetwork = IContextNetwork::create(this, CCoreFacadeConfig::NotUsed, nullptr, defaultConnection);
}
if (this->getIContextAudio())
{
disconnect(this->getIContextAudio());
this->getIContextAudio()->deleteLater();
// replace by dummy object avoiding nullptr issues during shutdown phase
QDBusConnection defaultConnection("default");
this->m_contextAudio = IContextAudio::create(this, CCoreFacadeConfig::NotUsed, nullptr, defaultConnection);
}
if (this->getIContextOwnAircraft())
{
disconnect(this->getIContextOwnAircraft());
this->getIContextOwnAircraft()->deleteLater();
QDBusConnection defaultConnection("default");
this->m_contextOwnAircraft = IContextOwnAircraft::create(this, CCoreFacadeConfig::NotUsed, nullptr, defaultConnection);
}
if (this->getIContextApplication())
{
disconnect(this->getIContextApplication());
this->getIContextApplication()->deleteLater();
QDBusConnection defaultConnection("default");
this->m_contextApplication = IContextApplication::create(this, CCoreFacadeConfig::NotUsed, nullptr, defaultConnection);
}
}
void CCoreFacade::initDBusConnection(const QString &address)
{
if (this->m_initDBusConnection) { return; }
if (address.isEmpty() || address == CDBusServer::sessionBusAddress())
{
this->m_dbusConnection = QDBusConnection::sessionBus();
}
else if (address == CDBusServer::systemBusAddress())
{
this->m_dbusConnection = QDBusConnection::sessionBus();
}
else
{
this->m_dbusConnection = QDBusConnection::connectToPeer(address, "BlackBoxRuntime");
}
}
const IContextApplication *CCoreFacade::getIContextApplication() const
{
return this->m_contextApplication;
}
IContextApplication *CCoreFacade::getIContextApplication()
{
return this->m_contextApplication;
}
IContextAudio *CCoreFacade::getIContextAudio()
{
return this->m_contextAudio;
}
const IContextAudio *CCoreFacade::getIContextAudio() const
{
return this->m_contextAudio;
}
IContextNetwork *CCoreFacade::getIContextNetwork()
{
return this->m_contextNetwork;
}
const IContextNetwork *CCoreFacade::getIContextNetwork() const
{
return this->m_contextNetwork;
}
IContextOwnAircraft *CCoreFacade::getIContextOwnAircraft()
{
return this->m_contextOwnAircraft;
}
const IContextOwnAircraft *CCoreFacade::getIContextOwnAircraft() const
{
return this->m_contextOwnAircraft;
}
const IContextSimulator *CCoreFacade::getIContextSimulator() const
{
return this->m_contextSimulator;
}
IContextSimulator *CCoreFacade::getIContextSimulator()
{
return this->m_contextSimulator;
}
CContextAudio *CCoreFacade::getCContextAudio()
{
Q_ASSERT_X(this->m_contextAudio && this->m_contextAudio->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextAudio *>(this->m_contextAudio);
}
const CContextAudio *CCoreFacade::getCContextAudio() const
{
Q_ASSERT_X(this->m_contextAudio && this->m_contextAudio->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextAudio *>(this->m_contextAudio);
}
CContextApplication *CCoreFacade::getCContextApplication()
{
Q_ASSERT_X(this->m_contextApplication && this->m_contextApplication->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextApplication *>(this->m_contextApplication);
}
const CContextApplication *CCoreFacade::getCContextApplication() const
{
Q_ASSERT_X(this->m_contextApplication && this->m_contextApplication->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextApplication *>(this->m_contextApplication);
}
CContextNetwork *CCoreFacade::getCContextNetwork()
{
Q_ASSERT_X(this->m_contextNetwork && this->m_contextNetwork->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextNetwork *>(this->m_contextNetwork);
}
const CContextNetwork *CCoreFacade::getCContextNetwork() const
{
Q_ASSERT_X(this->m_contextNetwork && this->m_contextNetwork->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextNetwork *>(this->m_contextNetwork);
}
CContextOwnAircraft *CCoreFacade::getCContextOwnAircraft()
{
Q_ASSERT_X(this->m_contextOwnAircraft && this->m_contextOwnAircraft->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextOwnAircraft *>(this->m_contextOwnAircraft);
}
const CContextOwnAircraft *CCoreFacade::getCContextOwnAircraft() const
{
Q_ASSERT_X(this->m_contextOwnAircraft && this->m_contextOwnAircraft->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextOwnAircraft *>(this->m_contextOwnAircraft);
}
CContextSimulator *CCoreFacade::getCContextSimulator()
{
Q_ASSERT_X(this->m_contextSimulator && this->m_contextSimulator->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextSimulator *>(this->m_contextSimulator);
}
const CContextSimulator *CCoreFacade::getCContextSimulator() const
{
Q_ASSERT_X(this->m_contextSimulator && this->m_contextSimulator->isUsingImplementingObject(), "CCoreRuntime", "Cannot downcast to local object");
return static_cast<CContextSimulator *>(this->m_contextSimulator);
}
} // namespace