Compare commits
10 Commits
abd8dd2d97
...
5b73038726
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b73038726 | ||
|
|
0070d7e3dd | ||
|
|
ab61ed9a8b | ||
|
|
3c7e1bed4f | ||
|
|
89ad2d0f12 | ||
|
|
028da6a3b4 | ||
|
|
b58c5646df | ||
|
|
53b00a950f | ||
|
|
5eb5c6628b | ||
|
|
a1d0574e20 |
@ -1,3 +1,20 @@
|
||||
nymea (1.14.2) noble; urgency=medium
|
||||
|
||||
[ Simon Stürz ]
|
||||
* Improve system update plugin API
|
||||
|
||||
-- jenkins <developer@nymea.io> Thu, 19 Feb 2026 16:27:40 +0100
|
||||
|
||||
nymea (1.14.1) noble; urgency=medium
|
||||
|
||||
[ Simon Stürz ]
|
||||
* LogEngine: Improve behavior of disabled logengine
|
||||
* JsonRpc Server: Improve token verification handling
|
||||
* Update default loations for the mac-addresses.db to be more generic
|
||||
* Thing: Add state name based set method for possible values
|
||||
|
||||
-- jenkins <developer@nymea.io> Tue, 10 Feb 2026 12:05:47 +0100
|
||||
|
||||
nymea (1.14.0) noble; urgency=medium
|
||||
|
||||
[ Simon Stürz ]
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include <QFileInfo>
|
||||
#include <QTimer>
|
||||
#include <QSqlDatabase>
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
@ -41,18 +42,30 @@ MacAddressDatabase::MacAddressDatabase(QObject *parent) : QObject(parent)
|
||||
{
|
||||
// Find database in system data locations
|
||||
QString databaseFileName;
|
||||
foreach (const QString &dataLocation, QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) {
|
||||
QFileInfo databaseFileInfo(dataLocation + QDir::separator() + "mac-addresses.db");
|
||||
if (!databaseFileInfo.exists()) {
|
||||
continue;
|
||||
const QStringList dataLocations = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
|
||||
foreach (const QString &dataLocation, dataLocations) {
|
||||
const QStringList candidateFiles = {
|
||||
dataLocation + QDir::separator() + "nymea" + QDir::separator() + "nymead" + QDir::separator() + "mac-addresses.db",
|
||||
dataLocation + QDir::separator() + "nymea" + QDir::separator() + "mac-addresses.db",
|
||||
dataLocation + QDir::separator() + "mac-addresses.db"
|
||||
};
|
||||
|
||||
foreach (const QString &candidate, candidateFiles) {
|
||||
QFileInfo databaseFileInfo(candidate);
|
||||
if (!databaseFileInfo.exists())
|
||||
continue;
|
||||
|
||||
databaseFileName = databaseFileInfo.absoluteFilePath();
|
||||
break;
|
||||
}
|
||||
|
||||
databaseFileName = databaseFileInfo.absoluteFilePath();
|
||||
break;
|
||||
if (!databaseFileName.isEmpty())
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (databaseFileName.isEmpty()) {
|
||||
qCWarning(dcMacAddressDatabase()) << "Could not find the mac address database in any system data location paths" << QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
|
||||
qCWarning(dcMacAddressDatabase()) << "Could not find the mac address database in any system data location paths" << dataLocations;
|
||||
qCWarning(dcMacAddressDatabase()) << "The mac address database lookup feature will not be available.";
|
||||
return;
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ private:
|
||||
QSqlDatabase m_db;
|
||||
bool m_available = false;
|
||||
QString m_connectionName;
|
||||
QString m_databaseName = "/usr/share/nymea/mac-addresses.db";
|
||||
QString m_databaseName = "/usr/share/nymea/nymead/mac-addresses.db";
|
||||
|
||||
MacAddressDatabaseReplyImpl *m_currentReply = nullptr;
|
||||
QFutureWatcher<QString> *m_futureWatcher = nullptr;
|
||||
|
||||
@ -789,7 +789,7 @@ JsonReply *IntegrationsHandler::GetThings(const QVariantMap ¶ms, const JsonC
|
||||
QVariantMap returns;
|
||||
QVariantList things;
|
||||
|
||||
if (NymeaCore::instance()->userManager()->hasRestrictedThingAccess(context.token())) {
|
||||
if (NymeaCore::instance()->userManager()->hasRestrictedThingAccess(context.token()) && context.authenticationEnabled()) {
|
||||
// Restricted things access
|
||||
QList<ThingId> allowedThingIds = NymeaCore::instance()->userManager()->getAllowedThingIdsForToken(context.token());
|
||||
if (params.contains("thingId")) {
|
||||
@ -983,7 +983,7 @@ JsonReply *IntegrationsHandler::GetStateTypes(const QVariantMap ¶ms, const J
|
||||
JsonReply *IntegrationsHandler::GetStateValue(const QVariantMap ¶ms, const JsonContext &context) const
|
||||
{
|
||||
ThingId thingId(params.value("thingId").toString());
|
||||
if (!NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
if (context.authenticationEnabled() && !NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||
|
||||
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
||||
@ -1002,7 +1002,7 @@ JsonReply *IntegrationsHandler::GetStateValue(const QVariantMap ¶ms, const J
|
||||
JsonReply *IntegrationsHandler::GetStateValues(const QVariantMap ¶ms, const JsonContext &context) const
|
||||
{
|
||||
ThingId thingId(params.value("thingId").toString());
|
||||
if (!NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
if (context.authenticationEnabled() && !NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||
|
||||
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
||||
@ -1017,7 +1017,7 @@ JsonReply *IntegrationsHandler::GetStateValues(const QVariantMap ¶ms, const
|
||||
JsonReply *IntegrationsHandler::BrowseThing(const QVariantMap ¶ms, const JsonContext &context) const
|
||||
{
|
||||
ThingId thingId(params.value("thingId").toString());
|
||||
if (!NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
if (context.authenticationEnabled() && !NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||
|
||||
QString itemId = params.value("itemId").toString();
|
||||
@ -1047,7 +1047,7 @@ JsonReply *IntegrationsHandler::BrowseThing(const QVariantMap ¶ms, const Jso
|
||||
JsonReply *IntegrationsHandler::GetBrowserItem(const QVariantMap ¶ms, const JsonContext &context) const
|
||||
{
|
||||
ThingId thingId(params.value("thingId").toString());
|
||||
if (!NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
if (context.authenticationEnabled() && !NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||
|
||||
QString itemId = params.value("itemId").toString();
|
||||
@ -1072,7 +1072,7 @@ JsonReply *IntegrationsHandler::GetBrowserItem(const QVariantMap ¶ms, const
|
||||
JsonReply *IntegrationsHandler::ExecuteAction(const QVariantMap ¶ms, const JsonContext &context)
|
||||
{
|
||||
ThingId thingId(params.value("thingId").toString());
|
||||
if (!NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
if (context.authenticationEnabled() && !NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||
|
||||
ActionTypeId actionTypeId(params.value("actionTypeId").toString());
|
||||
@ -1101,7 +1101,7 @@ JsonReply *IntegrationsHandler::ExecuteAction(const QVariantMap ¶ms, const J
|
||||
JsonReply *IntegrationsHandler::ExecuteBrowserItem(const QVariantMap ¶ms, const JsonContext &context)
|
||||
{
|
||||
ThingId thingId = ThingId(params.value("thingId").toString());
|
||||
if (!NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
if (context.authenticationEnabled() && !NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||
|
||||
QString itemId = params.value("itemId").toString();
|
||||
@ -1126,7 +1126,7 @@ JsonReply *IntegrationsHandler::ExecuteBrowserItem(const QVariantMap ¶ms, co
|
||||
JsonReply *IntegrationsHandler::ExecuteBrowserItemAction(const QVariantMap ¶ms, const JsonContext &context)
|
||||
{
|
||||
ThingId thingId = ThingId(params.value("thingId").toString());
|
||||
if (!NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
if (context.authenticationEnabled() && !NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||
|
||||
QString itemId = params.value("itemId").toString();
|
||||
@ -1153,7 +1153,7 @@ JsonReply *IntegrationsHandler::ExecuteBrowserItemAction(const QVariantMap ¶
|
||||
JsonReply *IntegrationsHandler::GetIOConnections(const QVariantMap ¶ms, const JsonContext &context)
|
||||
{
|
||||
ThingId thingId = params.value("thingId").toUuid();
|
||||
if (!NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
if (context.authenticationEnabled() && !NymeaCore::instance()->userManager()->accessToThingGranted(thingId, context.token()))
|
||||
return createReply(statusToReply(Thing::ThingErrorThingNotFound));
|
||||
|
||||
IOConnections ioConnections = m_thingManager->ioConnections(thingId);
|
||||
|
||||
@ -603,7 +603,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
|
||||
}
|
||||
|
||||
// check if authentication is required for this transport
|
||||
if (interface->configuration().authenticationEnabled) {
|
||||
if (interface->configuration().authenticationEnabled) {
|
||||
QStringList authExemptMethodsNoUser = {"JSONRPC.Hello", "JSONRPC.RequestPushButtonAuth", "JSONRPC.CreateUser"};
|
||||
QStringList authExemptMethodsWithUser = {"JSONRPC.Hello", "JSONRPC.Authenticate", "JSONRPC.RequestPushButtonAuth"};
|
||||
// if there is no user in the system yet, let's fail unless this is a special method for authentication itself
|
||||
@ -617,7 +617,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// ok, we have a user. if there isn't a valid token, let's fail unless this is a Authenticate, Introspect Hello call
|
||||
// Ok, we have a user. If there isn't a valid token, let's fail unless this is an authentication related call
|
||||
if (!authExemptMethodsWithUser.contains(methodString)) {
|
||||
if (token.isEmpty() || !NymeaCore::instance()->userManager()->verifyToken(token)) {
|
||||
sendUnauthorizedResponse(interface, clientId, commandId, "Forbidden: Invalid token.");
|
||||
@ -681,7 +681,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
|
||||
handler->setProperty("transportInterface", reinterpret_cast<qint64>(interface));
|
||||
}
|
||||
|
||||
JsonContext callContext(clientId, m_clientLocales.value(clientId));
|
||||
JsonContext callContext(clientId, m_clientLocales.value(clientId), interface->configuration().authenticationEnabled);
|
||||
callContext.setToken(token);
|
||||
|
||||
qCDebug(dcJsonRpc()) << "Invoking method" << targetNamespace + '.' + method << "from client" << clientId;
|
||||
@ -809,7 +809,9 @@ void JsonRPCServerImplementation::sendClientNotification(const QVariantMap ¶
|
||||
continue;
|
||||
|
||||
// Make sure this client is allowed to receive this notification
|
||||
if (m_clientTokens.contains(clientId)) {
|
||||
TransportInterface *transport = m_clientTransports.value(clientId, nullptr);
|
||||
const bool authEnabled = transport ? transport->configuration().authenticationEnabled : true;
|
||||
if (authEnabled && m_clientTokens.contains(clientId)) {
|
||||
const QByteArray token = m_clientTokens.value(clientId);
|
||||
if (!NymeaCore::instance()->userManager()->accessToThingGranted(thingId, token)) {
|
||||
qCDebug(dcJsonRpc()) << "Not sending notification to client" << "to client" << clientId.toString()
|
||||
@ -849,9 +851,24 @@ void JsonRPCServerImplementation::sendClientNotification(const QVariantMap ¶
|
||||
{
|
||||
// Send client specific notifications
|
||||
qCDebug(dcJsonRpc()) << "Sending notification to client" << userInfo.username() << "connections...";
|
||||
foreach (const QByteArray &token, m_clientTokens) {
|
||||
for (auto it = m_clientTokens.constBegin(); it != m_clientTokens.constEnd(); ++it) {
|
||||
const QUuid clientId = it.key();
|
||||
const QByteArray token = it.value();
|
||||
|
||||
TransportInterface *transport = m_clientTransports.value(clientId, nullptr);
|
||||
const bool authEnabled = transport ? transport->configuration().authenticationEnabled : true;
|
||||
|
||||
if (!authEnabled) {
|
||||
sendClientNotification(clientId, params);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NymeaCore::instance()->userManager()->tokenInfo(token).username() == userInfo.username()) {
|
||||
sendClientNotification(m_clientTokens.key(token), params);
|
||||
sendClientNotification(clientId, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,15 +38,18 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent):
|
||||
registerObject<Package, Packages>();
|
||||
registerObject<Repository, Repositories>();
|
||||
|
||||
registerEnum<PlatformUpdateController::UpdateType>();
|
||||
|
||||
// Methods
|
||||
QString description; QVariantMap params; QVariantMap returns;
|
||||
description = "Get the list of capabilites on this system. The property \"powerManagement\" indicates whether "
|
||||
"restarting nymea and rebooting or shutting down is supported on this system. The property \"updateManagement indicates "
|
||||
"whether system update features are available in this system. The property \"timeManagement\" "
|
||||
"indicates whether the system time can be configured on this system. Note that GetTime will be "
|
||||
"available in any case.";
|
||||
"restarting nymea and rebooting or shutting down is supported on this system. The property \"updateManagement\" indicates "
|
||||
"whether system update features are available in this system. The \"updateManagementType\" indicates which kind of update is "
|
||||
"supported on this platform. The property \"timeManagement\" indicates whether the system time can be configured "
|
||||
"on this system. Note that GetTime will be available in any case.";
|
||||
returns.insert("powerManagement", enumValueName(Bool));
|
||||
returns.insert("updateManagement", enumValueName(Bool));
|
||||
returns.insert("updateManagementType", enumRef<PlatformUpdateController::UpdateType>());
|
||||
returns.insert("timeManagement", enumValueName(Bool));
|
||||
registerMethod("GetCapabilities", description, params, returns);
|
||||
|
||||
@ -66,15 +69,17 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent):
|
||||
registerMethod("Shutdown", description, params, returns);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Get the current status of the update system. \"busy\" indicates that the system is current busy with "
|
||||
"an operation regarding updates. This does not necessarily mean an actual update is running. When this "
|
||||
"is true, update related functions on the client should be marked as busy and no interaction with update "
|
||||
"components shall be allowed. An example for such a state is when the system queries the server if there "
|
||||
"are updates available, typically after a call to CheckForUpdates. \"updateRunning\" on the other hand "
|
||||
"indicates an actual update process is ongoing. The user should be informed about it, the system also "
|
||||
"might restart at any point while an update is running.";
|
||||
description = "Get the current status of the update system. \"busy\" indicates that the system is current busy with "
|
||||
"an operation regarding updates. This does not necessarily mean an actual update is running. When this "
|
||||
"is true, update related functions on the client should be marked as busy and no interaction with update "
|
||||
"components shall be allowed. An example for such a state is when the system queries the server if there "
|
||||
"are updates available, typically after a call to CheckForUpdates. \"updateRunning\" on the other hand "
|
||||
"indicates an actual update process is ongoing. The user should be informed about it, the system also "
|
||||
"might restart at any point while an update is running. The \"updateProgress\" property is optional, "
|
||||
"if the backend supports it, a progress >= 0 indicated the update progress in percentage.";
|
||||
returns.insert("busy", enumValueName(Bool));
|
||||
returns.insert("updateRunning", enumValueName(Bool));
|
||||
returns.insert("o:updateProgress", enumValueName(Int));
|
||||
registerMethod("GetUpdateStatus", description, params, returns);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
@ -172,12 +177,14 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent):
|
||||
description = "Emitted whenever the system capabilities change.";
|
||||
params.insert("powerManagement", enumValueName(Bool));
|
||||
params.insert("updateManagement", enumValueName(Bool));
|
||||
params.insert("updateManagementType", enumRef<PlatformUpdateController::UpdateType>());
|
||||
registerNotification("CapabilitiesChanged", description, params);
|
||||
|
||||
params.clear();
|
||||
description = "Emitted whenever the update status changes.";
|
||||
params.insert("busy", enumValueName(Bool));
|
||||
params.insert("updateRunning", enumValueName(Bool));
|
||||
params.insert("o:updateProgress", enumValueName(Int));
|
||||
registerNotification("UpdateStatusChanged", description, params);
|
||||
|
||||
params.clear();
|
||||
@ -220,18 +227,17 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent):
|
||||
|
||||
connect(m_platform->systemController(), &PlatformSystemController::availableChanged, this, &SystemHandler::onCapabilitiesChanged);
|
||||
connect(m_platform->updateController(), &PlatformUpdateController::availableChanged, this, &SystemHandler::onCapabilitiesChanged);
|
||||
|
||||
connect(m_platform->updateController(), &PlatformUpdateController::busyChanged, this, [this](){
|
||||
QVariantMap params;
|
||||
params.insert("busy", m_platform->updateController()->busy());
|
||||
params.insert("updateRunning", m_platform->updateController()->updateRunning());
|
||||
emit UpdateStatusChanged(params);
|
||||
emit UpdateStatusChanged(buildUpdateStatus());
|
||||
});
|
||||
connect(m_platform->updateController(), &PlatformUpdateController::updateRunningChanged, this, [this](){
|
||||
QVariantMap params;
|
||||
params.insert("busy", m_platform->updateController()->busy());
|
||||
params.insert("updateRunning", m_platform->updateController()->updateRunning());
|
||||
emit UpdateStatusChanged(params);
|
||||
emit UpdateStatusChanged(buildUpdateStatus());
|
||||
});
|
||||
connect(m_platform->updateController(), &PlatformUpdateController::updateProgressChanged, this, [this](){
|
||||
emit UpdateStatusChanged(buildUpdateStatus());
|
||||
});
|
||||
|
||||
connect(m_platform->updateController(), &PlatformUpdateController::packageAdded, this, [this](const Package &package){
|
||||
QVariantMap params;
|
||||
params.insert("package", pack(package));
|
||||
@ -247,6 +253,7 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent):
|
||||
params.insert("packageId", packageId);
|
||||
emit PackageRemoved(params);
|
||||
});
|
||||
|
||||
connect(m_platform->updateController(), &PlatformUpdateController::repositoryAdded, this, [this](const Repository &repository){
|
||||
QVariantMap params;
|
||||
params.insert("repository", pack(repository));
|
||||
@ -262,6 +269,7 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent):
|
||||
params.insert("repositoryId", repositoryId);
|
||||
emit RepositoryRemoved(params);
|
||||
});
|
||||
|
||||
connect(m_platform->systemController(), &PlatformSystemController::timeConfigurationChanged, this, [this](){
|
||||
QVariantMap params;
|
||||
params.insert("time", QDateTime::currentMSecsSinceEpoch() / 1000);
|
||||
@ -283,6 +291,7 @@ JsonReply *SystemHandler::GetCapabilities(const QVariantMap ¶ms)
|
||||
QVariantMap data;
|
||||
data.insert("powerManagement", m_platform->systemController()->powerManagementAvailable());
|
||||
data.insert("updateManagement", m_platform->updateController()->updateManagementAvailable());
|
||||
data.insert("updateManagementType", enumValueName(m_platform->updateController()->updateType()));
|
||||
data.insert("timeManagement", m_platform->systemController()->timeManagementAvailable());
|
||||
return createReply(data);
|
||||
}
|
||||
@ -317,10 +326,7 @@ JsonReply *SystemHandler::Shutdown(const QVariantMap ¶ms) const
|
||||
JsonReply *SystemHandler::GetUpdateStatus(const QVariantMap ¶ms) const
|
||||
{
|
||||
Q_UNUSED(params)
|
||||
QVariantMap ret;
|
||||
ret.insert("busy", m_platform->updateController()->busy());
|
||||
ret.insert("updateRunning", m_platform->updateController()->updateRunning());
|
||||
return createReply(ret);
|
||||
return createReply(buildUpdateStatus());
|
||||
}
|
||||
|
||||
JsonReply *SystemHandler::CheckForUpdates(const QVariantMap ¶ms) const
|
||||
@ -459,7 +465,19 @@ void SystemHandler::onCapabilitiesChanged()
|
||||
QVariantMap caps;
|
||||
caps.insert("powerManagement", m_platform->systemController()->powerManagementAvailable());
|
||||
caps.insert("updateManagement", m_platform->updateController()->updateManagementAvailable());
|
||||
caps.insert("updateManagementType", enumValueName(m_platform->updateController()->updateType()));
|
||||
emit CapabilitiesChanged(caps);
|
||||
}
|
||||
|
||||
QVariantMap SystemHandler::buildUpdateStatus() const
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("busy", m_platform->updateController()->busy());
|
||||
params.insert("updateRunning", m_platform->updateController()->updateRunning());
|
||||
if (m_platform->updateController()->updateProgress() >= 0)
|
||||
params.insert("updateProgress", m_platform->updateController()->updateProgress());
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -82,6 +82,8 @@ private slots:
|
||||
|
||||
private:
|
||||
Platform *m_platform = nullptr;
|
||||
|
||||
QVariantMap buildUpdateStatus() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -189,15 +189,21 @@ JsonReply *UsersHandler::ChangePassword(const QVariantMap ¶ms, const JsonCon
|
||||
QVariantMap returns;
|
||||
|
||||
QByteArray currentToken = context.token();
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot change password from an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
if (context.authenticationEnabled()) {
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot change password from an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
} else if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot change password without token even if authentication is disabled for the transport";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
@ -216,15 +222,21 @@ JsonReply *UsersHandler::ChangeUserPassword(const QVariantMap ¶ms, const Jso
|
||||
QVariantMap returns;
|
||||
|
||||
QByteArray currentToken = context.token();
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot change a user password from an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
if (context.authenticationEnabled()) {
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot change a user password from an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Cannot change a user password from an unauthenticated connection";
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Cannot change a user password from an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
} else if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot change a user password without token even if authentication is disabled for the transport";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
@ -244,15 +256,21 @@ JsonReply *UsersHandler::GetUserInfo(const QVariantMap ¶ms, const JsonContex
|
||||
QVariantMap returns;
|
||||
|
||||
QByteArray currentToken = context.token();
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot get user info from an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
if (context.authenticationEnabled()) {
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot get user info from an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
} else if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot get user info without token even if authentication is disabled for the transport";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
@ -272,15 +290,21 @@ JsonReply *UsersHandler::GetTokens(const QVariantMap ¶ms, const JsonContext
|
||||
QVariantMap returns;
|
||||
|
||||
QByteArray currentToken = context.token();
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot fetch tokens for an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
if (context.authenticationEnabled()) {
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot fetch tokens for an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
} else if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot fetch tokens without token even if authentication is disabled for the transport";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
@ -302,15 +326,21 @@ JsonReply *UsersHandler::GetUserTokens(const QVariantMap ¶ms, const JsonCont
|
||||
QVariantMap returns;
|
||||
|
||||
QByteArray currentToken = context.token();
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot fetch tokens for an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
if (context.authenticationEnabled()) {
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot fetch tokens for an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
} else if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot fetch tokens without token even if authentication is disabled for the transport";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
@ -333,15 +363,21 @@ JsonReply *UsersHandler::RemoveToken(const QVariantMap ¶ms, const JsonContex
|
||||
QVariantMap returns;
|
||||
|
||||
QByteArray currentToken = context.token();
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot remove a token from an unauthenticated connection.";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
if (context.authenticationEnabled()) {
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot remove a token from an unauthenticated connection.";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
if (!m_userManager->verifyToken(currentToken)) {
|
||||
// Might happen if the client is connecting via an unauthenticated connection but tries to sneak in an invalid token
|
||||
qCWarning(dcJsonRpc()) << "Invalid token. Is this an unauthenticated connection?";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
} else if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot remove a token without token even if authentication is disabled for the transport.";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
@ -414,7 +450,20 @@ JsonReply *UsersHandler::SetUserInfo(const QVariantMap ¶ms, const JsonContex
|
||||
{
|
||||
QVariantMap returns;
|
||||
|
||||
TokenInfo callingTokenInfo = m_userManager->tokenInfo(context.token());
|
||||
QByteArray currentToken = context.token();
|
||||
if (context.authenticationEnabled()) {
|
||||
if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot set user info from an unauthenticated connection";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
} else if (currentToken.isEmpty()) {
|
||||
qCWarning(dcJsonRpc()) << "Cannot set user info without token even if authentication is disabled for the transport";
|
||||
returns.insert("error", enumValueName<UserManager::UserError>(UserManager::UserErrorPermissionDenied));
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
TokenInfo callingTokenInfo = m_userManager->tokenInfo(currentToken);
|
||||
QString username;
|
||||
|
||||
if (params.contains("username")) {
|
||||
|
||||
@ -24,18 +24,18 @@
|
||||
|
||||
#include "logengineinfluxdb.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QUrlQuery>
|
||||
#include <QJsonDocument>
|
||||
#include <QCoreApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkReply>
|
||||
#include <QRegularExpression>
|
||||
#include <QUrlQuery>
|
||||
|
||||
LogEngineInfluxDB::LogEngineInfluxDB(const QString &host, const QString &dbName, const QString &username, const QString &password, QObject *parent)
|
||||
: LogEngine{parent},
|
||||
m_host(host),
|
||||
m_dbName(dbName),
|
||||
m_username(username),
|
||||
m_password(password)
|
||||
: LogEngine{parent}
|
||||
, m_host(host)
|
||||
, m_dbName(dbName)
|
||||
, m_username(username)
|
||||
, m_password(password)
|
||||
{
|
||||
m_nam = new QNetworkAccessManager(this);
|
||||
|
||||
@ -53,7 +53,7 @@ LogEngineInfluxDB::~LogEngineInfluxDB()
|
||||
qCInfo(dcLogEngine()) << "Waiting for" << (m_initQueryQueue.count() + m_queryQueue.count() + m_writeQueue.count()) << "jobs to finish... Init status:" << m_initStatus;
|
||||
}
|
||||
while (jobsRunning()) {
|
||||
// qCDebug(dcLogEngine()) << "Waiting for logs to finish processing." << m_writeQueue.count() << "jobs pending...";
|
||||
// qCDebug(dcLogEngine()) << "Waiting for logs to finish processing." << m_writeQueue.count() << "jobs pending...";
|
||||
processQueues();
|
||||
qApp->processEvents();
|
||||
}
|
||||
@ -66,12 +66,12 @@ Logger *LogEngineInfluxDB::registerLogSource(const QString &name, const QStringL
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// qCDebug(dcLogEngine()) << "Registering log source" << name << "with tags" << tagNames;
|
||||
// qCDebug(dcLogEngine()) << "Registering log source" << name << "with tags" << tagNames;
|
||||
|
||||
Logger *logger = createLogger(name, tagNames, loggingType);
|
||||
m_loggers.insert(name, logger);
|
||||
|
||||
if (loggingType == Types::LoggingTypeSampled) {
|
||||
if (m_initStatus != InitStatusDisabled && loggingType == Types::LoggingTypeSampled) {
|
||||
qCDebug(dcLogEngine()) << "Setting up log sampling on" << sampleColumn;
|
||||
|
||||
if (sampleColumn.isEmpty()) {
|
||||
@ -84,55 +84,45 @@ Logger *LogEngineInfluxDB::registerLogSource(const QString &name, const QStringL
|
||||
columns.append(QString("MEAN(\"%1\") AS %1").arg(sampleColumn));
|
||||
QString target = columns.join(", ");
|
||||
|
||||
QueryJob *minutesJob = query(QString("CREATE CONTINUOUS QUERY \"minutes-%1\" "
|
||||
"ON \"nymea\" "
|
||||
"BEGIN "
|
||||
"SELECT %2 "
|
||||
"INTO minutes.\"%1\" "
|
||||
"FROM live.\"%1\" "
|
||||
"GROUP BY time(1m) "
|
||||
"fill(previous) "
|
||||
"END").arg(name).arg(target), true);
|
||||
connect(minutesJob, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &response){
|
||||
QueryJob *minutesJob = query(
|
||||
QString(
|
||||
"CREATE CONTINUOUS QUERY \"minutes-%1\" " "ON \"nymea\" " "BEGIN " "SELECT %2 " "INTO minutes.\"%1\" " "FROM live.\"%1\" " "GROUP BY time(1m) " "fill(previous)" " " "END")
|
||||
.arg(name)
|
||||
.arg(target),
|
||||
true);
|
||||
connect(minutesJob, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &response) {
|
||||
if (status == QNetworkReply::NoError) {
|
||||
qCDebug(dcLogEngine()) << "Created minute based continuous query for" << name << qUtf8Printable(QJsonDocument::fromVariant(response).toJson());
|
||||
} else {
|
||||
qCWarning(dcLogEngine()) << "Unable to create minute based continuous query for" << name << qUtf8Printable(QJsonDocument::fromVariant(response).toJson());
|
||||
}
|
||||
});
|
||||
QueryJob *hoursJob = query(QString("CREATE CONTINUOUS QUERY \"hours-%1\" "
|
||||
"ON \"nymea\" "
|
||||
"BEGIN "
|
||||
"SELECT %2 "
|
||||
"INTO hours.\"%1\" "
|
||||
"FROM minutes.\"%1\" "
|
||||
"GROUP BY time(1h) "
|
||||
"fill(previous) "
|
||||
"END").arg(name).arg(target), true);
|
||||
connect(hoursJob, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &response){
|
||||
QueryJob *hoursJob = query(
|
||||
QString(
|
||||
"CREATE CONTINUOUS QUERY \"hours-%1\" " "ON \"nymea\" " "BEGIN " "SELECT %2 " "INTO hours.\"%1\" " "FROM minutes.\"%1\" " "GROUP BY time(1h) " "fill(previous) " "END")
|
||||
.arg(name)
|
||||
.arg(target),
|
||||
true);
|
||||
connect(hoursJob, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &response) {
|
||||
if (status == QNetworkReply::NoError) {
|
||||
qCDebug(dcLogEngine()) << "Created hour based continuous query for" << name << qUtf8Printable(QJsonDocument::fromVariant(response).toJson());
|
||||
} else {
|
||||
qCWarning(dcLogEngine()) << "Unable to create hour based continuous query for" << name << qUtf8Printable(QJsonDocument::fromVariant(response).toJson());
|
||||
}
|
||||
});
|
||||
QueryJob *daysJob = query(QString("CREATE CONTINUOUS QUERY \"days-%1\" "
|
||||
"ON \"nymea\" "
|
||||
"BEGIN "
|
||||
"SELECT %2 "
|
||||
"INTO days.\"%1\" "
|
||||
"FROM hours.\"%1\" "
|
||||
"GROUP BY time(24h) "
|
||||
"fill(previous) "
|
||||
"END").arg(name).arg(target), true);
|
||||
connect(daysJob, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &response){
|
||||
QueryJob *daysJob = query(
|
||||
QString(
|
||||
"CREATE CONTINUOUS QUERY \"days-%1\" " "ON \"nymea\" " "BEGIN " "SELECT %2 " "INTO days.\"%1\" " "FROM hours.\"%1\" " "GROUP BY time(24h) " "fill(previous) " "END")
|
||||
.arg(name)
|
||||
.arg(target),
|
||||
true);
|
||||
connect(daysJob, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &response) {
|
||||
if (status == QNetworkReply::NoError) {
|
||||
qCDebug(dcLogEngine()) << "Created day based continuous query for" << name << qUtf8Printable(QJsonDocument::fromVariant(response).toJson());
|
||||
} else {
|
||||
qCWarning(dcLogEngine()) << "Unable to create days based continuous query for" << name << qUtf8Printable(QJsonDocument::fromVariant(response).toJson());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,12 +137,15 @@ void LogEngineInfluxDB::unregisterLogSource(const QString &name)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
QString queryString = QString("DROP MEASUREMENT \"%1\"").arg(name);
|
||||
if (m_initStatus == InitStatusOK)
|
||||
qCDebug(dcLogEngine()) << "Removing log entries:" << queryString;
|
||||
|
||||
QueryJob *job = query(queryString);
|
||||
connect(job, &QueryJob::finished, this, [name](bool success){
|
||||
connect(job, &QueryJob::finished, this, [name](bool success) {
|
||||
if (success) {
|
||||
qCDebug(dcLogEngine()) << "Removed log entries for source" << name;
|
||||
} else {
|
||||
@ -163,6 +156,9 @@ void LogEngineInfluxDB::unregisterLogSource(const QString &name)
|
||||
|
||||
void LogEngineInfluxDB::logEvent(Logger *logger, const QStringList &tags, const QVariantMap &values)
|
||||
{
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
QString measurement = logger->name();
|
||||
QStringList tagsList;
|
||||
QStringList fieldsList;
|
||||
@ -233,7 +229,7 @@ void LogEngineInfluxDB::processQueues()
|
||||
return;
|
||||
}
|
||||
|
||||
// qCDebug(dcLogEngine()) << "Processing queue:" << m_initStatus << "init count:" << m_initQueryQueue.count() << "query count:" << m_queryQueue.count() << "write count:" << m_writeQueue.count();
|
||||
// qCDebug(dcLogEngine()) << "Processing queue:" << m_initStatus << "init count:" << m_initQueryQueue.count() << "query count:" << m_queryQueue.count() << "write count:" << m_writeQueue.count();
|
||||
|
||||
if (!m_currentInitQuery && !m_initQueryQueue.isEmpty()) {
|
||||
QueryJob *job = m_initQueryQueue.takeFirst();
|
||||
@ -248,10 +244,14 @@ void LogEngineInfluxDB::processQueues()
|
||||
|
||||
m_currentInitQuery = job;
|
||||
|
||||
connect(reply, &QNetworkReply::finished, job, [=](){
|
||||
connect(reply, &QNetworkReply::finished, job, [=]() {
|
||||
m_currentInitQuery = nullptr;
|
||||
qCDebug(dcLogEngine()) << "Init query job finished";
|
||||
reply->deleteLater();
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
job->finish(reply->error());
|
||||
return;
|
||||
}
|
||||
if (reply->error() == QNetworkReply::ProtocolInvalidOperationError) {
|
||||
qCWarning(dcLogEngine()) << "Influx DB protocol error:" << reply->readAll();
|
||||
job->finish(reply->error());
|
||||
@ -259,6 +259,10 @@ void LogEngineInfluxDB::processQueues()
|
||||
}
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
job->finish(reply->error());
|
||||
return;
|
||||
}
|
||||
qCWarning(dcLogEngine()) << "Error in influxdb communication:" << reply->error() << reply->errorString() << "for query:" << job->m_request.url().toString();
|
||||
job->finish(reply->error());
|
||||
return;
|
||||
@ -276,7 +280,7 @@ void LogEngineInfluxDB::processQueues()
|
||||
});
|
||||
}
|
||||
|
||||
if (m_initStatus != InitStatusOK ) {
|
||||
if (m_initStatus != InitStatusOK) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -294,10 +298,15 @@ void LogEngineInfluxDB::processQueues()
|
||||
|
||||
m_currentQuery = job;
|
||||
|
||||
connect(reply, &QNetworkReply::finished, job, [=](){
|
||||
connect(reply, &QNetworkReply::finished, job, [=]() {
|
||||
qCDebug(dcLogEngine()) << "Query finished";
|
||||
m_currentQuery = nullptr;
|
||||
reply->deleteLater();
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
job->finish(reply->error());
|
||||
processQueues();
|
||||
return;
|
||||
}
|
||||
if (reply->error() == QNetworkReply::ProtocolInvalidOperationError) {
|
||||
qCWarning(dcLogEngine()) << "Influx DB protocol error:" << reply->readAll();
|
||||
job->finish(reply->error());
|
||||
@ -306,6 +315,11 @@ void LogEngineInfluxDB::processQueues()
|
||||
}
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
job->finish(reply->error());
|
||||
processQueues();
|
||||
return;
|
||||
}
|
||||
qCWarning(dcLogEngine()) << "Error in influxdb communication:" << reply->error() << reply->errorString();
|
||||
job->finish(reply->error());
|
||||
processQueues();
|
||||
@ -320,7 +334,7 @@ void LogEngineInfluxDB::processQueues()
|
||||
processQueues();
|
||||
return;
|
||||
}
|
||||
// qCDebug(dcLogEngine()) << "Reply" << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented));
|
||||
// qCDebug(dcLogEngine()) << "Reply" << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented));
|
||||
|
||||
job->finish(QNetworkReply::NoError, jsonDoc.toVariant().toMap().value("results").toList());
|
||||
|
||||
@ -341,11 +355,19 @@ void LogEngineInfluxDB::processQueues()
|
||||
qCDebug(dcLogEngine()) << "Started:" << reply->isRunning() << reply->isFinished();
|
||||
m_currentWriteReply = reply;
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [=](){
|
||||
connect(reply, &QNetworkReply::finished, this, [=]() {
|
||||
m_currentWriteReply = nullptr;
|
||||
reply->deleteLater();
|
||||
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
processQueues();
|
||||
return;
|
||||
}
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
processQueues();
|
||||
return;
|
||||
}
|
||||
qCWarning(dcLogEngine()) << "Unable to connect to influxdb. Cannot log events." << reply->error() << reply->readAll();
|
||||
processQueues();
|
||||
return;
|
||||
@ -362,10 +384,23 @@ void LogEngineInfluxDB::processQueues()
|
||||
}
|
||||
}
|
||||
|
||||
LogFetchJob *LogEngineInfluxDB::fetchLogEntries(const QStringList &sources, const QStringList &columns, const QDateTime &startTime, const QDateTime &endTime, const QVariantMap &filter, Types::SampleRate sampleRate, Qt::SortOrder sortOrder, int offset, int limit)
|
||||
LogFetchJob *LogEngineInfluxDB::fetchLogEntries(const QStringList &sources,
|
||||
const QStringList &columns,
|
||||
const QDateTime &startTime,
|
||||
const QDateTime &endTime,
|
||||
const QVariantMap &filter,
|
||||
Types::SampleRate sampleRate,
|
||||
Qt::SortOrder sortOrder,
|
||||
int offset,
|
||||
int limit)
|
||||
{
|
||||
LogFetchJob *job = new LogFetchJob(this);
|
||||
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
finishFetchJob(job, LogEntries());
|
||||
return job;
|
||||
}
|
||||
|
||||
// FIXME: injection attacks possible?
|
||||
QString what = "*";
|
||||
if (sampleRate == Types::SampleRateAny) {
|
||||
@ -386,7 +421,6 @@ LogFetchJob *LogEngineInfluxDB::fetchLogEntries(const QStringList &sources, cons
|
||||
|
||||
QStringList escapedSourced;
|
||||
foreach (const QString &source, sources) {
|
||||
|
||||
QString retentionPolicy;
|
||||
switch (sampleRate) {
|
||||
case Types::SampleRate1Min:
|
||||
@ -456,9 +490,17 @@ LogFetchJob *LogEngineInfluxDB::fetchLogEntries(const QStringList &sources, cons
|
||||
QNetworkRequest request = createQueryRequest(query);
|
||||
qCDebug(dcLogEngine()) << "Request:" << request.url() << filter;
|
||||
QNetworkReply *reply = m_nam->get(request);
|
||||
connect(reply, &QNetworkReply::finished, this, [=](){
|
||||
connect(reply, &QNetworkReply::finished, this, [=]() {
|
||||
reply->deleteLater();
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
finishFetchJob(job, QList<LogEntry>());
|
||||
return;
|
||||
}
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
finishFetchJob(job, QList<LogEntry>());
|
||||
return;
|
||||
}
|
||||
qCWarning(dcLogEngine()) << "Unable to obtain entries from influxdb" << reply->error() << reply->readAll();
|
||||
finishFetchJob(job, QList<LogEntry>());
|
||||
return;
|
||||
@ -507,20 +549,18 @@ LogFetchJob *LogEngineInfluxDB::fetchLogEntries(const QStringList &sources, cons
|
||||
|
||||
bool LogEngineInfluxDB::jobsRunning() const
|
||||
{
|
||||
// qCDebug(dcLogEngine()) << "Jobs running:" << m_initStatus << m_writeQueue.count() << m_initQueryQueue.count() << m_queryQueue.count() << m_currentWriteReply;
|
||||
return m_currentInitQuery
|
||||
|| !m_initQueryQueue.isEmpty()
|
||||
|| m_currentQuery
|
||||
|| !m_queryQueue.isEmpty()
|
||||
|| m_currentWriteReply
|
||||
|| !m_writeQueue.isEmpty();
|
||||
// qCDebug(dcLogEngine()) << "Jobs running:" << m_initStatus << m_writeQueue.count() << m_initQueryQueue.count() << m_queryQueue.count() << m_currentWriteReply;
|
||||
return m_currentInitQuery || !m_initQueryQueue.isEmpty() || m_currentQuery || !m_queryQueue.isEmpty() || m_currentWriteReply || !m_writeQueue.isEmpty();
|
||||
}
|
||||
|
||||
void LogEngineInfluxDB::clear(const QString &source)
|
||||
{
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
qCDebug(dcLogEngine()) << "Clearing entries for source:" << source;
|
||||
QueryJob *job = query(QString("DROP MEASUREMENT \"%1\"").arg(source));
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &results){
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &results) {
|
||||
if (status != QNetworkReply::NoError) {
|
||||
qCWarning(dcLogEngine()) << "Unable to clear log entries for" << source << ":" << qUtf8Printable(QJsonDocument::fromVariant(results).toJson());
|
||||
}
|
||||
@ -552,8 +592,14 @@ void LogEngineInfluxDB::initDB()
|
||||
|
||||
void LogEngineInfluxDB::createDB()
|
||||
{
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
QueryJob *job = query("SHOW DATABASES", false, true);
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &results){
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &results) {
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
if (status != QNetworkReply::NoError) {
|
||||
if (status == QNetworkReply::ConnectionRefusedError) {
|
||||
// Influx not up yet? trying again in 5 secs...
|
||||
@ -563,6 +609,10 @@ void LogEngineInfluxDB::createDB()
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
qCCritical(dcLogEngine()) << "Unable to connect to InfluxDB";
|
||||
m_initStatus = InitStatusFailure;
|
||||
return;
|
||||
@ -604,6 +654,9 @@ void LogEngineInfluxDB::createDB()
|
||||
|
||||
QueryJob *job = query(QString("CREATE DATABASE %1").arg(m_dbName), true, true);
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &result) {
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
if (status != QNetworkReply::NoError) {
|
||||
qCCritical(dcLogEngine()) << "Unable to create" << m_dbName << "database in influxdb:" << QJsonDocument::fromVariant(result).toJson();
|
||||
m_initStatus = InitStatusFailure;
|
||||
@ -617,8 +670,14 @@ void LogEngineInfluxDB::createDB()
|
||||
|
||||
void LogEngineInfluxDB::createRetentionPolicies()
|
||||
{
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
QueryJob *job = query("SHOW RETENTION POLICIES", false, true);
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &results){
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status, const QVariantList &results) {
|
||||
if (m_initStatus == InitStatusDisabled) {
|
||||
return;
|
||||
}
|
||||
if (status != QNetworkReply::NoError) {
|
||||
qCCritical(dcLogEngine()) << "Unable to query retention policies.";
|
||||
m_initStatus = InitStatusFailure;
|
||||
@ -679,7 +738,10 @@ void LogEngineInfluxDB::createRetentionPolicies()
|
||||
if (!discreteRPFound) {
|
||||
qCInfo(dcLogEngine()) << "Creating discrete nymea retention policy in influxdb";
|
||||
QueryJob *job = query(QString("CREATE RETENTION POLICY discrete ON %1 DURATION 8760h REPLICATION 1").arg(m_dbName), true, true);
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status){
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status) {
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
if (status != QNetworkReply::NoError) {
|
||||
qCWarning(dcLogEngine()) << "Unable to create discrete retention policy in influxdb.";
|
||||
m_initStatus = InitStatusFailure;
|
||||
@ -693,7 +755,10 @@ void LogEngineInfluxDB::createRetentionPolicies()
|
||||
if (!liveRPFound) {
|
||||
qCInfo(dcLogEngine()) << "Creating live nymea retention policy in influxdb";
|
||||
QueryJob *job = query(QString("CREATE RETENTION POLICY live ON %1 DURATION 24h REPLICATION 1").arg(m_dbName), true, true);
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status){
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status) {
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
if (status != QNetworkReply::NoError) {
|
||||
qCWarning(dcLogEngine()) << "Unable to create live retention policy in influxdb.";
|
||||
m_initStatus = InitStatusFailure;
|
||||
@ -707,7 +772,10 @@ void LogEngineInfluxDB::createRetentionPolicies()
|
||||
if (!minutesRPFound) {
|
||||
qCInfo(dcLogEngine()) << "Creating minutes nymea retention policy in influxdb";
|
||||
QueryJob *job = query(QString("CREATE RETENTION POLICY minutes ON %1 DURATION 168h REPLICATION 1").arg(m_dbName), true, true);
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status){
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status) {
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
if (status != QNetworkReply::NoError) {
|
||||
qCWarning(dcLogEngine()) << "Unable to create minutes retention policy in influxdb.";
|
||||
m_initStatus = InitStatusFailure;
|
||||
@ -721,7 +789,10 @@ void LogEngineInfluxDB::createRetentionPolicies()
|
||||
if (!hoursRPFound) {
|
||||
qCInfo(dcLogEngine()) << "Creating hours nymea retention policy in influxdb";
|
||||
QueryJob *job = query(QString("CREATE RETENTION POLICY hours ON %1 DURATION 26280h REPLICATION 1").arg(m_dbName), true, true);
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status){
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status) {
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
if (status != QNetworkReply::NoError) {
|
||||
qCWarning(dcLogEngine()) << "Unable to create hours retention policy in influxdb.";
|
||||
m_initStatus = InitStatusFailure;
|
||||
@ -735,7 +806,10 @@ void LogEngineInfluxDB::createRetentionPolicies()
|
||||
if (!daysRPFound) {
|
||||
qCInfo(dcLogEngine()) << "Creating days nymea retention policy in influxdb";
|
||||
QueryJob *job = query(QString("CREATE RETENTION POLICY days ON %1 DURATION 175200h REPLICATION 1").arg(m_dbName), true, true);
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status){
|
||||
connect(job, &QueryJob::finished, this, [=](QNetworkReply::NetworkError status) {
|
||||
if (m_initStatus == InitStatusDisabled)
|
||||
return;
|
||||
|
||||
if (status != QNetworkReply::NoError) {
|
||||
qCWarning(dcLogEngine()) << "Unable to create days retention policy in influxdb.";
|
||||
m_initStatus = InitStatusFailure;
|
||||
@ -748,7 +822,8 @@ void LogEngineInfluxDB::createRetentionPolicies()
|
||||
|
||||
m_initStatus = InitStatusOK;
|
||||
|
||||
qCDebug(dcLogEngine()) << "Influx initialized. Starting to process log entries (" << m_initQueryQueue.count() << m_queryQueue.count() << m_writeQueue.count() << "in queue)";
|
||||
qCDebug(dcLogEngine()) << "Influx initialized. Starting to process log entries (" << m_initQueryQueue.count() << m_queryQueue.count() << m_writeQueue.count()
|
||||
<< "in queue)";
|
||||
processQueues();
|
||||
});
|
||||
}
|
||||
@ -819,18 +894,15 @@ QueryJob *LogEngineInfluxDB::query(const QString &query, bool post, bool isInit)
|
||||
return job;
|
||||
}
|
||||
|
||||
QueryJob::QueryJob(const QNetworkRequest &request, bool post, bool isInit, QObject *parent):
|
||||
QObject(parent),
|
||||
m_request(request),
|
||||
m_post(post),
|
||||
m_isInit(isInit)
|
||||
{
|
||||
|
||||
}
|
||||
QueryJob::QueryJob(const QNetworkRequest &request, bool post, bool isInit, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_request(request)
|
||||
, m_post(post)
|
||||
, m_isInit(isInit)
|
||||
{}
|
||||
|
||||
void QueryJob::finish(QNetworkReply::NetworkError status, const QVariantList &results)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, status), Q_ARG(QVariantList, results));
|
||||
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
|
||||
@ -534,7 +534,7 @@ QList<TokenInfo> UserManager::tokens(const QString &username) const
|
||||
TokenInfo UserManager::tokenInfo(const QByteArray &token) const
|
||||
{
|
||||
if (!validateToken(token)) {
|
||||
qCWarning(dcUserManager) << "Token did not pass validation:" << token;
|
||||
qCWarning(dcUserManager()) << "Token did not pass validation:" << token;
|
||||
return TokenInfo();
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright (C) 2013 - 2024, nymea GmbH
|
||||
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
* Copyright (C) 2024 - 2026, chargebyte austria GmbH
|
||||
*
|
||||
* This file is part of nymea.
|
||||
*
|
||||
@ -25,10 +25,11 @@
|
||||
#ifndef BROWSERESULT_H
|
||||
#define BROWSERESULT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QLocale>
|
||||
#include <QObject>
|
||||
|
||||
#include "thing.h"
|
||||
#include "types/browseritem.h"
|
||||
|
||||
class ThingManager;
|
||||
|
||||
@ -38,7 +39,7 @@ class BrowseResult : public QObject
|
||||
public:
|
||||
explicit BrowseResult(Thing *thing, ThingManager *thingManager, const QString &itemId, const QLocale &locale, QObject *parent, quint32 timeout = 0);
|
||||
|
||||
Thing* thing() const;
|
||||
Thing *thing() const;
|
||||
QString itemId() const;
|
||||
QLocale locale() const;
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright (C) 2013 - 2024, nymea GmbH
|
||||
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
* Copyright (C) 2024 - 2026, chargebyte austria GmbH
|
||||
*
|
||||
* This file is part of nymea.
|
||||
*
|
||||
@ -25,10 +25,11 @@
|
||||
#ifndef BROWSERITEMRESULT_H
|
||||
#define BROWSERITEMRESULT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QLocale>
|
||||
#include <QObject>
|
||||
|
||||
#include "thing.h"
|
||||
#include "types/browseritem.h"
|
||||
|
||||
class ThingManager;
|
||||
|
||||
@ -39,7 +40,7 @@ class BrowserItemResult : public QObject
|
||||
public:
|
||||
explicit BrowserItemResult(Thing *thing, ThingManager *thingManager, const QString &itemId, const QLocale &locale, QObject *parent, quint32 timeout = 0);
|
||||
|
||||
Thing* thing() const;
|
||||
Thing *thing() const;
|
||||
QString itemId() const;
|
||||
QLocale locale() const;
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright (C) 2013 - 2024, nymea GmbH
|
||||
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
* Copyright (C) 2024 - 2026, chargebyte austria GmbH
|
||||
*
|
||||
* This file is part of nymea.
|
||||
*
|
||||
@ -313,7 +313,6 @@ States Thing::states() const
|
||||
return m_states;
|
||||
}
|
||||
|
||||
|
||||
/*! Returns true, a \l{Param} with the given \a paramTypeId exists for this thing. */
|
||||
bool Thing::hasParam(const QString ¶mName) const
|
||||
{
|
||||
@ -321,7 +320,6 @@ bool Thing::hasParam(const QString ¶mName) const
|
||||
return m_params.hasParam(paramTypeId);
|
||||
}
|
||||
|
||||
|
||||
/*! Returns true, a \l{Param} with the given \a paramTypeId exists for this thing. */
|
||||
bool Thing::hasParam(const ParamTypeId ¶mTypeId) const
|
||||
{
|
||||
@ -516,7 +514,7 @@ void Thing::setStateValue(const QString &stateName, const QVariant &value)
|
||||
setStateValue(stateTypeId, value);
|
||||
}
|
||||
|
||||
/*! Sets the minimum value for the \l{State} matching the given \a stateTypeId in this thing to value. */
|
||||
/*! Sets the minimum value for the \l{State} matching the given \a stateTypeId in this thing to \a minValue. */
|
||||
void Thing::setStateMinValue(const StateTypeId &stateTypeId, const QVariant &minValue)
|
||||
{
|
||||
StateType stateType = m_thingClass.stateTypes().findById(stateTypeId);
|
||||
@ -559,14 +557,14 @@ void Thing::setStateMinValue(const StateTypeId &stateTypeId, const QVariant &min
|
||||
qCWarning(dcThing()).nospace() << this << ": Failed setting minimum state value " << stateType.name() << " to " << minValue;
|
||||
}
|
||||
|
||||
/*! Sets the minimum value for the \l{State} matching the given \a stateName in this thing to value. */
|
||||
/*! Sets the minimum value for the \l{State} matching the given \a stateName in this thing to \a minValue. */
|
||||
void Thing::setStateMinValue(const QString &stateName, const QVariant &minValue)
|
||||
{
|
||||
StateTypeId stateTypeId = m_thingClass.stateTypes().findByName(stateName).id();
|
||||
setStateMinValue(stateTypeId, minValue);
|
||||
}
|
||||
|
||||
/*! Sets the maximum value for the \l{State} matching the given \a stateTypeId in this thing to value. */
|
||||
/*! Sets the maximum value for the \l{State} matching the given \a stateTypeId in this thing to \a maxValue. */
|
||||
void Thing::setStateMaxValue(const StateTypeId &stateTypeId, const QVariant &maxValue)
|
||||
{
|
||||
StateType stateType = m_thingClass.stateTypes().findById(stateTypeId);
|
||||
@ -619,7 +617,7 @@ void Thing::setStateMaxValue(const StateTypeId &stateTypeId, const QVariant &max
|
||||
qCWarning(dcThing()).nospace() << this << ": Failed setting maximum state value " << stateType.name() << " to " << maxValue;
|
||||
}
|
||||
|
||||
/*! Sets the maximum value for the \l{State} matching the given \a stateName in this thing to value. */
|
||||
/*! Sets the maximum value for the \l{State} matching the given \a stateName in this thing to \a maxValue. */
|
||||
void Thing::setStateMaxValue(const QString &stateName, const QVariant &maxValue)
|
||||
{
|
||||
StateTypeId stateTypeId = m_thingClass.stateTypes().findByName(stateName).id();
|
||||
@ -697,6 +695,14 @@ void Thing::setStateMinMaxValues(const QString &stateName, const QVariant &minVa
|
||||
setStateMinMaxValues(stateTypeId, minValue, maxValue);
|
||||
}
|
||||
|
||||
/*! Sets the possible values for the \l{State} matching the given \a stateName in this thing to \a values. */
|
||||
void Thing::setStatePossibleValues(const QString &stateName, const QVariantList &values)
|
||||
{
|
||||
const StateTypeId stateTypeId = m_thingClass.stateTypes().findByName(stateName).id();
|
||||
setStatePossibleValues(stateTypeId, values);
|
||||
}
|
||||
|
||||
/*! Sets the possible values for the \l{State} matching the given \a stateTypeId in this thing to \a values. */
|
||||
void Thing::setStatePossibleValues(const StateTypeId &stateTypeId, const QVariantList &values)
|
||||
{
|
||||
StateType stateType = m_thingClass.stateTypes().findById(stateTypeId);
|
||||
@ -704,6 +710,7 @@ void Thing::setStatePossibleValues(const StateTypeId &stateTypeId, const QVarian
|
||||
qCWarning(dcThing()) << "No such state type" << stateTypeId.toString() << "in" << m_name << "(" + thingClass().name() + ")";
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_states.count(); ++i) {
|
||||
if (m_states.at(i).stateTypeId() == stateTypeId) {
|
||||
if (values == m_states.at(i).possibleValues()) {
|
||||
@ -739,10 +746,10 @@ void Thing::setStatePossibleValues(const StateTypeId &stateTypeId, const QVarian
|
||||
return;
|
||||
}
|
||||
}
|
||||
qCWarning(dcThing()).nospace() << this << ": Failed setting maximum state value " << stateType.name() << " to " << values;
|
||||
qCWarning(dcThing()).nospace() << this << ": Failed setting possible state values " << stateType.name() << " to " << values;
|
||||
Q_ASSERT_X(false,
|
||||
m_name.toUtf8(),
|
||||
QString("Failed setting possible state values for %1 to %2").arg(stateType.name()).arg(QString(QJsonDocument::fromVariant(values).toJson())).toUtf8());
|
||||
QString("Failed setting possible state values for %1 to %2").arg(stateType.name(), QString(QJsonDocument::fromVariant(values).toJson())).toUtf8());
|
||||
}
|
||||
|
||||
/*! Returns the \l{State} with the given \a stateTypeId of this thing. */
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright (C) 2013 - 2024, nymea GmbH
|
||||
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
* Copyright (C) 2024 - 2026, chargebyte austria GmbH
|
||||
*
|
||||
* This file is part of nymea.
|
||||
*
|
||||
@ -32,7 +32,6 @@
|
||||
#include "types/state.h"
|
||||
#include "types/param.h"
|
||||
#include "types/event.h"
|
||||
#include "types/browseritem.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QUuid>
|
||||
@ -145,6 +144,7 @@ public:
|
||||
Q_INVOKABLE void setStateMinMaxValues(const StateTypeId &stateTypeId, const QVariant &minValue, const QVariant &maxValue);
|
||||
Q_INVOKABLE void setStateMinMaxValues(const QString &stateName, const QVariant &minValue, const QVariant &maxValue);
|
||||
Q_INVOKABLE void setStatePossibleValues(const StateTypeId &stateTypeId, const QVariantList &values);
|
||||
Q_INVOKABLE void setStatePossibleValues(const QString &stateName, const QVariantList &values);
|
||||
|
||||
Q_INVOKABLE State state(const StateTypeId &stateTypeId) const;
|
||||
Q_INVOKABLE State state(const QString &stateName) const;
|
||||
|
||||
@ -24,9 +24,10 @@
|
||||
|
||||
#include "jsoncontext.h"
|
||||
|
||||
JsonContext::JsonContext(const QUuid &clientId, const QLocale &locale):
|
||||
JsonContext::JsonContext(const QUuid &clientId, const QLocale &locale, bool authenticationEnabled):
|
||||
m_clientId(clientId),
|
||||
m_locale(locale)
|
||||
m_locale(locale),
|
||||
m_authenticationEnabled(authenticationEnabled)
|
||||
{
|
||||
|
||||
}
|
||||
@ -50,3 +51,13 @@ void JsonContext::setToken(const QByteArray &token)
|
||||
{
|
||||
m_token = token;
|
||||
}
|
||||
|
||||
bool JsonContext::authenticationEnabled() const
|
||||
{
|
||||
return m_authenticationEnabled;
|
||||
}
|
||||
|
||||
void JsonContext::setAuthenticationEnabled(bool authenticationEnabled)
|
||||
{
|
||||
m_authenticationEnabled = authenticationEnabled;
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
class JsonContext
|
||||
{
|
||||
public:
|
||||
JsonContext(const QUuid &clientId, const QLocale &locale);
|
||||
JsonContext(const QUuid &clientId, const QLocale &locale, bool authenticationEnabled = true);
|
||||
|
||||
QUuid clientId() const;
|
||||
QLocale locale() const;
|
||||
@ -39,10 +39,14 @@ public:
|
||||
QByteArray token() const;
|
||||
void setToken(const QByteArray &token);
|
||||
|
||||
bool authenticationEnabled() const;
|
||||
void setAuthenticationEnabled(bool authenticationEnabled);
|
||||
|
||||
private:
|
||||
QUuid m_clientId;
|
||||
QLocale m_locale;
|
||||
QByteArray m_token;
|
||||
bool m_authenticationEnabled = true;
|
||||
};
|
||||
|
||||
#endif // JSONCONTEXT_H
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright (C) 2013 - 2024, nymea GmbH
|
||||
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
* Copyright (C) 2024 - 2026, chargebyte austria GmbH
|
||||
*
|
||||
* This file is part of nymea.
|
||||
*
|
||||
@ -24,9 +24,21 @@
|
||||
|
||||
#include "platformupdatecontroller.h"
|
||||
|
||||
PlatformUpdateController::PlatformUpdateController(QObject *parent) : QObject(parent)
|
||||
{
|
||||
PlatformUpdateController::PlatformUpdateController(QObject *parent)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
/*! Indicates whether the update of this platform is package manager based or entire System updates or none.
|
||||
On platforms like debian the update is mostly package manager based using apt in the background.
|
||||
On many products like yocto or mender based systems there are system update images, where the user has no
|
||||
influcence on individual packages, only to select between entire system images and their updates.
|
||||
|
||||
A backend plugin should override this to indicate the type of the system update.
|
||||
*/
|
||||
|
||||
PlatformUpdateController::UpdateType PlatformUpdateController::updateType() const
|
||||
{
|
||||
return PlatformUpdateController::UpdateTypeNone;
|
||||
}
|
||||
|
||||
/*! Whether or not the update management is available. Returns true if the system is ready
|
||||
@ -78,6 +90,16 @@ bool PlatformUpdateController::updateRunning() const
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Indicates the progress of the update as percentage. Since not all update platforms support this feature,
|
||||
the value defaults to -1 if not supported or not running.
|
||||
|
||||
A backend plugin should override this and return actual update percentage if supported.
|
||||
*/
|
||||
int PlatformUpdateController::updateProgress() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*! Returns a list of packages availabe in the system. If a backend supports installation of new packages,
|
||||
the list of packages may contain not installed packages. Such packages are marked by
|
||||
returning an empty \l{Package::installedVersion()}. If the backend supports removal
|
||||
@ -163,4 +185,3 @@ bool PlatformUpdateController::enableRepository(const QString &repositoryId, boo
|
||||
Q_UNUSED(enabled)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright (C) 2013 - 2024, nymea GmbH
|
||||
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
||||
* Copyright (C) 2024 - 2026, chargebyte austria GmbH
|
||||
*
|
||||
* This file is part of nymea.
|
||||
*
|
||||
@ -34,14 +34,24 @@ class PlatformUpdateController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum UpdateType {
|
||||
UpdateTypeNone,
|
||||
UpdateTypeSystem,
|
||||
UpdateTypePackageManager
|
||||
};
|
||||
Q_ENUM(UpdateType)
|
||||
|
||||
explicit PlatformUpdateController(QObject *parent = nullptr);
|
||||
virtual ~PlatformUpdateController() = default;
|
||||
|
||||
virtual PlatformUpdateController::UpdateType updateType() const;
|
||||
|
||||
virtual bool updateManagementAvailable() const;
|
||||
|
||||
virtual bool checkForUpdates();
|
||||
virtual bool busy() const;
|
||||
virtual bool updateRunning() const;
|
||||
virtual int updateProgress() const;
|
||||
|
||||
virtual QList<Package> packages() const;
|
||||
virtual QList<Repository> repositories() const;
|
||||
@ -56,6 +66,7 @@ signals:
|
||||
void availableChanged();
|
||||
void busyChanged();
|
||||
void updateRunningChanged();
|
||||
void updateProgressChanged();
|
||||
void packageAdded(const Package &pacakge);
|
||||
void packageChanged(const Package &package);
|
||||
void packageRemoved(const QString &packageId);
|
||||
|
||||
@ -11,10 +11,10 @@ isEmpty(NYMEA_VERSION) {
|
||||
|
||||
# define protocol versions
|
||||
JSON_PROTOCOL_VERSION_MAJOR=8
|
||||
JSON_PROTOCOL_VERSION_MINOR=4
|
||||
JSON_PROTOCOL_VERSION_MINOR=5
|
||||
JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}"
|
||||
LIBNYMEA_API_VERSION_MAJOR=9
|
||||
LIBNYMEA_API_VERSION_MINOR=0
|
||||
LIBNYMEA_API_VERSION_MINOR=1
|
||||
LIBNYMEA_API_VERSION_PATCH=0
|
||||
LIBNYMEA_API_VERSION="$${LIBNYMEA_API_VERSION_MAJOR}.$${LIBNYMEA_API_VERSION_MINOR}.$${LIBNYMEA_API_VERSION_PATCH}"
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
8.4
|
||||
8.5
|
||||
{
|
||||
"enums": {
|
||||
"BasicType": [
|
||||
@ -359,6 +359,11 @@
|
||||
"UnitLiter",
|
||||
"UnitMicroGrammPerCubicalMeter"
|
||||
],
|
||||
"UpdateType": [
|
||||
"UpdateTypeNone",
|
||||
"UpdateTypeSystem",
|
||||
"UpdateTypePackageManager"
|
||||
],
|
||||
"UserError": [
|
||||
"UserErrorNoError",
|
||||
"UserErrorBackendError",
|
||||
@ -1785,14 +1790,15 @@
|
||||
}
|
||||
},
|
||||
"System.GetCapabilities": {
|
||||
"description": "Get the list of capabilites on this system. The property \"powerManagement\" indicates whether restarting nymea and rebooting or shutting down is supported on this system. The property \"updateManagement indicates whether system update features are available in this system. The property \"timeManagement\" indicates whether the system time can be configured on this system. Note that GetTime will be available in any case.",
|
||||
"description": "Get the list of capabilites on this system. The property \"powerManagement\" indicates whether restarting nymea and rebooting or shutting down is supported on this system. The property \"updateManagement\" indicates whether system update features are available in this system. The \"updateManagementType\" indicates which kind of update is supported on this platform. The property \"timeManagement\" indicates whether the system time can be configured on this system. Note that GetTime will be available in any case.",
|
||||
"params": {
|
||||
},
|
||||
"permissionScope": "PermissionScopeAdmin",
|
||||
"returns": {
|
||||
"powerManagement": "Bool",
|
||||
"timeManagement": "Bool",
|
||||
"updateManagement": "Bool"
|
||||
"updateManagement": "Bool",
|
||||
"updateManagementType": "$ref:UpdateType"
|
||||
}
|
||||
},
|
||||
"System.GetPackages": {
|
||||
@ -1844,12 +1850,13 @@
|
||||
}
|
||||
},
|
||||
"System.GetUpdateStatus": {
|
||||
"description": "Get the current status of the update system. \"busy\" indicates that the system is current busy with an operation regarding updates. This does not necessarily mean an actual update is running. When this is true, update related functions on the client should be marked as busy and no interaction with update components shall be allowed. An example for such a state is when the system queries the server if there are updates available, typically after a call to CheckForUpdates. \"updateRunning\" on the other hand indicates an actual update process is ongoing. The user should be informed about it, the system also might restart at any point while an update is running.",
|
||||
"description": "Get the current status of the update system. \"busy\" indicates that the system is current busy with an operation regarding updates. This does not necessarily mean an actual update is running. When this is true, update related functions on the client should be marked as busy and no interaction with update components shall be allowed. An example for such a state is when the system queries the server if there are updates available, typically after a call to CheckForUpdates. \"updateRunning\" on the other hand indicates an actual update process is ongoing. The user should be informed about it, the system also might restart at any point while an update is running. The \"updateProgress\" property is optional, if the backend supports it, a progress >= 0 indicated the update progress in percentage.",
|
||||
"params": {
|
||||
},
|
||||
"permissionScope": "PermissionScopeAdmin",
|
||||
"returns": {
|
||||
"busy": "Bool",
|
||||
"o:updateProgress": "Int",
|
||||
"updateRunning": "Bool"
|
||||
}
|
||||
},
|
||||
@ -2684,7 +2691,8 @@
|
||||
"description": "Emitted whenever the system capabilities change.",
|
||||
"params": {
|
||||
"powerManagement": "Bool",
|
||||
"updateManagement": "Bool"
|
||||
"updateManagement": "Bool",
|
||||
"updateManagementType": "$ref:UpdateType"
|
||||
}
|
||||
},
|
||||
"System.PackageAdded": {
|
||||
@ -2736,6 +2744,7 @@
|
||||
"description": "Emitted whenever the update status changes.",
|
||||
"params": {
|
||||
"busy": "Bool",
|
||||
"o:updateProgress": "Int",
|
||||
"updateRunning": "Bool"
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user