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)
56 this->reloadSettings();
110 return m_flightPlanRemarks.value(callsign).getVoiceCapabilities();
115 if (callsign.
isEmpty()) {
return QString(); }
117 return m_flightPlanRemarks.value(callsign);
146 if (callsigns.
isEmpty()) {
return users; }
147 for (
const CCallsign &callsign : callsigns)
157 void CVatsimDataFileReader::read()
162 Q_ASSERT_X(
sApp, Q_FUNC_INFO,
"Missing application");
164 if (url.isEmpty()) {
return; }
168 void CVatsimDataFileReader::parseVatsimFile(QNetworkReply *nwReplyPtr)
172 QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> nwReply(nwReplyPtr);
183 QStringList illegalEquipmentCodes;
184 const QUrl url = nwReply->url();
185 const QString urlString = url.toString();
187 if (nwReply->error() == QNetworkReply::NoError)
189 const QString dataFileData = nwReply->readAll();
192 if (dataFileData.isEmpty()) {
return; }
195 CLogMessage(
this).
info(u
"VATSIM file '%1' has same content, skipped") << urlString;
198 auto jsonDoc = QJsonDocument::fromJson(dataFileData.toUtf8());
199 if (jsonDoc.isEmpty()) {
return; }
206 auto updateTimestampFromFile =
207 QDateTime::fromString(jsonDoc[
"general"][
"update_timestamp"].toString(), Qt::ISODateWithMs);
216 for (QJsonValueRef pilot : jsonDoc[
"pilots"].toArray())
223 aircraft.
push_back(parsePilot(pilot.toObject(), illegalEquipmentCodes));
224 flightPlanRemarksMap.insert(aircraft.
back().
getCallsign(), parseFlightPlanRemarks(pilot.toObject()));
226 for (QJsonValueRef controller : jsonDoc[
"controllers"].toArray())
233 atcStations.
push_back(parseController(controller.toObject()));
235 for (QJsonValueRef atis : jsonDoc[
"atis"].toArray())
242 atcStations.
push_back(parseController(atis.toObject()));
246 fsdServers.
sortBy(&CServer::getName, &CServer::getDescription);
252 m_aircraft = aircraft;
253 m_atcStations = atcStations;
254 m_flightPlanRemarks = flightPlanRemarksMap;
258 if (!illegalEquipmentCodes.isEmpty())
262 u
"Illegal / ignored equipment code(s) in VATSIM data file: %1")
263 << illegalEquipmentCodes.join(
", "));
268 emit this->
dataRead(CEntityFlags::VatsimDataFile, CEntityFlags::ReadFinished, dataFileData.size() / 1000,
275 << nwReply->errorString() << urlString;
277 emit this->
dataRead(CEntityFlags::VatsimDataFile, CEntityFlags::ReadFailed, 0, url);
282 QStringList &o_illegalEquipmentCodes)
const
284 const CCallsign callsign(pilot[
"callsign"].toString());
285 const CUser user(pilot[
"cid"].toString(), pilot[
"name"].toString(), callsign);
286 const CCoordinateGeodetic position(pilot[
"latitude"].toDouble(), pilot[
"longitude"].toDouble(),
287 pilot[
"altitude"].toInt());
288 const CHeading heading(pilot[
"heading"].toInt(), CAngleUnit::deg());
289 const CSpeed groundspeed(pilot[
"groundspeed"].toInt(), CSpeedUnit::kts());
292 const QString icaoAndEquipment(pilot[
"flight_plan"][
"aircraft"].toString().trimmed());
294 if (info.getAircraftIcao().hasValidDesignator()) { aircraft.setAircraftIcaoCode(info.getAircraftIcao()); }
295 else if (!icaoAndEquipment.isEmpty()) { o_illegalEquipmentCodes.
push_back(icaoAndEquipment); }
296 aircraft.setTransponderCode(pilot[
"transponder"].toString().toInt());
300 CFlightPlanRemarks CVatsimDataFileReader::parseFlightPlanRemarks(
const QJsonObject &pilot)
const
305 CAtcStation CVatsimDataFileReader::parseController(
const QJsonObject &controller)
const
307 const CCallsign callsign(controller[
"callsign"].toString());
308 const CUser user(controller[
"cid"].toString(), controller[
"name"].toString(), callsign);
309 const CFrequency freq(controller[
"frequency"].toString().toDouble(), CFrequencyUnit::kHz());
310 const CLength range(controller[
"visual_range"].toInt(), CLengthUnit::NM());
311 const QJsonArray atisLines = controller[
"text_atis"].toArray();
312 const auto atisText =
makeRange(atisLines).transform([](
auto line) {
return line.toString(); });
313 const CInformationMessage atis(CInformationMessage::ATIS, atisText.to<QStringList>().join(
'\n'));
314 return CAtcStation(callsign, user, freq, {}, range,
true, {}, {}, atis);
317 void CVatsimDataFileReader::reloadSettings()
319 CReaderSettings s = m_settings.
get();
321 std::chrono::milliseconds(s.getPeriodicTime().toMs()));
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.
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 everything 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.
bool doWorkCheck() const
Still enabled etc.?
Periodically executes doWorkImpl() in a separate thread.
void setInitialAndPeriodicTime(std::chrono::milliseconds initialTime, std::chrono::milliseconds periodicTime)
Set initial and periodic times Changes only apply after the next time the timer restarts.
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 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.