swift
backgroundvalidation.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2019 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QDateTime>
7 
8 #include "misc/eventloop.h"
9 #include "misc/logmessage.h"
12 #include "misc/threadutils.h"
13 
14 using namespace swift::misc::network;
15 using namespace swift::misc::simulation::data;
16 
17 namespace swift::misc::simulation
18 {
19  const QStringList &CBackgroundValidation::getLogCategories()
20  {
21  static const QStringList cats({ CLogCategories::worker(), CLogCategories::modelSetCache() });
22  return cats;
23  }
24 
25  CBackgroundValidation::CBackgroundValidation(QObject *owner)
26  : CContinuousWorker(owner, "Background validation"), m_updateTimer(this, "Background validation")
27  {
28  connect(&m_updateTimer, &CThreadedTimer::timeout, this, &CBackgroundValidation::doWork);
29  }
30 
31  void CBackgroundValidation::setCurrentSimulator(const CSimulatorInfo &simulator, const QString &simDirectory,
32  const QStringList &modelDirList)
33  {
34  QWriteLocker l(&m_lock);
35  m_simulator = simulator;
36  m_simDirectory = simDirectory;
37  m_modelDirList = modelDirList;
38  }
39 
41  {
42  QReadLocker l(&m_lock);
43  return m_checkedSimulatorMsgs.contains(simulator);
44  }
45 
47  {
48  QWriteLocker l(&m_lock);
49  m_checkedSimulatorMsgs.remove(simulator);
50  }
51 
53  {
54  QReadLocker l(&m_lock);
55  return m_simulator;
56  }
57 
58  bool CBackgroundValidation::triggerValidation(const CSimulatorInfo &simulator, const QString &simDirectory)
59  {
60  const QPointer<CBackgroundValidation> myself(this);
61  if (simulator.isNoSimulator()) { return this->requestLastValidationResults(); }
62 
63  {
64  QWriteLocker l(&m_lock);
65  if (m_inWork) { return false; }
66  m_simulator = simulator;
67  m_simDirectory = simDirectory;
68  m_checkedSimulatorMsgs.remove(simulator);
69  }
70  QTimer::singleShot(5, this, [=] {
71  if (!myself) { return; }
72  myself->doWork();
73  });
74  return true;
75  }
76 
78  {
79  CAircraftModelList valid;
80  CAircraftModelList invalid;
81  CAircraftModelList models;
82  CStatusMessageList msgs;
83  CSimulatorInfo simulator;
84  bool wasStopped = false;
85  {
86  QReadLocker l(&m_lock);
87  simulator = m_lastResultSimulator;
88  valid = m_lastResultValid;
89  invalid = m_lastResultInvalid;
90  msgs = m_lastResultMsgs;
91  wasStopped = m_lastResultWasStopped;
92  }
93  if (m_lastResultSimulator.isUnspecified()) { return false; }
94  emit this->validated(simulator, valid, invalid, wasStopped, msgs);
95  return true;
96  }
97 
98  void CBackgroundValidation::startUpdating(std::chrono::milliseconds ms)
99  {
100  Q_ASSERT_X(this->hasStarted(), Q_FUNC_INFO, "Worker not started yet");
101  m_updateTimer.startTimer(ms);
102  }
103 
105  {
106  m_wasStopped = true; // stop in utility functions
107  m_updateTimer.stopTimer();
108  }
109 
110  void CBackgroundValidation::doWork()
111  {
112  if (m_inWork) { return; }
113  m_inWork = true;
114  emit this->validating(true);
115 
116  const bool isTimerBased = (QObject::sender() == &m_updateTimer);
117  CAircraftModelList valid;
118  CAircraftModelList invalid;
119  CStatusMessageList msgs;
120  bool validated = false;
121  bool onlyErrorsAndWarnings = false;
122  const CSimulatorInfo simulator = this->getCurrentSimulator();
123  const qint64 started = QDateTime::currentMSecsSinceEpoch();
124  m_wasStopped = false;
125 
126  do {
127  if (!simulator.isSingleSimulator()) { break; }
128  if (this->wasAlreadyChecked(simulator)) { break; }
129 
130  const CAircraftMatcherSetup setup = m_matchingSettings.get();
131  if (!setup.doVerificationAtStartup()) { break; }
132 
133  onlyErrorsAndWarnings = setup.onlyShowVerificationWarningsAndErrors();
134  const CAircraftModelList models = m_modelSets.getCachedModels(simulator);
135  const qint64 now = QDateTime::currentMSecsSinceEpoch();
136  validated = true;
137 
138  if (models.isEmpty())
139  {
140  msgs.push_back(
141  CStatusMessage(this, CStatusMessage::SeverityWarning,
142  QStringLiteral("No models in set for '%1'").arg(simulator.toQString(true))));
143  }
144  else
145  {
146  msgs = CAircraftModelUtilities::validateModelFiles(simulator, models, valid, invalid, false, 25,
147  m_wasStopped, m_simDirectory);
148  }
149 
150  const qint64 deltaTimeMs = now - started;
151  msgs.push_back(CStatusMessage(this, CStatusMessage::SeverityInfo,
152  QStringLiteral("Validated in %1ms").arg(deltaTimeMs)));
154  msgs.freezeOrder();
155 
156  QWriteLocker l(&m_lock);
157  m_lastResultValid = valid;
158  m_lastResultInvalid = invalid;
159  m_lastResultWasStopped = m_wasStopped;
160  m_lastResultSimulator = simulator;
161  m_lastResultMsgs = msgs;
162  m_checkedSimulatorMsgs.insert(simulator, msgs);
163  }
164  while (false);
165 
166  m_inWork = false;
167  if (isTimerBased)
168  {
169  m_timerBasedRuns++;
170 
171  // stop timer after some runs
172  if (m_timerBasedRuns > 3) { m_updateTimer.stopTimer(); }
173  }
174 
175  emit this->validating(false);
176  if (validated)
177  {
178  const bool e = !onlyErrorsAndWarnings || (!invalid.isEmpty() || msgs.hasWarningOrErrorMessages());
179  if (e || !isTimerBased) { emit this->validated(simulator, valid, invalid, m_wasStopped, msgs); }
180  }
181  }
182 } // namespace swift::misc::simulation
Base class for a long-lived worker object which lives in its own thread.
Definition: worker.h:299
static const QString & worker()
Background task.
static const QString & modelSetCache()
Model set cache.
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
constexpr static auto SeverityInfo
Status severities.
constexpr static auto SeverityWarning
Status severities.
Status messages, e.g. from Core -> GUI.
bool hasWarningOrErrorMessages() const
Warning or error messages.
void sortBySeverityHighestFirst()
Sort by severity, highest first.
void stopTimer()
Safely stop update time.
void startTimer(std::chrono::milliseconds ms)
Start updating (start timer)
bool hasStarted() const
True if the worker has started.
Definition: worker.h:182
void freezeOrder()
Current order of list will be new order values.
Value object encapsulating a list of aircraft models.
static CStatusMessageList validateModelFiles(const CSimulatorInfo &simulator, const CAircraftModelList &models, CAircraftModelList &validModels, CAircraftModelList &invalidModels, bool ignoreEmpty, int stopAtFailedFiles, std::atomic_bool &wasStopped, const QString &simulatorDir)
Validate aircraft.cfg entries.
bool wasAlreadyChecked(const CSimulatorInfo &simulator) const
Was already checked for simulator?
swift::misc::simulation::CSimulatorInfo getCurrentSimulator() const
Corresponding simulator.
void validating(bool running)
Validating.
bool requestLastValidationResults()
Request last results (again), if there are any.
void startUpdating(std::chrono::milliseconds ms)
Start the updating timer.
void setCurrentSimulator(const CSimulatorInfo &simulator, const QString &simDirectory, const QStringList &modelDirList)
Corresponding simulator.
virtual void beforeQuit() noexcept
Called before quit is called.
void resetAlreadyChecked(const CSimulatorInfo &simulator)
Reset checked for simulator.
bool triggerValidation(const CSimulatorInfo &simulator, const QString &simDirectory)
Trigger a validation, returns false if "work in progress".
void validated(const CSimulatorInfo &simulator, const CAircraftModelList &validModels, const CAircraftModelList &invalidModels, bool stopped, const CStatusMessageList &msgs)
Validated for simulator.
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
bool isNoSimulator() const
No simulator?
bool isUnspecified() const
Unspecified simulator.
CAircraftModelList getCachedModels(const CSimulatorInfo &simulator) const
Models for simulator.
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...
Definition: threadutils.h:30