9 #include <QNetworkReply>
11 #include <QReadLocker>
12 #include <QRegularExpression>
13 #include <QScopedPointer>
14 #include <QScopedPointerDeleteLater>
15 #include <QStringBuilder>
18 #include <QWriteLocker>
44 using namespace swift::misc::aviation;
45 using namespace swift::misc::network;
46 using namespace swift::misc::geo;
47 using namespace swift::misc::simulation;
48 using namespace swift::misc::physical_quantities;
51 namespace swift::core::vatsim
53 CVatsimDataFileReader::CVatsimDataFileReader(QObject *owner) :
CThreadedReader(owner,
"CVatsimDataFileReader")
55 this->reloadSettings();
109 return m_flightPlanRemarks.value(callsign).getVoiceCapabilities();
114 if (callsign.
isEmpty()) {
return QString(); }
116 return m_flightPlanRemarks.value(callsign);
145 if (callsigns.
isEmpty()) {
return users; }
146 for (
const CCallsign &callsign : callsigns)
156 QPointer<CVatsimDataFileReader> myself(
this);
158 if (!myself) {
return; }
165 void CVatsimDataFileReader::read()
170 Q_ASSERT_X(
sApp, Q_FUNC_INFO,
"Missing application");
172 if (url.isEmpty()) {
return; }
176 void CVatsimDataFileReader::parseVatsimFile(QNetworkReply *nwReplyPtr)
180 QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> nwReply(nwReplyPtr);
191 QStringList illegalEquipmentCodes;
192 const QUrl url = nwReply->url();
193 const QString urlString = url.toString();
195 if (nwReply->error() == QNetworkReply::NoError)
197 const QString dataFileData = nwReply->readAll();
200 if (dataFileData.isEmpty()) {
return; }
203 CLogMessage(
this).
info(u
"VATSIM file '%1' has same content, skipped") << urlString;
206 auto jsonDoc = QJsonDocument::fromJson(dataFileData.toUtf8());
207 if (jsonDoc.isEmpty()) {
return; }
214 auto updateTimestampFromFile =
215 QDateTime::fromString(jsonDoc[
"general"][
"update_timestamp"].toString(), Qt::ISODateWithMs);
224 for (QJsonValueRef pilot : jsonDoc[
"pilots"].toArray())
231 aircraft.
push_back(parsePilot(pilot.toObject(), illegalEquipmentCodes));
232 flightPlanRemarksMap.insert(aircraft.
back().
getCallsign(), parseFlightPlanRemarks(pilot.toObject()));
234 for (QJsonValueRef controller : jsonDoc[
"controllers"].toArray())
241 atcStations.
push_back(parseController(controller.toObject()));
243 for (QJsonValueRef atis : jsonDoc[
"atis"].toArray())
250 atcStations.
push_back(parseController(atis.toObject()));
254 fsdServers.
sortBy(&CServer::getName, &CServer::getDescription);
260 m_aircraft = aircraft;
261 m_atcStations = atcStations;
262 m_flightPlanRemarks = flightPlanRemarksMap;
266 if (!illegalEquipmentCodes.isEmpty())
270 u
"Illegal / ignored equipment code(s) in VATSIM data file: %1")
271 << illegalEquipmentCodes.join(
", "));
276 emit this->
dataRead(CEntityFlags::VatsimDataFile, CEntityFlags::ReadFinished, dataFileData.size() / 1000,
283 << nwReply->errorString() << urlString;
285 emit this->
dataRead(CEntityFlags::VatsimDataFile, CEntityFlags::ReadFailed, 0, url);
290 QStringList &o_illegalEquipmentCodes)
const
292 const CCallsign callsign(pilot[
"callsign"].toString());
293 const CUser user(pilot[
"cid"].toString(), pilot[
"name"].toString(), callsign);
294 const CCoordinateGeodetic position(pilot[
"latitude"].toDouble(), pilot[
"longitude"].toDouble(),
295 pilot[
"altitude"].toInt());
296 const CHeading heading(pilot[
"heading"].toInt(), CAngleUnit::deg());
297 const CSpeed groundspeed(pilot[
"groundspeed"].toInt(), CSpeedUnit::kts());
300 const QString icaoAndEquipment(pilot[
"flight_plan"][
"aircraft"].toString().trimmed());
302 if (info.getAircraftIcao().hasValidDesignator()) { aircraft.setAircraftIcaoCode(info.getAircraftIcao()); }
303 else if (!icaoAndEquipment.isEmpty()) { o_illegalEquipmentCodes.
push_back(icaoAndEquipment); }
304 aircraft.setTransponderCode(pilot[
"transponder"].toString().toInt());
308 CFlightPlanRemarks CVatsimDataFileReader::parseFlightPlanRemarks(
const QJsonObject &pilot)
const
313 CAtcStation CVatsimDataFileReader::parseController(
const QJsonObject &controller)
const
315 const CCallsign callsign(controller[
"callsign"].toString());
316 const CUser user(controller[
"cid"].toString(), controller[
"name"].toString(), callsign);
317 const CFrequency freq(controller[
"frequency"].toString().toDouble(), CFrequencyUnit::kHz());
318 const CLength range(controller[
"visual_range"].toInt(), CLengthUnit::NM());
319 const QJsonArray atisLines = controller[
"text_atis"].toArray();
320 const auto atisText =
makeRange(atisLines).transform([](
auto line) {
return line.toString(); });
321 const CInformationMessage atis(CInformationMessage::ATIS, atisText.to<QStringList>().join(
'\n'));
322 return CAtcStation(callsign, user, freq, {}, range,
true, {}, {}, atis);
325 void CVatsimDataFileReader::reloadSettings()
327 CReaderSettings s = m_settings.
get();
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
swift::misc::network::CUrl getVatsimDataFileUrl() const
Consolidated version of data file URL, either from CGlobalSetup or CVatsimSetup.
Support for threaded based reading and parsing tasks such as data files via http, or file system and ...
QDateTime getUpdateTimestamp() const
Thread safe, get update timestamp.
void setUpdateTimestamp(const QDateTime &updateTimestamp=QDateTime::currentDateTimeUtc())
Thread safe, set update timestamp.
static void logInconsistentData(const swift::misc::CStatusMessage &msg, const char *funcInfo=nullptr)
Use this to log inconsistent data.
void threadAssertCheck() const
Make sure everthing runs correctly in own thread.
void logNetworkReplyReceived(QNetworkReply *reply)
Network reply received, mark in m_urlReadLog.
QReadWriteLock m_lock
lock which can be used from the derived classes
bool didContentChange(const QString &content, int startPosition=-1)
Stores new content hash and returns if content changed (based on hash value.
QNetworkReply * getFromNetworkAndLog(const swift::misc::network::CUrl &url, const swift::misc::CSlot< void(QNetworkReply *)> &callback)
Get request from network, and log with m_urlReadLog.
void setInitialAndPeriodicTime(int initialTime, int periodicTime)
Set initial and periodic times.
bool doWorkCheck() const
Still enabled etc.?
swift::misc::network::CUserList getControllersForCallsigns(const swift::misc::aviation::CCallsignSet &callsigns) const
Controllers for callsigns.
swift::misc::aviation::CFlightPlanRemarks getFlightPlanRemarksForCallsign(const swift::misc::aviation::CCallsign &callsign) const
Flight plan remarks for callsign.
void readInBackgroundThread()
Start reading in own thread.
void dataRead(swift::misc::network::CEntityFlags::Entity entity, swift::misc::network::CEntityFlags::ReadState state, int number, const QUrl &url)
Data have been read.
swift::misc::network::CUserList getPilotsForCallsigns(const swift::misc::aviation::CCallsignSet &callsigns) const
Users for callsigns.
swift::misc::aviation::CAirlineIcaoCode getAirlineIcaoCode(const swift::misc::aviation::CCallsign &callsign) const
Airline ICAO info for callsign.
void dataFileRead(int kB)
Data have been read.
virtual void doWorkImpl()
This method does the actual work in the derived class.
swift::misc::aviation::CAtcStationList getAtcStationsForCallsigns(const swift::misc::aviation::CCallsignSet &callsigns) const
Get ATC stations for callsigns.
swift::misc::aviation::CAtcStationList getAtcStationsForCallsign(const swift::misc::aviation::CCallsign &callsign) const
Get ATC stations for callsign.
swift::misc::network::CVoiceCapabilities getVoiceCapabilityForCallsign(const swift::misc::aviation::CCallsign &callsign) const
Voice capability for callsign.
void updateWithVatsimDataFileData(swift::misc::simulation::CSimulatedAircraft &aircraftToBeUdpated) const
Update aircraft with VATSIM aircraft data from data file.
swift::misc::network::CUserList getUsersForCallsigns(const swift::misc::aviation::CCallsignSet &callsigns) const
Users for callsign(s)
swift::misc::network::CUserList getPilotsForCallsign(const swift::misc::aviation::CCallsign &callsign) const
Users for callsign.
swift::misc::network::CUserList getControllersForCallsign(const swift::misc::aviation::CCallsign &callsign) const
Controllers for callsign.
swift::misc::aviation::CAtcStationList getAtcStations() const
Get ATC station.
swift::misc::network::CUserList getUsersForCallsign(const swift::misc::aviation::CCallsign &callsign) const
User for callsign.
swift::misc::aviation::CAircraftIcaoCode getAircraftIcaoCode(const swift::misc::aviation::CCallsign &callsign) const
Aircraft ICAO info for callsign.
swift::misc::simulation::CSimulatedAircraftList getAircraft() const
Get aircraft.
T get() const
Get a copy of the current value.
bool isEmpty() const
Synonym for empty.
Class for emitting a log message.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
auto transform(F function) const
Return a new container generated by applying some transformation function to all elements of this one...
void sortBy(K1 key1, Keys... keys)
In-place sort by some particular key(s).
void push_back(const T &value)
Appends an element at the end of the sequence.
reference back()
Access the last element.
Streamable status message, e.g.
constexpr static auto SeverityInfo
Status severities.
Value object for ICAO classification.
Value object encapsulating information of an aircraft's situation.
Value object for ICAO classification.
Value object encapsulating information about an ATC station.
Value object for a list of ATC stations.
Value object encapsulating information of a callsign.
bool isEmpty() const
Is empty?
Value object for a set of callsigns.
Flightplan-related information about an aircraft (aircraft ICAO, equipment and WTC)
Heading as used in aviation, can be true or magnetic heading.
OBJ findFirstByCallsign(const CCallsign &callsign, const OBJ &ifNotFound={}) const
Find the first aircraft by callsign, if none return given one.
CONTAINER findByCallsigns(const CCallsignSet &callsigns) const
Find 0..n aircraft matching any of a set of callsigns.
Value object encapsulating a list of servers.
Value object encapsulating information of a user.
Value object encapsulating a list of voice rooms.
Value object encapsulating information for voice capabilities.
Physical unit length (length)
Comprehensive information of an aircraft.
const network::CUser & getPilot() const
Get user.
const aviation::CCallsign & getCallsign() const
Get callsign.
const aviation::CAircraftIcaoCode & getAircraftIcaoCode() const
Get aircraft ICAO info.
const aviation::CAirlineIcaoCode & getAirlineIcaoCode() const
Airline ICAO code if any.
Value object encapsulating a list of aircraft.
bool updateWithVatsimDataFileData(CSimulatedAircraft &aircraftToBeUpdated) const
Update aircraft with data from VATSIM data file.
Core data traits (aka cached values) and classes.
auto MemberTransform(T memberFunc)
Returns a function object that returns the value returned by one of it's argument member functions.
Free functions in swift::misc.
auto makeRange(I begin, I2 end) -> CRange< I >
Returns a CRange constructed from begin and end iterators of deduced types.
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...