mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-16 02:06:08 +08:00
refs #288, added FSD servers to VATSIM reader
* Voice and FSD servers can be obtained via context * using QSCopedPointer for network reply * minor fixes / renaming
This commit is contained in:
committed by
Roland Winklmeier
parent
adba17da0f
commit
a401ce439d
@@ -10,6 +10,7 @@
|
|||||||
#include "blackmisc/sequence.h"
|
#include "blackmisc/sequence.h"
|
||||||
#include "blackmisc/avatcstation.h"
|
#include "blackmisc/avatcstation.h"
|
||||||
#include "blackmisc/nwuser.h"
|
#include "blackmisc/nwuser.h"
|
||||||
|
#include "blackmisc/logmessage.h"
|
||||||
#include "vatsimbookingreader.h"
|
#include "vatsimbookingreader.h"
|
||||||
|
|
||||||
#include <QtXml/QDomElement>
|
#include <QtXml/QDomElement>
|
||||||
@@ -56,12 +57,17 @@ namespace BlackCore
|
|||||||
/*
|
/*
|
||||||
* Parse bookings
|
* Parse bookings
|
||||||
*/
|
*/
|
||||||
void CVatsimBookingReader::parseBookings(QNetworkReply *nwReply)
|
void CVatsimBookingReader::parseBookings(QNetworkReply *nwReplyPtr)
|
||||||
{
|
{
|
||||||
|
// wrap pointer, make sure any exit cleans up reply
|
||||||
|
// required to use delete later as object is created in a different thread
|
||||||
|
QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> nwReply(nwReplyPtr);
|
||||||
|
|
||||||
// Worker thread, make sure to write no members here!
|
// Worker thread, make sure to write no members here!
|
||||||
if (this->isStopped())
|
if (this->isStopped())
|
||||||
{
|
{
|
||||||
qDebug() << "terminated" << Q_FUNC_INFO;
|
CLogMessage(this).debug() << Q_FUNC_INFO;
|
||||||
|
CLogMessage(this).info("terminated booking parsing process"); // for users
|
||||||
return; // stop, terminate straight away, ending thread
|
return; // stop, terminate straight away, ending thread
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +75,7 @@ namespace BlackCore
|
|||||||
{
|
{
|
||||||
static const QString timestampFormat("yyyy-MM-dd HH:mm:ss");
|
static const QString timestampFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
QString xmlData = nwReply->readAll();
|
QString xmlData = nwReply->readAll();
|
||||||
|
nwReply->close(); // close asap
|
||||||
QDomDocument doc;
|
QDomDocument doc;
|
||||||
QDateTime updateTimestamp = QDateTime::currentDateTimeUtc();
|
QDateTime updateTimestamp = QDateTime::currentDateTimeUtc();
|
||||||
|
|
||||||
@@ -95,7 +102,8 @@ namespace BlackCore
|
|||||||
{
|
{
|
||||||
if (this->isStopped())
|
if (this->isStopped())
|
||||||
{
|
{
|
||||||
qDebug() << "terminated" << Q_FUNC_INFO;
|
CLogMessage(this).debug() << Q_FUNC_INFO;
|
||||||
|
CLogMessage(this).info("terminated booking parsing process"); // for users
|
||||||
return; // stop, terminate straight away, ending thread
|
return; // stop, terminate straight away, ending thread
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,11 +156,10 @@ namespace BlackCore
|
|||||||
this->setUpdateTimestamp(updateTimestamp); // thread safe update
|
this->setUpdateTimestamp(updateTimestamp); // thread safe update
|
||||||
emit this->dataRead(bookedStations);
|
emit this->dataRead(bookedStations);
|
||||||
} // node
|
} // node
|
||||||
} // content
|
} else {
|
||||||
|
// with errors
|
||||||
nwReply->close();
|
nwReply->abort();
|
||||||
nwReply->deleteLater();
|
}
|
||||||
|
|
||||||
} // method
|
} // method
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace BlackCore
|
|||||||
|
|
||||||
//! Parse received bookings
|
//! Parse received bookings
|
||||||
//! \threadsafe
|
//! \threadsafe
|
||||||
void parseBookings(QNetworkReply *nwReply);
|
void parseBookings(QNetworkReply *nwReplyPtr);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
//! Bookings have been read and converted to BlackMisc::Aviation::CAtcStationList
|
//! Bookings have been read and converted to BlackMisc::Aviation::CAtcStationList
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "blackmisc/avatcstation.h"
|
#include "blackmisc/avatcstation.h"
|
||||||
#include "blackmisc/nwuser.h"
|
#include "blackmisc/nwuser.h"
|
||||||
#include "blackmisc/nwserver.h"
|
#include "blackmisc/nwserver.h"
|
||||||
|
#include "blackmisc/logmessage.h"
|
||||||
#include "vatsimdatafilereader.h"
|
#include "vatsimdatafilereader.h"
|
||||||
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
@@ -69,6 +70,12 @@ namespace BlackCore
|
|||||||
return this->m_voiceServers;
|
return this->m_voiceServers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CServerList CVatsimDataFileReader::getFsdServers() const
|
||||||
|
{
|
||||||
|
QReadLocker rl(&this->m_lock);
|
||||||
|
return this->m_fsdServers;
|
||||||
|
}
|
||||||
|
|
||||||
CUserList CVatsimDataFileReader::getPilotsForCallsigns(const CCallsignList &callsigns)
|
CUserList CVatsimDataFileReader::getPilotsForCallsigns(const CCallsignList &callsigns)
|
||||||
{
|
{
|
||||||
return this->getAircrafts().findByCallsigns(callsigns).transform(Predicates::MemberTransform(&CAircraft::getPilot));
|
return this->getAircrafts().findByCallsigns(callsigns).transform(Predicates::MemberTransform(&CAircraft::getPilot));
|
||||||
@@ -153,12 +160,17 @@ namespace BlackCore
|
|||||||
* Data file read from XML
|
* Data file read from XML
|
||||||
* Example: http://info.vroute.net/vatsim-data.txt
|
* Example: http://info.vroute.net/vatsim-data.txt
|
||||||
*/
|
*/
|
||||||
void CVatsimDataFileReader::parseVatsimFileInBackground(QNetworkReply *nwReply)
|
void CVatsimDataFileReader::parseVatsimFileInBackground(QNetworkReply *nwReplyPtr)
|
||||||
{
|
{
|
||||||
|
// wrap pointer, make sure any exit cleans up reply
|
||||||
|
// required to use delete later as object is created in a different thread
|
||||||
|
QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> nwReply(nwReplyPtr);
|
||||||
|
|
||||||
// Worker thread, make sure to write only synced here!
|
// Worker thread, make sure to write only synced here!
|
||||||
if (this->isStopped())
|
if (this->isStopped())
|
||||||
{
|
{
|
||||||
qDebug() << "terminated" << Q_FUNC_INFO;
|
CLogMessage(this).debug() << Q_FUNC_INFO;
|
||||||
|
CLogMessage(this).info("terminated VATSIM file parsing process"); // for users
|
||||||
return; // stop, terminate straight away, ending thread
|
return; // stop, terminate straight away, ending thread
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,12 +178,15 @@ namespace BlackCore
|
|||||||
if (nwReply->error() == QNetworkReply::NoError)
|
if (nwReply->error() == QNetworkReply::NoError)
|
||||||
{
|
{
|
||||||
const QString dataFileData = nwReply->readAll();
|
const QString dataFileData = nwReply->readAll();
|
||||||
|
nwReply->close(); // close asap
|
||||||
|
|
||||||
if (dataFileData.isEmpty()) return;
|
if (dataFileData.isEmpty()) return;
|
||||||
QStringList lines = dataFileData.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
|
QStringList lines = dataFileData.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
|
||||||
if (lines.isEmpty()) return;
|
if (lines.isEmpty()) return;
|
||||||
|
|
||||||
// build on local vars for thread safety
|
// build on local vars for thread safety
|
||||||
CServerList voiceServers;
|
CServerList voiceServers;
|
||||||
|
CServerList fsdServers;
|
||||||
CAtcStationList atcStations;
|
CAtcStationList atcStations;
|
||||||
CAircraftList aircrafts;
|
CAircraftList aircrafts;
|
||||||
QMap<CCallsign, CVoiceCapabilities> voiceCapabilities;
|
QMap<CCallsign, CVoiceCapabilities> voiceCapabilities;
|
||||||
@@ -183,7 +198,8 @@ namespace BlackCore
|
|||||||
{
|
{
|
||||||
if (this->isStopped())
|
if (this->isStopped())
|
||||||
{
|
{
|
||||||
qDebug() << "terminated" << Q_FUNC_INFO;
|
CLogMessage(this).debug() << Q_FUNC_INFO;
|
||||||
|
CLogMessage(this).info("terminated booking parsing process"); // for users
|
||||||
return; // stop, terminate straight away, ending thread
|
return; // stop, terminate straight away, ending thread
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,24 +220,10 @@ namespace BlackCore
|
|||||||
}
|
}
|
||||||
else if (currentLine.startsWith("!"))
|
else if (currentLine.startsWith("!"))
|
||||||
{
|
{
|
||||||
if (currentLine.contains("GENERAL", Qt::CaseInsensitive))
|
section = currentLineToSection(currentLine);
|
||||||
{
|
|
||||||
section = SectionGeneral;
|
|
||||||
}
|
|
||||||
else if (currentLine.contains("VOICE SERVERS", Qt::CaseInsensitive))
|
|
||||||
{
|
|
||||||
section = SectionVoiceServer;
|
|
||||||
}
|
|
||||||
else if (currentLine.contains("CLIENTS", Qt::CaseInsensitive))
|
|
||||||
{
|
|
||||||
section = SectionClients;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
section = SectionNone;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (section)
|
switch (section)
|
||||||
{
|
{
|
||||||
case SectionClients:
|
case SectionClients:
|
||||||
@@ -305,42 +307,61 @@ namespace BlackCore
|
|||||||
bool alreadyRead = (updateTimestampFromFile == this->getUpdateTimestamp());
|
bool alreadyRead = (updateTimestampFromFile == this->getUpdateTimestamp());
|
||||||
if (alreadyRead) { return; }// still same data, terminate
|
if (alreadyRead) { return; }// still same data, terminate
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case SectionVoiceServer:
|
|
||||||
{
|
|
||||||
QStringList voiceServerParts = currentLine.split(':');
|
|
||||||
if (voiceServerParts.size() < 3) continue;
|
|
||||||
BlackMisc::Network::CServer voiceServer(voiceServerParts.at(1), voiceServerParts.at(2), voiceServerParts.at(0), -1, CUser());
|
|
||||||
voiceServers.push_back(voiceServer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SectionNone:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} // for each
|
break;
|
||||||
|
case SectionFsdServers:
|
||||||
|
{
|
||||||
|
// ident:hostname_or_IP:location:name:clients_connection_allowed:
|
||||||
|
QStringList fsdServerParts = currentLine.split(':');
|
||||||
|
if (fsdServerParts.size() < 4) continue;
|
||||||
|
if (!fsdServerParts.at(3).trimmed().contains('1')) continue; // allowed?
|
||||||
|
BlackMisc::Network::CServer fsdServer(fsdServerParts.at(0), fsdServerParts.at(2), fsdServerParts.at(1), 6809, CUser("id", "real name", "email", "password"));
|
||||||
|
fsdServers.push_back(fsdServer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SectionVoiceServers:
|
||||||
|
{
|
||||||
|
// hostname_or_IP:location:name:clients_connection_allowed:type_of_voice_server:
|
||||||
|
QStringList voiceServerParts = currentLine.split(':');
|
||||||
|
if (voiceServerParts.size() < 3) continue;
|
||||||
|
if (!voiceServerParts.at(3).trimmed().contains('1')) continue; // allowed?
|
||||||
|
BlackMisc::Network::CServer voiceServer(voiceServerParts.at(1), voiceServerParts.at(2), voiceServerParts.at(0), -1, CUser());
|
||||||
|
voiceServers.push_back(voiceServer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SectionNone:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
} // switch section
|
||||||
|
|
||||||
// this part needs to be synchronized
|
// this part needs to be synchronized
|
||||||
{
|
{
|
||||||
QWriteLocker wl(&this->m_lock);
|
QWriteLocker wl(&this->m_lock);
|
||||||
this->m_updateTimestamp = updateTimestampFromFile;
|
this->setUpdateTimestamp(updateTimestampFromFile);
|
||||||
this->m_aircrafts = aircrafts;
|
this->m_aircrafts = aircrafts;
|
||||||
this->m_atcStations = atcStations;
|
this->m_atcStations = atcStations;
|
||||||
this->m_voiceServers = voiceServers;
|
this->m_voiceServers = voiceServers;
|
||||||
|
this->m_fsdServers = fsdServers;
|
||||||
this->m_voiceCapabilities = voiceCapabilities;
|
this->m_voiceCapabilities = voiceCapabilities;
|
||||||
}
|
}
|
||||||
} // read success
|
} // for each line
|
||||||
|
|
||||||
nwReply->close();
|
|
||||||
nwReply->deleteLater(); // we are responsible for deleting this
|
|
||||||
|
|
||||||
emit this->dataRead();
|
|
||||||
// warnings, if required
|
// warnings, if required
|
||||||
if (!illegalIcaoCodes.isEmpty())
|
if (!illegalIcaoCodes.isEmpty())
|
||||||
{
|
{
|
||||||
qWarning() << "Illegal ICAO code(s) in VATSIM data file:" << illegalIcaoCodes.join(", ");
|
CLogMessage(this).info("Illegal / ignored ICAO code(s) in VATSIM data file: %1") << illegalIcaoCodes.join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// data read finished
|
||||||
|
emit this->dataRead();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// network error
|
||||||
|
nwReply->abort();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const QMap<QString, QString> CVatsimDataFileReader::clientPartsToMap(const QString ¤tLine, const QStringList &clientSectionAttributes)
|
const QMap<QString, QString> CVatsimDataFileReader::clientPartsToMap(const QString ¤tLine, const QStringList &clientSectionAttributes)
|
||||||
@@ -355,4 +376,13 @@ namespace BlackCore
|
|||||||
}
|
}
|
||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CVatsimDataFileReader::Section CVatsimDataFileReader::currentLineToSection(const QString ¤tLine)
|
||||||
|
{
|
||||||
|
if (currentLine.contains("!GENERAL", Qt::CaseInsensitive)) { return SectionGeneral; }
|
||||||
|
if (currentLine.contains("!VOICE SERVERS", Qt::CaseInsensitive)) { return SectionVoiceServers; }
|
||||||
|
if (currentLine.contains("!SERVERS", Qt::CaseInsensitive)) { return SectionFsdServers; }
|
||||||
|
if (currentLine.contains("!CLIENTS", Qt::CaseInsensitive)) { return SectionClients; }
|
||||||
|
return SectionNone;
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ namespace BlackCore
|
|||||||
//! \threadsafe
|
//! \threadsafe
|
||||||
BlackMisc::Network::CServerList getVoiceServers() const;
|
BlackMisc::Network::CServerList getVoiceServers() const;
|
||||||
|
|
||||||
|
//! Get all FSD servers
|
||||||
|
//! \threadsafe
|
||||||
|
BlackMisc::Network::CServerList getFsdServers() const;
|
||||||
|
|
||||||
//! Users for callsign(s)
|
//! Users for callsign(s)
|
||||||
//! \threadsafe
|
//! \threadsafe
|
||||||
BlackMisc::Network::CUserList getUsersForCallsigns(const BlackMisc::Aviation::CCallsignList &callsigns);
|
BlackMisc::Network::CUserList getUsersForCallsigns(const BlackMisc::Aviation::CCallsignList &callsigns);
|
||||||
@@ -98,6 +102,7 @@ namespace BlackCore
|
|||||||
int m_currentUrlIndex;
|
int m_currentUrlIndex;
|
||||||
QNetworkAccessManager *m_networkManager;
|
QNetworkAccessManager *m_networkManager;
|
||||||
BlackMisc::Network::CServerList m_voiceServers;
|
BlackMisc::Network::CServerList m_voiceServers;
|
||||||
|
BlackMisc::Network::CServerList m_fsdServers;
|
||||||
BlackMisc::Aviation::CAtcStationList m_atcStations;
|
BlackMisc::Aviation::CAtcStationList m_atcStations;
|
||||||
BlackMisc::Aviation::CAircraftList m_aircrafts;
|
BlackMisc::Aviation::CAircraftList m_aircrafts;
|
||||||
QMap<BlackMisc::Aviation::CCallsign, BlackMisc::Network::CVoiceCapabilities> m_voiceCapabilities;
|
QMap<BlackMisc::Aviation::CCallsign, BlackMisc::Network::CVoiceCapabilities> m_voiceCapabilities;
|
||||||
@@ -109,13 +114,17 @@ namespace BlackCore
|
|||||||
enum Section
|
enum Section
|
||||||
{
|
{
|
||||||
SectionNone,
|
SectionNone,
|
||||||
SectionVoiceServer,
|
SectionFsdServers,
|
||||||
|
SectionVoiceServers,
|
||||||
SectionClients,
|
SectionClients,
|
||||||
SectionGeneral
|
SectionGeneral
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Get current section
|
||||||
|
static Section currentLineToSection(const QString ¤tLine);
|
||||||
|
|
||||||
//! Parse the VATSIM data file in backgroun
|
//! Parse the VATSIM data file in backgroun
|
||||||
void parseVatsimFileInBackground(QNetworkReply *nwReply);
|
void parseVatsimFileInBackground(QNetworkReply *nwReplyPtr);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
//! Data have been read
|
//! Data have been read
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ namespace BlackMisc
|
|||||||
//! Destructor
|
//! Destructor
|
||||||
virtual ~CThreadedReader()
|
virtual ~CThreadedReader()
|
||||||
{
|
{
|
||||||
delete m_updateTimer;
|
|
||||||
this->stop();
|
this->stop();
|
||||||
|
delete m_updateTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Thread safe, set update timestamp
|
//! Thread safe, set update timestamp
|
||||||
@@ -59,10 +59,13 @@ namespace BlackMisc
|
|||||||
virtual void stop()
|
virtual void stop()
|
||||||
{
|
{
|
||||||
if (this->isStopped()) return;
|
if (this->isStopped()) return;
|
||||||
|
|
||||||
|
// thread safe stopping timer and mark as stopped
|
||||||
this->setStopFlag();
|
this->setStopFlag();
|
||||||
this->setInterval(0);
|
this->setInterval(0);
|
||||||
|
|
||||||
// shutdown pending
|
// shutdown pending
|
||||||
|
QWriteLocker(&this->m_lock);
|
||||||
if (this->m_pendingFuture.isRunning())
|
if (this->m_pendingFuture.isRunning())
|
||||||
{
|
{
|
||||||
// cancel does not work with all futures, especially not with QConcurrent::run
|
// cancel does not work with all futures, especially not with QConcurrent::run
|
||||||
@@ -78,7 +81,6 @@ namespace BlackMisc
|
|||||||
|
|
||||||
// cancel or stop flag above should terminate QFuture
|
// cancel or stop flag above should terminate QFuture
|
||||||
this->m_pendingFuture.waitForFinished();
|
this->m_pendingFuture.waitForFinished();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Thread safe, is in state stopped?
|
//! Thread safe, is in state stopped?
|
||||||
@@ -114,8 +116,7 @@ namespace BlackMisc
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Constructor
|
//! Constructor
|
||||||
CThreadedReader() :
|
CThreadedReader() : m_lock(QReadWriteLock::Recursive)
|
||||||
m_updateTimer(nullptr), m_stopped(false), m_pendingNetworkReply(nullptr), m_lock(QReadWriteLock::Recursive)
|
|
||||||
{
|
{
|
||||||
this->m_updateTimer = new QTimer();
|
this->m_updateTimer = new QTimer();
|
||||||
}
|
}
|
||||||
@@ -144,12 +145,14 @@ namespace BlackMisc
|
|||||||
this->m_stopped = true;
|
this->m_stopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime m_updateTimestamp; //!< when was file / resource read
|
QTimer *m_updateTimer = nullptr; //!< update timer
|
||||||
QTimer *m_updateTimer; //!< update times
|
mutable QReadWriteLock m_lock; //!< lock
|
||||||
bool m_stopped; //!< mark as stopped, threads should terminate
|
|
||||||
QFuture<FutureRet> m_pendingFuture; //!< optional future to be stopped
|
private:
|
||||||
QNetworkReply *m_pendingNetworkReply; //!< optional future to be stopped
|
QDateTime m_updateTimestamp; //!< when was file / resource read
|
||||||
mutable QReadWriteLock m_lock; //!< lock
|
bool m_stopped = false; //!< mark as stopped, threads should terminate
|
||||||
|
QFuture<FutureRet> m_pendingFuture; //!< optional future to be stopped
|
||||||
|
QNetworkReply *m_pendingNetworkReply = nullptr; //!< optional network reply to be stopped
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user