24 #include <QJsonDocument> 42 #ifdef USING_XMLPATTERNS 48 #ifdef USING_GRAPHVIZ_LIBS 49 #include <graphviz/gvc.h> 65 TorcHTTPService(this, QStringLiteral(
"central"), QStringLiteral(
"central"),
TorcCentral::staticMetaObject, QStringLiteral(
"")),
66 m_config(QVariantMap()),
77 if (QFile::exists(graphdot))
78 QFile::remove(graphdot);
79 if (QFile::exists(graphsvg))
80 QFile::remove(graphsvg);
81 if (QFile::exists(config))
82 QFile::remove(config);
84 QFile currentconfig(current);
85 if (!currentconfig.copy(config))
86 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Failed to copy current config file to content directory"));
96 if (m_config.contains(QStringLiteral(
"settings")))
98 QVariantMap settings = m_config.value(QStringLiteral(
"settings")).toMap();
101 if (settings.contains(QStringLiteral(
"applicationname")))
103 QString name = settings.value(QStringLiteral(
"applicationname")).toString().trimmed();
106 QCoreApplication::setApplicationName(name);
107 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Changed application name to '%1'").arg(name));
112 if (settings.contains(QStringLiteral(
"temperatureunits")))
114 QString units = settings.value(QStringLiteral(
"temperatureunits")).toString().trimmed().toLower();
115 if (units == QStringLiteral(
"metric") || units == QStringLiteral(
"celsius"))
117 else if (units == QStringLiteral(
"imperial") || units == QStringLiteral(
"fahrenheit"))
120 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Unknown temperature units - defaulting to metric (Celsius)"));
125 temperatureUnits = TorcCoreUtils::EnumToLowerString<TorcCentral::TemperatureUnits>(temperatureunits);
126 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Using '%1' temperature units").arg(
temperatureUnits));
132 TorcControls::gControls->Validate();
137 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Initialising state machine"));
147 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Notifying start"));
153 m_graph.append(QStringLiteral(
"strict digraph \"%1\" {\r\n" 154 " rankdir=\"LR\";\r\n" 155 " node [shape=rect];\r\n")
159 TorcInputs::gInputs->Graph(&m_graph);
160 TorcOutputs::gOutputs->Graph(&m_graph);
161 TorcControls::gControls->Graph(&m_graph);
165 m_graph.append(
"}\r\n");
167 QFile file(graphdot);
168 if (file.open(QIODevice::ReadWrite))
173 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Saved state graph as %1").arg(graphdot));
177 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to open '%1' to write state graph").arg(graphdot));
181 #ifdef USING_GRAPHVIZ_LIBS 182 bool created =
false;
184 FILE *handle = fopen(graphsvg.toLocal8Bit().data(),
"w");
187 GVC_t *gvc = gvContext();
188 Agraph_t *g = agmemread(m_graph.data());
189 gvLayout(gvc, g,
"dot");
190 gvRender(gvc, g,
"svg", handle);
199 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Failed to open '%1' for writing (err: %2)").arg(graphsvg, strerror(errno)));
206 QString command = QStringLiteral(
"dot -Tsvg -o %1 %2").arg(graphsvg, graphdot);
207 int err = system(command.toLocal8Bit());
210 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to create stategraph representation (err: %1)").arg(strerror(errno)));
214 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Saved state graph representation as %1").arg(graphsvg));
216 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"dot returned an unexpected result - stategraph may be incomplete or absent"));
219 #ifdef USING_GRAPHVIZ_LIBS 237 return tr(
"Central");
250 bool TorcCentral::LoadConfig(
void)
252 bool skipvalidation =
false;
254 if (!qEnvironmentVariableIsEmpty(
"TORC_NO_VALIDATION"))
256 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Skipping configuration file validation (command line)."));
257 skipvalidation =
true;
261 QFileInfo config(xml);
262 if (!skipvalidation && !config.exists())
264 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to find configuration file '%1'").arg(xml));
268 #if defined(USING_XMLPATTERNS) || defined(USING_LIBXML2) 273 if (QFile::exists(customxsd))
275 QFile customxsdfile(customxsd);
276 if (customxsdfile.open(QIODevice::ReadOnly))
278 oldxsd = customxsdfile.readAll();
279 customxsdfile.close();
281 QFile::remove(customxsd);
285 if (!QFile::exists(basexsd))
287 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to find base XSD file '%1'").arg(basexsd));
297 if (!newxsd.isEmpty())
300 QFile customxsdfile(customxsd);
301 if (customxsdfile.open(QIODevice::ReadWrite))
303 customxsdfile.write(newxsd);
304 customxsdfile.flush();
305 customxsdfile.close();
306 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Saved current XSD as '%1'").arg(customxsd));
310 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Failed to open '%1' for writing").arg(customxsd));
315 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Strange - empty xsd..."));
322 QString lastvalidated =
gLocalContext->
GetSetting(QStringLiteral(
"configLastValidated"), QStringLiteral(
"never"));
323 if (!skipvalidation && lastvalidated != QStringLiteral(
"never"))
325 bool xsdmodified = qstrcmp(oldxsd.constData(), newxsd.constData()) != 0;
326 bool configmodified = config.lastModified() >= QDateTime::fromString(lastvalidated);
329 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"XSD file changed since last validation"));
331 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"XSD unchanged since last validation"));
334 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Configuration file changed since last validation"));
336 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Configuration file unchanged since last validation:"));
338 skipvalidation = !xsdmodified && !configmodified;
343 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Starting validation of configuration file"));
347 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Configuration file '%1' failed validation").arg(xml));
353 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Configuration successfully validated"));
358 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Skipping validation of configuration file"));
361 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Xml validation unavailable - not validating configuration file."));
369 LOG(VB_GENERAL, LOG_ERR, error);
376 if (!result.contains(QStringLiteral(
"torc")))
378 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to find 'torc' root element in '%1'").arg(xml));
382 m_config = result.value(QStringLiteral(
"torc")).toMap();
384 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Loaded config from %1").arg(xml));
391 if (!QFile::exists(BaseXSDFile))
393 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Base XSD file '%1' does not exist").arg(BaseXSDFile));
397 QFile xsd(BaseXSDFile);
398 if (!xsd.open(QIODevice::ReadOnly))
400 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to open base XSD file '%1'").arg(BaseXSDFile));
404 result = xsd.readAll();
426 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Resetting devices to defaults."));
440 return QObject::event(Event);
463 Strings.insert(QStringLiteral(
"CelsiusTr"), QCoreApplication::translate(
"TorcCentral",
"Celsius"));
464 Strings.insert(QStringLiteral(
"CelsiusUnitsTr"), QCoreApplication::translate(
"TorcCentral",
"°C"));
465 Strings.insert(QStringLiteral(
"FahrenheitTr"), QCoreApplication::translate(
"TorcCentral",
"Fahrenheit"));
466 Strings.insert(QStringLiteral(
"FahrenheitUnitsTr"), QCoreApplication::translate(
"TorcCentral",
"°F"));
489 : nextTorcXSDFactory(gTorcXSDFactory)
508 QStringList identifiers;
513 QMultiMap<QString,QString> xsds;
518 foreach (
const QString &ident, identifiers)
521 QMultiMap<QString,QString>::const_iterator it = xsds.constBegin();
522 for ( ; it != xsds.constEnd(); ++it)
523 if (it.key() == ident)
524 replacewith += it.value();
525 XSD.replace(ident, replacewith.toLatin1());
TorcXSDFactory * NextFactory(void) const
static QByteArray GetCustomisedXSD(const QString &BaseXSDFile)
void SubscriberDeleted(QObject *Subscriber)
TorcLocalContext * gLocalContext
#define XSD_NOTIFIERTYPES
A factory class for automatically running objects outside of the main loop.
int GetEvent(void)
Return the Torc action associated with this event.
QString GetTorcShareDir(void)
Return the path to the installed Torc shared resources.
void Graph(QByteArray *Data)
QString GetTemperatureUnits(void)
virtual void GetXSD(QMultiMap< QString, QString > &XSD)=0
static TemperatureUnits gTemperatureUnits
Create the central controller object.
static TorcXSDFactory * GetTorcXSDFactory(void)
#define XSD_NOTIFICATIONTYPES
static void CustomiseXSD(QByteArray &XSD)
Customise the given base XSD with additional elements.
void SetSetting(const QString &Name, const QString &Value)
static TemperatureUnits GetGlobalTemperatureUnits(void)
static void NotifyEvent(int Event)
static QMutex * gDeviceListLock
static QHash< QString, TorcDevice * > * gDeviceList
static void Start(const QVariantMap &Details)
#define TORC_ADMIN_LOW_PRIORITY
QVariantMap GetResult(void) const
bool IsValid(QString &Message) const
TorcCentralObject TorcCentralObject
TorcXSDFactory * nextTorcXSDFactory
bool event(QEvent *Event) override
Handle Exit events.
#define XSD_NOTIFICATIONS
static bool RegisterEnvironmentVariable(const QString &Var, const QString &Description)
Register an environment variable for display via the help option.
QString GetUIName(void) override
void HandleSubscriberDeleted(QObject *Subscriber)
QString GetSetting(const QString &Name, const QString &DefaultValue)
QString GetTorcContentDir(void)
brief Return the path to generated content
A general purpose event object.
#define LOG(_MASK_, _LEVEL_, _STRING_)
void AddObserver(QObject *Observer)
brief Register the given object to receive events.
static TorcXSDFactory * gTorcXSDFactory
void GetStrings(QVariantMap &Strings)
A factory class to register translatable strings for use with external interfaces/applications.
void RemoveObserver(QObject *Observer)
brief Deregister the given object.
bool Validated(void) const
QString GetTorcConfigDir(void)
Return the path to the application configuration directory.
static TorcNotify * gNotify