9 #include <QCoreApplication>
13 #include <QHttpMultiPart>
14 #include <QNetworkReply>
15 #include <QNetworkRequest>
17 #include <QRegularExpression>
19 #include <QStandardPaths>
20 #include <QStringBuilder>
21 #include <QStringList>
23 #include <QTemporaryDir>
26 #include <QWriteLocker>
58 using namespace swift::config;
60 using namespace swift::misc::db;
61 using namespace swift::misc::network;
62 using namespace swift::misc::aviation;
63 using namespace swift::misc::simulation;
64 using namespace swift::misc::weather;
66 using namespace swift::core::context;
67 using namespace swift::core::vatsim;
74 static const QString &swiftDataRoot()
76 static const QString path =
77 QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
"/org.swift-project/";
88 :
CIdentifiable(this), m_accessManager(new QNetworkAccessManager(this)), m_applicationInfo(application),
91 Q_ASSERT_X(!
sApp, Q_FUNC_INFO,
"already initialized");
92 Q_ASSERT_X(QCoreApplication::instance(), Q_FUNC_INFO,
"no application object");
95 QCoreApplication::setApplicationName(m_applicationName);
96 QCoreApplication::setApplicationVersion(CBuildConfig::getVersionString());
97 this->setObjectName(m_applicationName);
98 this->thread()->setObjectName(
110 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
this,
126 this->tagApplicationDataDirectory();
148 Qt::QueuedConnection);
150 Qt::QueuedConnection);
161 CLogMessage(cat).
debug(u
"Worker named '%1' still exists after application destroyed")
162 << worker->objectName();
188 if (!apps.
contains(myself)) {
return true; }
201 Q_ASSERT_X(
instance(), Q_FUNC_INFO,
"missing application");
204 return QCoreApplication::exec();
210 const QString prg = QCoreApplication::applicationFilePath();
211 const QStringList args = this->
argumentsJoined(newArguments, removeArguments);
213 QProcess::startDetached(prg, args);
250 static const QString s(m_applicationName % u
" " % CBuildConfig::getVersionString());
271 if (!m_gitHubPackagesReader) {
return CUpdateInfo(); }
272 return m_gitHubPackagesReader->getUpdateInfo();
278 if (!m_gitHubPackagesReader) {
return; }
279 m_gitHubPackagesReader->readUpdateInfo();
284 if (CBuildConfig::isLocalDeveloperDebugBuild()) {
return CDistribution::localDeveloperBuild(); }
293 Q_ASSERT_X(
m_parsed, Q_FUNC_INFO,
"Call this function after parsing");
311 this->simulateCrash();
315 Q_ASSERT_X(m_setupReader && m_setupReader->isSetupAvailable(), Q_FUNC_INFO,
"Setup not available");
322 msgs.
push_back(this->initLocalSettings());
341 if (
m_shutdown || !m_setupReader) {
return false; }
342 return m_setupReader->isSetupAvailable();
347 return (this->
getGlobalSetup().isSwiftVersionMinimumMappingVersion());
353 return !m_webDataServices.isNull();
361 Q_ASSERT_X(m_webDataServices, Q_FUNC_INFO,
362 "Missing web data services, use hasWebDataServices to test if existing");
363 return m_webDataServices.data();
370 static const QString s(CBuildConfig::getVersionStringPlatform() % u
" [dev,DEVDBG]");
375 static const QString s(CBuildConfig::getVersionStringPlatform() % u
" [dev]");
378 if (CBuildConfig::isLocalDeveloperDebugBuild())
380 static const QString s(CBuildConfig::getVersionStringPlatform() % u
" [DEVDBG]");
383 return CBuildConfig::getVersionStringPlatform();
395 return a.constData();
398 bool CApplication::initIsRunningInDeveloperEnvironment()
const
405 if (CBuildConfig::isLocalDeveloperDebugBuild()) {
return true; }
416 m_localSettingsLoaded =
true;
452 static const QTemporaryDir tempDir;
453 if (tempDir.isValid()) {
return tempDir.path(); }
454 return QDir::tempPath();
459 QString str = CBuildConfig::getVersionString() % u
" " %
460 (CBuildConfig::isReleaseBuild() ? u
"Release build" : u
"Debug build") % separator %
461 u
"Local dev.dbg.: " % boolToYesNo(CBuildConfig::isLocalDeveloperDebugBuild()) % separator %
462 u
"dev.env.: " % boolToYesNo(this->
isDeveloperFlagSet()) % separator % u
"distribution: " %
464 boolToYesNo(CBuildConfig::isRunningOnWindowsNtPlatform()) % separator % u
"Linux: " %
465 boolToYesNo(CBuildConfig::isRunningOnLinuxPlatform()) %
" Unix: " %
466 boolToYesNo(CBuildConfig::isRunningOnUnixPlatform()) % separator % u
"MacOS: " %
467 boolToYesNo(CBuildConfig::isRunningOnMacOSPlatform()) % separator %
"Build Abi: " %
468 QSysInfo::buildAbi() % separator % u
"Build CPU: " % QSysInfo::buildCpuArchitecture() % separator %
469 CBuildConfig::compiledWithInfo();
471 if (this->
supportsContexts()) { str += (separator % u
"Supporting contexts"); }
480 return this->
getFromNetwork(url, callback, progress, maxRedirects);
499 return this->
getFromNetwork(request, callback, progress, maxRedirects);
513 return this->httpRequestImpl(request, logId, callback, progress, maxRedirects,
514 [](QNetworkAccessManager &qam,
const QNetworkRequest &request) {
515 QNetworkReply *nr = qam.get(request);
524 return this->httpRequestImpl(request, logId, callback, progress, maxRedirects,
525 [](QNetworkAccessManager &qam,
const QNetworkRequest &request) {
526 QNetworkReply *nr = qam.deleteResource(request);
532 const CSlot<
void(QNetworkReply *)> &callback)
534 return this->httpRequestImpl(request, logId, callback,
NoRedirects,
535 [data](QNetworkAccessManager &qam,
const QNetworkRequest &request) {
536 QNetworkReply *nr = qam.post(request, data);
542 const CSlot<
void(QNetworkReply *)> &callback)
544 if (multiPart->thread() != m_accessManager->thread()) { multiPart->moveToThread(m_accessManager->thread()); }
546 QPointer<CApplication> myself(
this);
547 return httpRequestImpl(request, logId, callback,
NoRedirects,
548 [=](QNetworkAccessManager &qam,
const QNetworkRequest &request) {
549 QNetworkReply *nr =
nullptr;
550 if (!myself) {
return nr; }
551 if (!multiPart) {
return nr; }
552 nr = qam.post(request, multiPart);
553 multiPart->setParent(nr);
566 return httpRequestImpl(
568 [](QNetworkAccessManager &qam,
const QNetworkRequest &request) {
return qam.head(request); });
576 if (url.
isEmpty()) {
return nullptr; }
577 if (saveAsFileName.isEmpty()) {
return nullptr; }
578 const QFileInfo fi(saveAsFileName);
579 if (!fi.dir().exists()) {
return nullptr; }
582 CallbackSlot callbackSlot(
this, [=](QNetworkReply *reply) {
583 QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> nwReply(reply);
585 if (reply->error() != QNetworkReply::NoError)
588 << url.
getFullUrl() << nwReply->errorString();
596 u
"Saving file '%1' downloaded from '%2' failed")
601 if (!sApp || sApp->isShuttingDown()) { return; }
606 ProgressSlot progressSlot(
this, [=](
int, qint64, qint64,
const QUrl &) {
610 QNetworkReply *reply = this->getFromNetwork(url, callbackSlot, progressSlot, maxRedirects);
614 void CApplication::deleteAllCookies() { m_cookieManager->deleteAllCookies(); }
616 void CApplication::exit(
int retcode)
618 if (
sApp) { instance()->gracefulShutdown(); }
621 QCoreApplication::exit(retcode);
624 QStringList CApplication::arguments() {
return QCoreApplication::arguments(); }
626 int CApplication::indexOfCommandLineOption(
const QCommandLineOption &option,
const QStringList &args)
628 const QStringList names = option.names();
629 if (names.isEmpty() || args.isEmpty()) {
return -1; }
631 for (
const QString &arg : args)
635 if (arg.startsWith(
"--")) { a = arg.mid(2); }
636 else if (arg.startsWith(
"-")) { a = arg.mid(1); }
639 if (names.contains(a, Qt::CaseInsensitive)) {
return i; }
644 void CApplication::argumentsWithoutOption(
const QCommandLineOption &option, QStringList &args)
646 const int index = indexOfCommandLineOption(option, args);
647 if (index < 0) {
return; }
650 args.removeAt(index);
651 if (!option.valueName().isEmpty() && args.size() > index) { args.removeAt(index); }
654 void CApplication::processEventsFor(
int milliseconds)
658 QEventLoop eventLoop;
660 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, &eventLoop, &QEventLoop::quit);
666 Q_ASSERT_X(m_parsed, Q_FUNC_INFO,
"Call this function after parsing");
668 m_useContexts =
true;
669 m_coreFacadeConfig = coreConfig;
675 if (!m_webDataServices)
678 CWebReaderFlags::AllReaders, CDatabaseReaderConfigList::forPilotClient());
681 return this->startCoreFacade();
686 Q_ASSERT_X(m_parsed, Q_FUNC_INFO,
"Call this function after parsing");
688 m_useContexts =
true;
693 return this->startCoreFacade();
699 Q_ASSERT_X(m_webDataServices.isNull(), Q_FUNC_INFO,
"Services already started");
701 if (!QSslSocket::supportsSsl()) {
return CStatusMessage(
this).
error(u
"No SSL supported, can`t be used"); }
703 return this->startWebDataServices(webReader, dbReaderConfig);
706 bool CApplication::isLocalContext()
const
708 return this->getIContextApplication() && this->getIContextApplication()->isUsingImplementingObject();
711 bool CApplication::isDBusContext()
const
713 return this->getIContextApplication() && !this->getIContextApplication()->isUsingImplementingObject() &&
714 !this->getIContextApplication()->isEmptyObject();
719 Q_ASSERT_X(m_parsed, Q_FUNC_INFO,
"Call this function after parsing");
725 if (!m_setupReader || !m_setupReader->isSetupAvailable())
730 Q_ASSERT_X(m_coreFacade.isNull(), Q_FUNC_INFO,
"Cannot alter facade");
731 Q_ASSERT_X(m_setupReader, Q_FUNC_INFO,
"No facade without setup possible");
732 Q_ASSERT_X(m_webDataServices, Q_FUNC_INFO,
"Need running web data services");
735 m_coreFacade.reset(
new CCoreFacade(m_coreFacadeConfig));
736 emit this->coreFacadeStarted();
743 Q_ASSERT_X(m_parsed, Q_FUNC_INFO,
"Call this function after parsing");
745 if (!m_setupReader || !m_setupReader->isSetupAvailable())
750 Q_ASSERT_X(m_setupReader, Q_FUNC_INFO,
"No web data services without setup possible");
752 if (!m_webDataServices)
755 m_webDataServices.reset(
new CWebDataServices(webReader, dbReaderConfig,
this));
756 Q_ASSERT_X(m_webDataServices, Q_FUNC_INFO,
"Missing web services");
758 emit this->webDataServicesStarted(
true);
765 void CApplication::initLogging()
767 CLogHandler::instance()->install();
771 connect(CLogHandler::instance(), &CLogHandler::localMessageLogged, m_fileLogger.data(),
772 &CFileLogger::writeStatusMessageToFile);
773 connect(CLogHandler::instance(), &CLogHandler::remoteMessageLogged, m_fileLogger.data(),
774 &CFileLogger::writeStatusMessageToFile);
775 m_fileLogger->changeLogPattern(
CLogPattern().withSeverityAtOrAbove(CStatusMessage::SeverityDebug));
778 void CApplication::initParser()
780 m_parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
781 m_parser.setApplicationDescription(m_applicationName);
782 m_cmdHelp = m_parser.addHelpOption();
783 m_cmdVersion = m_parser.addVersionOption();
784 m_allOptions.append(m_cmdHelp);
785 m_allOptions.append(m_cmdVersion);
788 m_cmdDevelopment = QCommandLineOption({
"dev",
"development" },
789 QCoreApplication::translate(
"application",
"Dev. system features?"));
790 this->addParserOption(m_cmdDevelopment);
793 m_cmdSkipSingleApp = QCommandLineOption(
794 {
"skipsa",
"skipsingleapp" }, QCoreApplication::translate(
"application",
"Skip the single app.test."));
795 this->addParserOption(m_cmdSkipSingleApp);
798 m_cmdClearCache = QCommandLineOption({
"ccache",
"clearcache" },
799 QCoreApplication::translate(
"application",
"Clear (reset) the caches."));
800 this->addParserOption(m_cmdClearCache);
803 m_cmdTestCrashpad = QCommandLineOption(
804 {
"testcp",
"testcrashpad" }, QCoreApplication::translate(
"application",
"Trigger crashpad situation."));
805 this->addParserOption(m_cmdTestCrashpad);
808 bool CApplication::isSet(
const QCommandLineOption &option)
const {
return (m_parser.isSet(option)); }
810 void CApplication::registerMetadata()
816 QStringList CApplication::clearCaches()
818 const QStringList files(CDataCache::instance()->enumerateStore());
819 CDataCache::instance()->clearAllValues();
823 void CApplication::gracefulShutdown()
825 if (m_shutdown) {
return; }
826 if (m_shutdownInProgress) {
return; }
827 m_shutdownInProgress =
true;
832 emit this->aboutToShutdown();
838 CLogMessage(
this).
info(u
"Graceful shutdown of CApplication, released devices");
839 m_inputManager->releaseDevices();
843 if (m_parsed && m_saveSettingsOnShutdown)
845 const CStatusMessage m = this->supportsContexts() ? this->getIContextApplication()->saveSettings() :
846 CSettingsCache::instance()->saveToStore();
853 if (this->supportsContexts(
true))
855 CLogMessage(
this).
info(u
"Graceful shutdown of CApplication, shutdown of contexts");
858 m_coreFacade->gracefulShutdown();
859 m_coreFacade.reset();
862 if (m_webDataServices)
864 CLogMessage(
this).
info(u
"Graceful shutdown of CApplication, shutdown of web services");
866 m_webDataServices->gracefulShutdown();
867 m_webDataServices.reset();
870 if (m_gitHubPackagesReader) { m_gitHubPackagesReader.reset(); }
872 if (m_setupReader) { m_setupReader.reset(); }
874 CLogMessage(
this).
info(u
"Graceful shutdown of CApplication, shutdown of logger");
875 m_fileLogger->close();
878 qApp->sendPostedEvents(
nullptr, QEvent::DeferredDelete);
888 void CApplication::onStartUpCompleted()
893 void CApplication::initNetwork()
895 if (!m_accessManager) { m_accessManager =
new QNetworkAccessManager(
this); }
898 m_cookieManager->setParent(m_accessManager);
899 m_accessManager->setCookieJar(m_cookieManager);
902 Q_ASSERT_X(m_accessManager, Q_FUNC_INFO,
"Need QAM");
907 const QString &CApplication::executable()
909 static const QString e(QFileInfo(QCoreApplication::applicationFilePath()).completeBaseName());
913 const QStringList &CApplication::getLogCategories()
915 static const QStringList l({
"swift.application",
"swift." % executable() });
923 bool CApplication::addParserOption(
const QCommandLineOption &option)
925 m_allOptions.append(option);
926 return m_parser.addOption(option);
929 bool CApplication::addParserOptions(
const QList<QCommandLineOption> &options)
931 m_allOptions.append(options);
932 return m_parser.addOptions(options);
935 void CApplication::addDBusAddressOption()
937 m_cmdDBusAddress = QCommandLineOption(
938 {
"dbus",
"dbusaddress" },
939 QCoreApplication::translate(
"application",
"DBus address (session, system, P2P IP e.g. 192.168.23.5)"),
941 this->addParserOption(m_cmdDBusAddress);
944 void CApplication::addNetworkOptions() { this->addParserOptions(IContextNetwork::getCmdLineOptions()); }
946 void CApplication::addAudioOptions() { this->addParserOptions(CContextAudioBase::getCmdLineOptions()); }
948 QString CApplication::getCmdDBusAddressValue()
const
950 if (!this->isParserOptionSet(m_cmdDBusAddress)) {
return {}; }
951 const QString v(this->getParserValue(m_cmdDBusAddress));
952 const QString dBusAddress(CDBusServer::normalizeAddress(v));
956 bool CApplication::isParserOptionSet(
const QString &option)
const {
return m_parser.isSet(option); }
958 bool CApplication::skipSingleApplicationCheck()
const {
return this->isParserOptionSet(m_cmdSkipSingleApp); }
960 bool CApplication::isParserOptionSet(
const QCommandLineOption &option)
const {
return m_parser.isSet(option); }
962 QString CApplication::getParserValue(
const QString &option)
const {
return m_parser.value(option).trimmed(); }
964 QString CApplication::getParserValue(
const QCommandLineOption &option)
const
966 return m_parser.value(option).trimmed();
969 bool CApplication::parseCommandLineArgsAndLoadSetup()
971 if (!this->startupCheck())
return false;
972 if (!this->parseCommandLineArguments())
return false;
973 if (!this->loadSetupAndHandleErrors())
return false;
977 bool CApplication::parseCommandLineArguments()
979 if (m_parsed) {
return m_parsed; }
982 const QStringList args(QCoreApplication::arguments());
983 if (!m_parser.parse(args))
985 this->cmdLineErrorMessage(
"Parser error:", m_parser.errorText());
989 if (m_alreadyRunning && !this->skipSingleApplicationCheck())
991 this->cmdLineErrorMessage(
"Program must only run once",
992 "You cannot run two or more instances side-by-side.");
997 if (m_parser.isSet(m_cmdHelp))
1000 this->cmdLineHelpMessage();
1003 if (m_parser.isSet(m_cmdVersion))
1006 this->cmdLineVersionMessage();
1011 m_devFlag = this->initIsRunningInDeveloperEnvironment();
1014 if (!this->parsingHookIn()) {
return false; }
1021 bool CApplication::startupCheck()
const
1023 const QStringList verifyErrors = CSwiftDirectories::verifyRuntimeDirectoriesAndFiles();
1024 if (!verifyErrors.isEmpty() && !m_applicationInfo.isUnitTest())
1026 cmdLineErrorMessage(
"Missing runtime directories/files:", verifyErrors.join(
", "));
1032 bool CApplication::loadSetupAndHandleErrors()
1036 if (msgs.
isFailure()) { displaySetupLoadFailure(msgs); }
1046 void CApplication::cmdLineErrorMessage(
const QString &text,
const QString &informativeText)
const
1048 fputs(qPrintable(text + informativeText), stderr);
1053 if (msgs.
isEmpty()) {
return; }
1055 CApplication::cmdLineErrorMessage(msgs.
toQString(
true),
"");
1058 QPointer<ISimulator> CApplication::getISimulator()
const
1060 if (!this->hasSimulator()) {
return nullptr; }
1061 return this->getCoreFacade()->getCContextSimulator()->simulator();
1064 bool CApplication::hasSimulator()
const
1066 if (!this->getCoreFacade()) {
return false; }
1067 if (!this->getCoreFacade()->getIContextSimulator()->isUsingImplementingObject()) {
return false; }
1068 return (this->getCoreFacade()->getCContextSimulator());
1071 void CApplication::cmdLineHelpMessage()
1073 m_parser.showHelp();
1077 void CApplication::cmdLineVersionMessage()
1079 m_parser.showVersion();
1083 QStringList CApplication::argumentsJoined(
const QStringList &newArguments,
const QStringList &removeArguments)
const
1085 QStringList joinedArguments = CApplication::arguments();
1086 QStringList newArgumentsChecked = newArguments;
1089 if (!joinedArguments.isEmpty() && !joinedArguments.at(0).startsWith(
"-"))
1091 joinedArguments.removeFirst();
1093 if (!newArgumentsChecked.isEmpty() && !newArgumentsChecked.at(0).startsWith(
"-"))
1095 newArgumentsChecked.removeFirst();
1099 static const QRegularExpression regExp(
"^-");
1100 QStringList toBeRemoved(newArgumentsChecked.filter(regExp));
1101 toBeRemoved.append(removeArguments.filter(regExp));
1102 toBeRemoved.append(
"--installer");
1103 toBeRemoved.removeDuplicates();
1105 if (!joinedArguments.isEmpty() && !toBeRemoved.isEmpty())
1109 for (
const QCommandLineOption &option : m_allOptions)
1111 const int n = indexOfCommandLineOption(option, toBeRemoved);
1112 if (n >= 0) { argumentsWithoutOption(option, joinedArguments); }
1116 joinedArguments.append(newArgumentsChecked);
1117 return joinedArguments;
1126 bool CApplication::supportsContexts(
bool ignoreShutdownTest)
const
1128 if (!ignoreShutdownTest && m_shutdown) {
return false; }
1129 if (m_coreFacade.isNull()) {
return false; }
1130 if (!m_coreFacade->getIContextApplication()) {
return false; }
1131 return (!m_coreFacade->getIContextApplication()->isEmptyObject());
1136 if (!supportsContexts()) {
return nullptr; }
1142 if (!supportsContexts()) {
return nullptr; }
1148 if (!supportsContexts()) {
return nullptr; }
1149 return m_coreFacade->getCContextAudioBase();
1154 if (!supportsContexts()) {
return nullptr; }
1160 if (!supportsContexts()) {
return nullptr; }
1166 if (!supportsContexts()) {
return nullptr; }
1172 if (!supportsContexts()) {
return nullptr; }
1178 if (!supportsContexts()) {
return nullptr; }
1184 if (!supportsContexts()) {
return nullptr; }
1185 return m_coreFacade->getCContextAudioBase();
1190 if (!supportsContexts()) {
return nullptr; }
1196 if (!supportsContexts()) {
return nullptr; }
1202 if (!supportsContexts()) {
return nullptr; }
1206 void CApplication::onCoreFacadeStarted()
1215 bool CApplication::hasSetupReader()
const {
return !m_setupReader.isNull(); }
1217 CSetupReader *CApplication::getSetupReader()
const {
return m_setupReader.data(); }
1222 if (!m_setupReader) {
return CStatusMessage(
this).
error(u
"No reader for setup/version"); }
1223 Q_ASSERT_X(m_parsed, Q_FUNC_INFO,
"Not yet parsed");
1228 CUrl CApplication::getVatsimMetarUrl()
const
1230 if (m_shutdown) {
return {}; }
1231 if (m_webDataServices)
1233 const CUrl url(m_webDataServices->getVatsimMetarUrl());
1234 if (!url.
isEmpty()) {
return url; }
1236 if (m_setupReader) {
return m_setupReader->getSetup().getVatsimMetarsUrl(); }
1240 CUrl CApplication::getVatsimDataFileUrl()
const
1242 if (m_shutdown) {
return {}; }
1243 if (m_webDataServices)
1245 const CUrl url(m_webDataServices->getVatsimDataFileUrl());
1246 if (!url.
isEmpty()) {
return url; }
1248 if (m_setupReader) {
return m_setupReader->getSetup().getVatsimDataFileUrl(); }
1252 CUrl CApplication::getVatsimServerFileUrl()
const
1254 if (m_shutdown || !m_setupReader) {
return {}; }
1256 return m_setupReader->getSetup().getVatsimServerFileUrl();
1259 CUrl CApplication::getVatsimFsdHttpUrl()
const
1261 if (m_shutdown || !m_setupReader) {
return {}; }
1263 return m_setupReader->getSetup().getVatsimFsdHttpUrl();
1266 void CApplication::onCrashDumpUploadEnabledChanged()
1268 const bool enabled = CBuildConfig::isReleaseBuild() && m_crashDumpUploadEnabled.getThreadLocal();
1269 this->enableCrashDumpUpload(enabled);
1272 void CApplication::simulateCrash() { CCrashHandler::instance()->simulateCrash(); }
1274 void CApplication::simulateAssert() { CCrashHandler::instance()->simulateAssert(); }
1276 void CApplication::enableCrashDumpUpload(
bool enable) { CCrashHandler::instance()->setUploadsEnabled(enable); }
1278 bool CApplication::isSupportingCrashpad()
const
1280 #ifdef SWIFT_USE_CRASHPAD
1287 void CApplication::httpRequestImplInQAMThread(
const QNetworkRequest &request,
int logId,
1288 const CallbackSlot &callback,
const ProgressSlot &progress,
1289 int maxRedirects, NetworkRequestOrPostFunction getPostOrDeleteRequest)
1292 if (this->isShuttingDown()) {
return; }
1296 Q_ASSERT_X(CThreadUtils::isInThisThread(
sApp->m_accessManager), Q_FUNC_INFO,
1297 "Wrong thread, must be QAM thread");
1298 this->httpRequestImpl(request, logId, callback, progress, maxRedirects, getPostOrDeleteRequest);
1302 QNetworkReply *CApplication::httpRequestImpl(
const QNetworkRequest &request,
int logId,
1304 NetworkRequestOrPostFunction requestOrPostMethod)
1306 ProgressSlot progress;
1307 return this->httpRequestImpl(request, logId, callback, progress, maxRedirects, requestOrPostMethod);
1310 QNetworkReply *CApplication::httpRequestImpl(
const QNetworkRequest &request,
int logId,
1311 const CallbackSlot &callback,
const ProgressSlot &progress,
1312 int maxRedirects, NetworkRequestOrPostFunction getPostOrDeleteRequest)
1314 if (this->isShuttingDown()) {
return nullptr; }
1316 QWriteLocker locker(&m_accessManagerLock);
1317 Q_ASSERT_X(m_accessManager->thread() == qApp->thread(), Q_FUNC_INFO,
1318 "Network manager supposed to be in main thread");
1319 if (!CThreadUtils::isInThisThread(m_accessManager))
1321 this->httpRequestImplInQAMThread(request, logId, callback, progress, maxRedirects, getPostOrDeleteRequest);
1325 Q_ASSERT_X(CThreadUtils::isInThisThread(m_accessManager), Q_FUNC_INFO,
"Network manager thread mismatch");
1326 QNetworkRequest copiedRequest =
1327 CNetworkUtils::getSwiftNetworkRequest(request, this->getApplicationNameAndVersion());
1329 QNetworkReply *reply = getPostOrDeleteRequest(*m_accessManager, copiedRequest);
1330 reply->setProperty(
"started", QVariant(QDateTime::currentMSecsSinceEpoch()));
1331 reply->setProperty(CUrlLog::propertyNameId(), QVariant(logId));
1332 const QUrl url(reply->url());
1333 QString urlStr = url.toString();
1337 connect(reply, &QNetworkReply::downloadProgress, progress.object(),
1338 [=](qint64 current, qint64 max) { progress(logId, current, max, url); });
1343 Q_ASSERT_X(callback.object(), Q_FUNC_INFO,
"Need callback object (to determine thread)");
1345 reply, &QNetworkReply::finished, callback.object(),
1352 const bool isRedirect = CNetworkUtils::isHttpStatusRedirect(reply);
1353 if (isRedirect && maxRedirects > 0)
1355 const QUrl redirectUrl = CNetworkUtils::getHttpRedirectUrl(reply);
1356 if (!redirectUrl.isEmpty())
1358 QNetworkRequest redirectRequest(redirectUrl);
1359 const int redirectsLeft = maxRedirects - 1;
1360 CLogMessage(sApp).info(u
"Redirecting '%1' to '%2'") << urlStr << redirectUrl.toString();
1361 this->httpRequestImplInQAMThread(redirectRequest, logId, callback, progress, redirectsLeft,
1362 getPostOrDeleteRequest);
1369 Qt::QueuedConnection);
1374 void CApplication::tagApplicationDataDirectory()
1378 if (!dir.exists() || !dir.isReadable()) {
return; }
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
QStringList argumentsJoined(const QStringList &newArguments={}, const QStringList &removeArguments={}) const
Current parameters replaced by new arguments without the cmd line argument.
const QString & versionStringDetailed() const
String with beta, dev. and version.
~CApplication()
Destructor.
QNetworkReply * getFromNetwork(const swift::misc::network::CUrl &url, const CallbackSlot &callback, int maxRedirects=DefaultMaxRedirects)
Request to get network reply.
QNetworkReply * downloadFromNetwork(const swift::misc::network::CUrl &url, const QString &saveAsFileName, const swift::misc::CSlot< void(const swift::misc::CStatusMessage &)> &callback, int maxRedirects=DefaultMaxRedirects)
Download file from network and store it as passed.
std::atomic_bool m_shutdown
Is being shutdown?
void restartApplication(const QStringList &newArguments={}, const QStringList &removeArguments={})
Stop and restart application.
bool m_parsed
Parsing accomplished?
data::CGlobalSetup getGlobalSetup() const
Global setup.
static constexpr int NoLogRequestId
network request without logging
bool isDeveloperFlagSet() const
Running with dev.flag?
swift::misc::db::CDistribution getOwnDistribution() const
Own distribution.
bool m_alreadyRunning
Application already running.
const char * swiftVersionChar()
swift info string
std::atomic_bool m_incognito
Incognito mode?
QCommandLineOption m_cmdClearCache
Clear cache.
const context::IContextApplication * getIContextApplication() const
Direct access to contexts if a CCoreFacade has been initialized.
virtual void onStartUpCompleted()
Startup completed.
static bool unregisterAsRunning()
Unregister from running.
bool isIncognito() const
Is incognito mode?
static void processEventsFor(int milliseconds)
Process all events for some time.
bool hasUnsavedSettings() const
Unsaved settings.
QNetworkReply * postToNetwork(const QNetworkRequest &request, int logId, const QByteArray &data, const CallbackSlot &callback)
Post to network.
virtual void onCoreFacadeStarted()
Called when facade/contexts have been started.
const QString & swiftVersionString() const
swift info string
void coreFacadeStarted()
Facade started.
void setIncognito(bool incognito)
Set incognito mode.
static QString getTemporaryDirectory()
Directory for temporary files.
bool hasWebDataServices() const
Web data services available?
virtual void cmdLineErrorMessage(const QString &text, const QString &informativeText) const
Display error message.
void init(bool withMetadata)
Init class, allows to init from swift::gui::CGuiApplication as well (pseudo virtual)
void updateInfoAvailable(bool success)
Update info available (cache, web load)
swift::misc::CStatusMessage saveSettingsByKey(const QStringList &keys)
Save all settings.
CApplication(swift::misc::CApplicationInfo::Application application, bool init=true)
Constructor.
static void exit(int retcode=EXIT_SUCCESS)
Exit application, perform graceful shutdown and exit.
QString getInfoString(const QString &separator) const
Comprehensive info.
bool isShuttingDown() const
Is application shutting down?
QNetworkReply * deleteResourceFromNetwork(const QNetworkRequest &request, int logId, const CallbackSlot &callback, int maxRedirects=DefaultMaxRedirects)
Request to delete a network resource from network, supporting swift::misc::network::CUrlLog.
static constexpr int NoRedirects
network request not allowing redirects
QCommandLineOption m_cmdDevelopment
Development flag.
bool isSet(const QCommandLineOption &option) const
Flag set or explicitly set to true.
std::atomic_bool m_shutdownInProgress
shutdown in progress?
static swift::misc::CApplicationInfoList getRunningApplications()
Information about all running apps (including this one only if exec() has already been called)
QStringList getUnsavedSettingsKeys() const
All unsaved settings.
const QString & getApplicationNameVersionDetailed() const
Version, name beta and dev info.
void toggleIncognito()
Toggle incognito mode.
virtual swift::misc::CStatusMessageList startHookIn()
Can be used to start special services.
static bool isApplicationRunning(swift::misc::CApplicationInfo::Application application)
Is application running?
bool m_started
Started with success?
swift::misc::db::CUpdateInfo getUpdateInfo() const
Update info.
bool isSetupAvailable() const
Setup already synchronized.
static QStringList clearCaches()
Clear the caches.
virtual bool start()
Start services, if not yet parsed call CApplication::parse.
bool supportsContexts(bool ignoreShutdownTest=false) const
Supports contexts.
void reloadUpdateInfo()
Reload update info.
CWebDataServices * getWebDataServices() const
Get the web data services.
const swift::misc::CApplicationInfo & getApplicationInfo() const
swift application running
int exec()
Finishes initialization and executes the event loop.
const QString & getApplicationNameAndVersion() const
Application name and version.
virtual void gracefulShutdown()
Graceful shutdown.
void saveSettingsOnShutdown(bool saveSettings)
Save settings on shutdown.
QCommandLineOption m_cmdTestCrashpad
Test a crasphpad upload.
static void registerMetadata()
Register metadata.
bool isAlreadyRunning() const
True if this swift application is already running (including different versions)
virtual bool hasMinimumMappingVersion() const
Minimum mapping version check.
void startUpCompleted(bool success)
Startup has been completed Will be triggered shortly before starting the event loop.
QNetworkReply * headerFromNetwork(const swift::misc::network::CUrl &url, const CallbackSlot &callback, int maxRedirects=NoRedirects)
Request to get network repy using HTTP's HEADER method.
static CApplication * instance()
Similar to.
static bool registerAsRunning()
Register as running.
Threadsafe version of QNetworkCookieJar.
Configuration object for the contexts.
ContextMode getMode() const
Mode.
@ Remote
context runs in a different process.
The class providing facades (the contexts) for all DBus relevant operations.
Read available updates from GitHub Packages REST API.
void updateInfoAvailable(bool available)
Updates have been received from GitHub Packages.
Read the central URLs / locations of our data, setup and versions.
data::CGlobalSetup getSetup() const
Current setup (reader URLs, DB location, crash server)
Encapsulates reading data from web sources.
Audio context base class.
Application context interface.
virtual misc::CStatusMessage saveSettingsByKey(const QStringList &keys)=0
Save core settings to disk.
virtual QStringList getUnsavedSettingsKeys() const =0
Get keys of all unsaved settings currently in core settings cache.
const IContextSimulator * getIContextSimulator() const
Context for simulator.
IContextNetwork * getIContextNetwork()
Context for network.
const IContextApplication * getIContextApplication() const
Context for application.
IContextAudio * getIContextAudio()
Context for network.
IContextOwnAircraft * getIContextOwnAircraft()
Context for own aircraft.
Global settings for readers, debug flags, etc.
Value object encapsulating a list of reader configs.
Description of a swift application.
Application getApplication() const
Get application.
static const QString & fileName()
File name of the application info file.
Application
Enumeration of application roles.
const CProcessInfo & getProcessInfo() const
Get process info.
void setApplicationDataDirectory(const QString &appDataDir)
Set application data dir.
List of swift application descriptions.
bool containsApplication(CApplicationInfo::Application application) const
List containing entry for CApplicationInfo::Application ?
QString toJsonString(QJsonDocument::JsonFormat format=QJsonDocument::Indented) const
Convenience function JSON as string.
CStatusMessage convertFromJsonNoThrow(const QJsonObject &json, const CLogCategoryList &categories, const QString &prefix)
Call convertFromJson, catch any CJsonException that is thrown and return it as CStatusMessage.
Class to write log messages to file.
static QString readLockedFileToString(const QString &fileNameAndPath)
Read file into string, with a lock so two applications can't access at the same time.
static bool writeStringToFile(const QString &content, const QString &fileNameAndPath)
Write string to text file.
static bool writeByteArrayToFile(const QByteArray &data, const QString &fileNameAndPath)
Write byte array to file.
static bool writeStringToLockedFile(const QString &content, const QString &fileNameAndPath)
Write string to file, with a lock so two applications can't access at the same time.
static QString appendFilePaths(const QString &path1, const QString &path2)
Append file paths.
Base class with a member CIdentifier to be inherited by a class which has an identity in the environm...
A sequence of log categories.
Class for emitting a log message.
static void preformatted(const CStatusMessage &statusMessage)
Sends a verbatim, preformatted message to the log.
Value class for matching log messages based on their categories.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
Derived & error(const char16_t(&format)[N])
Set the severity to error, providing a format string.
Derived & debug()
Set the severity to debug.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
bool containsBy(Predicate p) const
Return true if there is an element for which a given predicate returns true.
bool contains(const T &object) const
Return true if there is an element equal to given object. Uses the most efficient implementation avai...
int removeIf(Predicate p)
Remove elements for which a given predicate returns true.
void push_back(const T &value)
Appends an element at the end of the sequence.
int remove(const T &object)
Remove all elements equal to the given object, if it is contained.
bool isEmpty() const
Synonym for empty.
CStatusMessage loadFromStore()
Load settings from disk.
void enableLocalSave()
Connects signal CValueCache::valuesSaveRequested to a private slot that saves the values....
static CSettingsCache * instance()
Return the singleton instance.
CStatusMessage saveToStore(const QString &keyPrefix={})
Save settings to disk.
Callable wrapper for a member function with function signature F.
Streamable status message, e.g.
constexpr static auto SeverityError
Status severities.
constexpr static auto SeverityInfo
Status severities.
bool isFailure() const
Operation considered unsuccessful.
Status messages, e.g. from Core -> GUI.
bool isFailure() const
Any message is marked as failure.
bool hasErrorMessages() const
Error messages.
bool isSuccess() const
All messages are marked as success.
static const QString & normalizedApplicationDataDirectory()
swift application data directory for one specific installation (a version)
QStringList getAllUnsavedKeys(const QString &keyPrefix={}) const
Return keys of all values which have been changed but not saved.
Base class for CWorker and CContinuousWorker.
static const QSet< CWorkerBase * > & allWorkers()
All workers currently existing.
Distributions for channel.
Update info, i.e. artifacts and distributions.
CDistribution anticipateOwnDistribution() const
Own distribution.
QString toQString(bool i18n=false) const
Cast as QString.
Value object encapsulating information of a location, kind of simplified CValueObject compliant versi...
bool isEmpty() const
Empty.
QNetworkRequest toNetworkRequest() const
To request.
QString getFullUrl(bool withQuery=true) const
Qualified name.
A transport mechanism using signals and slots distributed by DBus.
Core data traits (aka cached values) and classes.
Classes interacting with the swift database (aka "datastore").
Backend services of the swift project, like dealing with the network or the simulators.
void registerMetadata()
Register all relevant metadata in swift::core.
Free functions in swift::misc.
SWIFT_MISC_EXPORT void setMockCacheRootDirectory(const QString &path)
Overwrite the default root directory for cache and settings, for testing purposes.
void registerMetadata()
Register all relevant metadata in Misc.
QString applicationName()
Get application name.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.