Add snapd plugin
parent
7976a67424
commit
42636ea14f
|
|
@ -461,6 +461,22 @@ Description: guh.io plugin for senic
|
|||
This package will install the guh.io plugin for senic
|
||||
|
||||
|
||||
Package: guh-plugin-snapd
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
guh-plugins-translations,
|
||||
Description: guh.io plugin for snapd
|
||||
The guh daemon is a plugin based IoT (Internet of Things) server. The
|
||||
server works like a translator for devices, things and services and
|
||||
allows them to interact.
|
||||
With the powerful rule engine you are able to connect any device available
|
||||
in the system and create individual scenes and behaviors for your environment.
|
||||
.
|
||||
This package will install the guh.io plugin for snapd
|
||||
|
||||
|
||||
|
||||
|
||||
Package: guh-plugins-translations
|
||||
Section: misc
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
usr/lib/@DEB_HOST_MULTIARCH@/guh/plugins/libguh_devicepluginsnapd.so
|
||||
|
|
@ -31,6 +31,7 @@ PLUGIN_DIRS = \
|
|||
denon \
|
||||
avahimonitor \
|
||||
gpio \
|
||||
snapd \
|
||||
|
||||
|
||||
CONFIG+=all
|
||||
|
|
|
|||
|
|
@ -0,0 +1,259 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2017 Simon Stürz <simon.stuerz@guh.io *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "devicepluginsnapd.h"
|
||||
#include "plugin/device.h"
|
||||
#include "plugininfo.h"
|
||||
#include "network/networkaccessmanager.h"
|
||||
|
||||
DevicePluginSnapd::DevicePluginSnapd()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DevicePluginSnapd::init()
|
||||
{
|
||||
// Check advanced mode
|
||||
m_advancedMode = configValue(advancedModeParamTypeId).toBool();
|
||||
connect(this, &DevicePluginSnapd::configValueChanged, this, &DevicePluginSnapd::onPluginConfigurationChanged);
|
||||
|
||||
// Setup timers
|
||||
m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(2);
|
||||
connect(m_refreshTimer, &PluginTimer::timeout, this, &DevicePluginSnapd::onRefreshTimer);
|
||||
|
||||
// Check all 5 min if there is an update available
|
||||
m_updateTimer = hardwareManager()->pluginTimerManager()->registerTimer(300);
|
||||
connect(m_refreshTimer, &PluginTimer::timeout, this, &DevicePluginSnapd::onUpdateTimer);
|
||||
}
|
||||
|
||||
void DevicePluginSnapd::startMonitoringAutoDevices()
|
||||
{
|
||||
// Check if we already have a controller and if snapd is available
|
||||
if (m_snapdControl && !m_snapdControl->available()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we already have a device for the snapd control
|
||||
bool deviceAlreadyExists = false;
|
||||
foreach (Device *device, myDevices()) {
|
||||
if (device->deviceClassId() == snapdControlDeviceClassId) {
|
||||
deviceAlreadyExists = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add device if there isn't already one
|
||||
if (!deviceAlreadyExists) {
|
||||
DeviceDescriptor descriptor(snapdControlDeviceClassId, "Update manager");
|
||||
emit autoDevicesAppeared(snapdControlDeviceClassId, QList<DeviceDescriptor>() << descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginSnapd::postSetupDevice(Device *device)
|
||||
{
|
||||
if (m_snapdControl && m_snapdControl->device() == device)
|
||||
m_snapdControl->update();
|
||||
|
||||
}
|
||||
|
||||
void DevicePluginSnapd::deviceRemoved(Device *device)
|
||||
{
|
||||
if (device->deviceClassId() == snapdControlDeviceClassId) {
|
||||
qCWarning(dcSnapd()) << "User deleted snapd control.";
|
||||
|
||||
// Clean up old device
|
||||
if (m_snapdControl) {
|
||||
delete m_snapdControl;
|
||||
m_snapdControl = nullptr;
|
||||
}
|
||||
|
||||
// Respawn device immediately
|
||||
startMonitoringAutoDevices();
|
||||
|
||||
} else if (device->deviceClassId() == snapDeviceClassId) {
|
||||
if (m_snapDevices.values().contains(device)) {
|
||||
QString snapId = m_snapDevices.key(device);
|
||||
m_snapDevices.remove(snapId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeviceManager::DeviceSetupStatus DevicePluginSnapd::setupDevice(Device *device)
|
||||
{
|
||||
qCDebug(dcSnapd()) << "Setup" << device->name() << device->params();
|
||||
|
||||
if (device->deviceClassId() == snapdControlDeviceClassId) {
|
||||
if (m_snapdControl) {
|
||||
delete m_snapdControl;
|
||||
m_snapdControl = nullptr;
|
||||
}
|
||||
|
||||
m_snapdControl = new SnapdControl(device, this);
|
||||
connect(m_snapdControl, &SnapdControl::snapListUpdated, this, &DevicePluginSnapd::onSnapListUpdated);
|
||||
|
||||
} else if (device->deviceClassId() == snapDeviceClassId) {
|
||||
device->setName(QString("%1").arg(device->paramValue(snapNameParamTypeId).toString()));
|
||||
m_snapDevices.insert(device->paramValue(snapIdParamTypeId).toString(), device);
|
||||
}
|
||||
|
||||
return DeviceManager::DeviceSetupStatusSuccess;
|
||||
}
|
||||
|
||||
DeviceManager::DeviceError DevicePluginSnapd::executeAction(Device *device, const Action &action) {
|
||||
|
||||
if (device->deviceClassId() == snapdControlDeviceClassId) {
|
||||
|
||||
if (!m_snapdControl) {
|
||||
qCDebug(dcSnapd()) << "There is currently no snapd controller.";
|
||||
return DeviceManager::DeviceErrorHardwareFailure;
|
||||
}
|
||||
|
||||
if (!m_snapdControl->connected()) {
|
||||
qCDebug(dcSnapd()) << "Snapd controller not connected to to backend.";
|
||||
return DeviceManager::DeviceErrorHardwareFailure;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == startUpdateActionTypeId) {
|
||||
m_snapdControl->snapRefresh();
|
||||
return DeviceManager::DeviceErrorNoError;
|
||||
} else if (action.actionTypeId() == checkUpdatesActionTypeId) {
|
||||
m_snapdControl->checkForUpdates();
|
||||
return DeviceManager::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
return DeviceManager::DeviceErrorActionTypeNotFound;
|
||||
|
||||
} else if (device->deviceClassId() == snapDeviceClassId) {
|
||||
|
||||
if (!m_snapdControl) {
|
||||
qCDebug(dcSnapd()) << "There is currently no snapd controller.";
|
||||
return DeviceManager::DeviceErrorHardwareFailure;
|
||||
}
|
||||
|
||||
if (!m_snapdControl->connected()) {
|
||||
qCDebug(dcSnapd()) << "Snapd controller not connected to to backend.";
|
||||
return DeviceManager::DeviceErrorHardwareFailure;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == snapChannelActionTypeId) {
|
||||
QString snapName = device->paramValue(snapNameParamTypeId).toString();
|
||||
m_snapdControl->changeSnapChannel(snapName, action.param(snapChannelStateParamTypeId).value().toString());
|
||||
return DeviceManager::DeviceErrorNoError;
|
||||
} else if (action.actionTypeId() == snapRevertActionTypeId) {
|
||||
QString snapName = device->paramValue(snapNameParamTypeId).toString();
|
||||
m_snapdControl->snapRevert(snapName);
|
||||
return DeviceManager::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
return DeviceManager::DeviceErrorActionTypeNotFound;
|
||||
}
|
||||
|
||||
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
||||
}
|
||||
|
||||
void DevicePluginSnapd::onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value)
|
||||
{
|
||||
if (paramTypeId == advancedModeParamTypeId) {
|
||||
qCDebug(dcSnapd()) << "Advanced mode" << (value.toBool() ? "enabled." : "disabled.");
|
||||
m_advancedMode = value.toBool();
|
||||
|
||||
// If advanced mode disabled, clean up all snap devices
|
||||
if (!m_advancedMode) {
|
||||
foreach (const QString deviceSnapId, m_snapDevices.keys()) {
|
||||
Device *device = m_snapDevices.take(deviceSnapId);
|
||||
qCDebug(dcSnapd()) << "Remove device for snap" << device->paramValue(snapNameParamTypeId).toString();
|
||||
emit autoDeviceDisappeared(device->id());
|
||||
}
|
||||
} else {
|
||||
if (!m_snapdControl)
|
||||
return;
|
||||
|
||||
m_snapdControl->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginSnapd::onRefreshTimer()
|
||||
{
|
||||
if (!m_snapdControl) {
|
||||
startMonitoringAutoDevices();
|
||||
return;
|
||||
}
|
||||
|
||||
m_snapdControl->update();
|
||||
}
|
||||
|
||||
void DevicePluginSnapd::onUpdateTimer()
|
||||
{
|
||||
if (!m_snapdControl)
|
||||
return;
|
||||
|
||||
m_snapdControl->checkForUpdates();
|
||||
}
|
||||
|
||||
void DevicePluginSnapd::onSnapListUpdated(const QVariantList &snapList)
|
||||
{
|
||||
// Check for new snap devices only in advanced mode
|
||||
if (!m_advancedMode)
|
||||
return;
|
||||
|
||||
// Collect list of snap id's from snapList for remove checking
|
||||
QStringList snapIdList;
|
||||
|
||||
// Check if we have to create a new device
|
||||
foreach (const QVariant &snapVariant, snapList) {
|
||||
QVariantMap snapMap = snapVariant.toMap();
|
||||
snapIdList.append(snapMap.value("id").toString());
|
||||
// If there is no device for this snap yet
|
||||
if (!m_snapDevices.contains(snapMap.value("id").toString())) {
|
||||
DeviceDescriptor descriptor(snapDeviceClassId, QString("Snap %1").arg(snapMap.value("name").toString()));
|
||||
ParamList params;
|
||||
params.append(Param(snapNameParamTypeId, snapMap.value("name")));
|
||||
params.append(Param(snapIdParamTypeId, snapMap.value("id")));
|
||||
params.append(Param(snapSummaryParamTypeId, snapMap.value("summary")));
|
||||
params.append(Param(snapDescriptionParamTypeId, snapMap.value("description")));
|
||||
params.append(Param(snapDeveloperParamTypeId, snapMap.value("developer")));
|
||||
descriptor.setParams(params);
|
||||
|
||||
emit autoDevicesAppeared(snapDeviceClassId, QList<DeviceDescriptor>() << descriptor);
|
||||
} else {
|
||||
// Update the states
|
||||
Device *device = m_snapDevices.value(snapMap.value("id").toString(), nullptr);
|
||||
if (!device) {
|
||||
qCWarning(dcSnapd()) << "Holding invalid snap device. This should never happen. Please report a bug if you see this message.";
|
||||
continue;
|
||||
}
|
||||
|
||||
device->setStateValue(snapChannelStateTypeId, snapMap.value("channel").toString());
|
||||
device->setStateValue(snapVersionStateTypeId, snapMap.value("version").toString());
|
||||
device->setStateValue(snapRevisionStateTypeId, snapMap.value("revision").toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have to remove a device
|
||||
foreach (const QString deviceSnapId, m_snapDevices.keys()) {
|
||||
if (!snapIdList.contains(deviceSnapId)) {
|
||||
Device *device = m_snapDevices.take(deviceSnapId);
|
||||
qCDebug(dcSnapd()) << "The snap" << device->paramValue(snapNameParamTypeId).toString() << "is not installed any more.";
|
||||
emit autoDeviceDisappeared(device->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2017 Simon Stürz <simon.stuerz@guh.io *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef DEVICEPLUGINSNAPD_H
|
||||
#define DEVICEPLUGINSNAPD_H
|
||||
|
||||
#include "devicemanager.h"
|
||||
#include "plugin/deviceplugin.h"
|
||||
#include "plugintimer.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QNetworkInterface>
|
||||
#include <QProcess>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include "snapdcontrol.h"
|
||||
|
||||
|
||||
class DevicePluginSnapd: public DevicePlugin {
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "guru.guh.DevicePlugin" FILE "devicepluginsnapd.json")
|
||||
Q_INTERFACES(DevicePlugin)
|
||||
|
||||
public:
|
||||
explicit DevicePluginSnapd();
|
||||
void init() override;
|
||||
void startMonitoringAutoDevices() override;
|
||||
void postSetupDevice(Device *device) override;
|
||||
void deviceRemoved(Device *device) override;
|
||||
|
||||
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
||||
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
|
||||
|
||||
private:
|
||||
SnapdControl *m_snapdControl = nullptr;
|
||||
PluginTimer *m_refreshTimer = nullptr;
|
||||
PluginTimer *m_updateTimer = nullptr;
|
||||
|
||||
bool m_advancedMode = false;
|
||||
|
||||
// Snap list for faster access (snap id, device)
|
||||
QHash<QString, Device *> m_snapDevices;
|
||||
|
||||
private slots:
|
||||
void onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value);
|
||||
void onRefreshTimer();
|
||||
void onUpdateTimer();
|
||||
void onSnapListUpdated(const QVariantList &snapList);
|
||||
|
||||
};
|
||||
|
||||
#endif // DEVICEPLUGINSNAPD_H
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
{
|
||||
"name": "Snapd",
|
||||
"idName": "Snapd",
|
||||
"id": "b82bce59-59bf-48b3-b781-54a6f45800f3",
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "017fe4c5-fc41-41fe-8e67-08fdaccb89ea",
|
||||
"idName": "advancedMode",
|
||||
"name": "Advanced mode",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
}
|
||||
],
|
||||
"vendors": [
|
||||
{
|
||||
"name": "Canonical",
|
||||
"idName": "canonical",
|
||||
"id": "60582ddf-32ea-4fcd-a6f2-f3beaaf21517",
|
||||
"deviceClasses": [
|
||||
{
|
||||
"id": "d90cda58-4d8c-4b7f-a982-38e56a95b72a",
|
||||
"idName": "snapdControl",
|
||||
"name": "Update manager",
|
||||
"createMethods": [ "auto" ],
|
||||
"basicTags": [ "Gateway" ],
|
||||
"deviceIcon": "Gateway",
|
||||
"paramTypes": [ ],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "45626b75-f09d-4dd1-b6c4-ee33201b47b0",
|
||||
"idName": "startUpdate",
|
||||
"name": "Start update",
|
||||
"paramTypes": [ ]
|
||||
},
|
||||
{
|
||||
"id": "4738f2c9-666e-45b9-91d3-7bcbf722b669",
|
||||
"idName": "checkUpdates",
|
||||
"name": "Check for updates",
|
||||
"paramTypes": [ ]
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "6b662b3e-fd12-4f24-be77-aec066f16d8c",
|
||||
"idName": "snapdAvailable",
|
||||
"name": "Update manager available",
|
||||
"eventTypeName": "Update manager available changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "a6b1d24b-d523-4516-9bce-5b467e5e09b2",
|
||||
"idName": "updateAvailable",
|
||||
"name": "System update available",
|
||||
"eventTypeName": "System update available changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "01ca7a22-5607-4c5e-a465-a2ae7e8b529c",
|
||||
"idName": "updateRunning",
|
||||
"name": "System update running",
|
||||
"eventTypeName": "System update running changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "c671545a-6bde-4c08-8e37-0d256841a3a5",
|
||||
"idName": "lastUpdateTime",
|
||||
"name": "Last automatic system update",
|
||||
"eventTypeName": "Last automatic system update time changed",
|
||||
"unit": "UnixTime",
|
||||
"type": "int",
|
||||
"eventRuleRelevant": false,
|
||||
"stateRuleRelevant": false,
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "122c2423-a1d9-400f-80f8-b1f798975914",
|
||||
"idName": "nextUpdateTime",
|
||||
"name": "Next automatic system update",
|
||||
"eventTypeName": "Next automatic system update time changed",
|
||||
"unit": "UnixTime",
|
||||
"type": "int",
|
||||
"eventRuleRelevant": false,
|
||||
"stateRuleRelevant": false,
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "4987aca3-3916-4cb3-938f-df6c99d04dbf",
|
||||
"idName": "status",
|
||||
"name": "Status",
|
||||
"eventTypeName": "Status changed",
|
||||
"type": "QString",
|
||||
"eventRuleRelevant": false,
|
||||
"stateRuleRelevant": false,
|
||||
"defaultValue": "-"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ff0840d7-fcfc-4403-9d9f-301610d5a437",
|
||||
"idName": "snap",
|
||||
"name": "Snap",
|
||||
"createMethods": [ "auto" ],
|
||||
"basicTags": [ "Gateway" ],
|
||||
"deviceIcon": "Network",
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "4f38614d-8be0-48dc-a24d-cee9ff1f2a89",
|
||||
"idName": "snapName",
|
||||
"name": "Name",
|
||||
"type": "QString",
|
||||
"defaultValue": "-"
|
||||
},
|
||||
{
|
||||
"id": "9afb98fb-f717-4f4c-8009-1a6514054c5f",
|
||||
"idName": "snapId",
|
||||
"name": "ID",
|
||||
"type": "QString",
|
||||
"defaultValue": "-"
|
||||
},
|
||||
{
|
||||
"id": "12b9a65f-970b-49b5-b1d0-1625fc6d8758",
|
||||
"idName": "snapSummary",
|
||||
"name": "Summary",
|
||||
"type": "QString",
|
||||
"defaultValue": "-"
|
||||
},
|
||||
{
|
||||
"id": "fe24c61b-e154-4259-b7ca-6f0602e9d1c3",
|
||||
"idName": "snapDescription",
|
||||
"name": "Description",
|
||||
"type": "QString",
|
||||
"defaultValue": "-"
|
||||
},
|
||||
{
|
||||
"id": "76ead9c5-0a18-40a2-b31d-f6bb6dfea0a5",
|
||||
"idName": "snapDeveloper",
|
||||
"name": "Developer",
|
||||
"type": "QString",
|
||||
"defaultValue": "-"
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "e061dee6-62fc-45cc-9c9f-403c2be52939",
|
||||
"idName": "snapRevert",
|
||||
"name": "Rollback to previous version"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "7be2b61e-3f59-4b92-b2bb-50d027bb92ff",
|
||||
"idName": "snapChannel",
|
||||
"name": "Channel",
|
||||
"eventTypeName": "Channel changed",
|
||||
"type": "QString",
|
||||
"eventRuleRelevant": false,
|
||||
"stateRuleRelevant": false,
|
||||
"actionTypeName": "Set channel",
|
||||
"defaultValue": "stable",
|
||||
"writable": true,
|
||||
"possibleValues": [
|
||||
"stable",
|
||||
"candidate",
|
||||
"beta",
|
||||
"edge"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "532a95f3-db29-427e-bb32-d5a22029e586",
|
||||
"idName": "snapVersion",
|
||||
"name": "Version",
|
||||
"eventTypeName": "Version changed",
|
||||
"type": "QString",
|
||||
"eventRuleRelevant": false,
|
||||
"stateRuleRelevant": false,
|
||||
"defaultValue": "-"
|
||||
},
|
||||
{
|
||||
"id": "f26a6404-e011-11e7-9224-2350048461eb",
|
||||
"idName": "snapRevision",
|
||||
"name": "Revision",
|
||||
"eventTypeName": "Revision changed",
|
||||
"type": "QString",
|
||||
"eventRuleRelevant": false,
|
||||
"stateRuleRelevant": false,
|
||||
"defaultValue": "-"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
TRANSLATIONS = translations/en_US.ts \
|
||||
translations/de_DE.ts
|
||||
|
||||
# Note: include after the TRANSLATIONS definition
|
||||
include(../plugins.pri)
|
||||
|
||||
TARGET = $$qtLibraryTarget(guh_devicepluginsnapd)
|
||||
|
||||
QT += network
|
||||
|
||||
SOURCES += \
|
||||
devicepluginsnapd.cpp \
|
||||
snapdcontrol.cpp \
|
||||
snapdconnection.cpp \
|
||||
snapdreply.cpp
|
||||
|
||||
HEADERS += \
|
||||
devicepluginsnapd.h \
|
||||
snapdcontrol.h \
|
||||
snapdconnection.h \
|
||||
snapdreply.h
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
#include "snapdconnection.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonParseError>
|
||||
|
||||
|
||||
SnapdConnection::SnapdConnection(QObject *parent) :
|
||||
QLocalSocket(parent)
|
||||
{
|
||||
connect(this, &QLocalSocket::connected, this, &SnapdConnection::onConnected);
|
||||
connect(this, &QLocalSocket::disconnected, this, &SnapdConnection::onDisconnected);
|
||||
connect(this, &QLocalSocket::readyRead, this, &SnapdConnection::onReadyRead);
|
||||
connect(this, &QLocalSocket::stateChanged, this, &SnapdConnection::onStateChanged);
|
||||
connect(this, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(onError(QLocalSocket::LocalSocketError)));
|
||||
}
|
||||
|
||||
SnapdReply *SnapdConnection::get(const QString &path)
|
||||
{
|
||||
SnapdReply *reply = new SnapdReply(this);
|
||||
reply->setRequestPath(path);
|
||||
reply->setRequestMethod("GET");
|
||||
reply->setRequestRawMessage(createRequestHeader("GET", path));
|
||||
|
||||
// Check if currently a reply is running
|
||||
if (m_currentReply) {
|
||||
m_replyQueue.enqueue(reply);
|
||||
} else {
|
||||
// Send request
|
||||
m_currentReply = reply;
|
||||
if (m_debug)
|
||||
qCDebug(dcSnapd()) << "-->" << reply->requestMethod() << reply->requestPath();
|
||||
|
||||
if (write(reply->requestRawMessage()) <= 0) {
|
||||
m_currentReply = nullptr;
|
||||
reply->setFinished(false);
|
||||
sendNextRequest();
|
||||
}
|
||||
}
|
||||
|
||||
// Note: the caller owns the object now
|
||||
return reply;
|
||||
}
|
||||
|
||||
SnapdReply *SnapdConnection::post(const QString &path, const QByteArray &payload)
|
||||
{
|
||||
SnapdReply *reply = new SnapdReply(this);
|
||||
reply->setRequestPath(path);
|
||||
reply->setRequestMethod("POST");
|
||||
QByteArray header = createRequestHeader("POST", path, payload);
|
||||
reply->setRequestRawMessage(header.append(payload));
|
||||
|
||||
// Check if currently a reply is running
|
||||
if (m_currentReply) {
|
||||
m_replyQueue.enqueue(reply);
|
||||
} else {
|
||||
// Send request
|
||||
m_currentReply = reply;
|
||||
if (m_debug)
|
||||
qCDebug(dcSnapd()) << "-->" << reply->requestMethod() << reply->requestPath() << payload;
|
||||
|
||||
if (write(reply->requestRawMessage()) <= 0) {
|
||||
m_currentReply = nullptr;
|
||||
reply->setFinished(false);
|
||||
sendNextRequest();
|
||||
}
|
||||
}
|
||||
|
||||
// Note: the caller owns the object now
|
||||
return reply;
|
||||
}
|
||||
|
||||
bool SnapdConnection::isConnected() const
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
|
||||
void SnapdConnection::setConnected(const bool &connected)
|
||||
{
|
||||
if (m_connected == connected)
|
||||
return;
|
||||
|
||||
qCDebug(dcSnapd()) << "Connected";
|
||||
|
||||
m_connected = connected;
|
||||
emit connectedChanged(m_connected);
|
||||
}
|
||||
|
||||
QByteArray SnapdConnection::createRequestHeader(const QString &method, const QString &path, const QByteArray &payload)
|
||||
{
|
||||
QByteArray request;
|
||||
request.append(QString("%1 %2 HTTP/1.1\r\n").arg(method).arg(path).toUtf8());
|
||||
request.append("Host: http\r\n");
|
||||
request.append("Accept: *\r\n");
|
||||
if (!payload.isEmpty()) {
|
||||
request.append("Content-Type: application/json\r\n");
|
||||
request.append(QString("Content-Length: %1\r\n").arg(payload.count()).toUtf8());
|
||||
}
|
||||
|
||||
request.append("\r\n");
|
||||
return request;
|
||||
}
|
||||
|
||||
QByteArray SnapdConnection::getChunckedPayload(const QByteArray &payload)
|
||||
{
|
||||
// Read line by line
|
||||
QStringList payloadLines = QString::fromUtf8(payload).split(QRegExp("\r\n"));
|
||||
if (payloadLines.count() < 4) {
|
||||
qCWarning(dcSnapd()) << "Chuncked payload invalid linecount" << payloadLines.count();
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
int payloadSize = payloadLines.at(2).toInt(0, 16);
|
||||
|
||||
if (m_debug)
|
||||
qCDebug(dcSnapd()) << "Payload size" << payloadSize;
|
||||
|
||||
if (payloadLines.at(3).toUtf8().size() != payloadSize) {
|
||||
qCWarning(dcSnapd()) << "Invalid payload size" << payloadLines.at(3).toUtf8().size() << "!=" << payloadSize;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
// Return just the payload
|
||||
return payloadLines.at(3).toUtf8();
|
||||
}
|
||||
|
||||
void SnapdConnection::processData()
|
||||
{
|
||||
if (!m_currentReply) {
|
||||
qCWarning(dcSnapd()) << "Data received without current reply" << m_payload;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_header.isEmpty()) {
|
||||
qCWarning(dcSnapd()) << "Could not process data. There is no header.";
|
||||
m_currentReply->setFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the raw payload
|
||||
QByteArray payloadData;
|
||||
if (m_chuncked) {
|
||||
payloadData = getChunckedPayload(m_payload);
|
||||
} else {
|
||||
payloadData = m_payload;
|
||||
}
|
||||
|
||||
// Check if there are data to process
|
||||
if (m_payload.isEmpty()) {
|
||||
qCWarning(dcSnapd()) << "Could not process data. There is no payload to process.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse header
|
||||
QHash<QString, QString> parsedHeader;
|
||||
QStringList headerLines = QString::fromUtf8(m_header).split(QRegExp("\r\n"));
|
||||
|
||||
// Read status line
|
||||
QString statusLine = headerLines.takeFirst();
|
||||
QStringList statusLineTokens = statusLine.split(QRegExp("[ \r\n][ \r\n]*"));
|
||||
if (statusLineTokens.count() < 3) {
|
||||
qCWarning(dcSnapd()) << "Could not parse HTTP status line:" << statusLine;
|
||||
return;
|
||||
}
|
||||
|
||||
bool statusCodeOk = false;
|
||||
int statusCode = statusLineTokens.at(1).simplified().toInt(&statusCodeOk);
|
||||
if (!statusCodeOk) {
|
||||
qCWarning(dcSnapd()) << "Could not parse HTTP status code:" << statusLineTokens.at(1);
|
||||
return;
|
||||
}
|
||||
|
||||
QString statusMessage;
|
||||
for (int i = 2; i < statusLineTokens.count(); i++) {
|
||||
statusMessage.append(statusLineTokens.at(i).simplified());
|
||||
if (i < statusLineTokens.count() -1) {
|
||||
statusMessage.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
// Verify header formating
|
||||
foreach (const QString &line, headerLines) {
|
||||
if (!line.contains(":")) {
|
||||
qCWarning(dcSnapd()) << "Invalid HTTP header. Missing \":\" in line" << line;
|
||||
return;
|
||||
}
|
||||
|
||||
int index = line.indexOf(":");
|
||||
QString key = line.left(index).toUtf8().simplified();
|
||||
QString value = line.right(line.count() - index - 1).toUtf8().simplified();
|
||||
//qCDebug(dcSnapd()) << " Key:" << key << "Value:" << value;
|
||||
parsedHeader.insert(key, value);
|
||||
}
|
||||
|
||||
// Parse payload
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(payloadData, &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qCWarning(dcSnapd()) << "Got invalid JSON data from snapd:" << error.offset << error.errorString();
|
||||
qCWarning(dcSnapd()) << qUtf8Printable(payloadData);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_debug)
|
||||
qCDebug(dcSnapd()) << "<--" << m_currentReply->requestPath() << statusCode << statusMessage;
|
||||
|
||||
// Fill reply
|
||||
m_currentReply->setStatusCode(statusCode);
|
||||
m_currentReply->setStatusMessage(statusMessage);
|
||||
m_currentReply->setHeader(parsedHeader);
|
||||
m_currentReply->setDataMap(jsonDoc.toVariant().toMap());
|
||||
m_currentReply->setFinished();
|
||||
m_currentReply = nullptr;
|
||||
|
||||
sendNextRequest();
|
||||
|
||||
// Current data stream finished, reset for new messages
|
||||
m_payload.clear();
|
||||
m_header.clear();
|
||||
m_chuncked = false;
|
||||
}
|
||||
|
||||
void SnapdConnection::sendNextRequest()
|
||||
{
|
||||
if (m_replyQueue.isEmpty())
|
||||
return;
|
||||
|
||||
SnapdReply *reply = m_replyQueue.dequeue();
|
||||
m_currentReply = reply;
|
||||
if (m_debug)
|
||||
qCDebug(dcSnapd()) << "-->" << reply->requestMethod() << reply->requestPath();
|
||||
|
||||
if (write(reply->requestRawMessage()) < 0) {
|
||||
m_currentReply->setFinished(false);
|
||||
m_currentReply = nullptr;
|
||||
sendNextRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void SnapdConnection::onConnected()
|
||||
{
|
||||
setConnected(true);
|
||||
}
|
||||
|
||||
void SnapdConnection::onDisconnected()
|
||||
{
|
||||
setConnected(false);
|
||||
}
|
||||
|
||||
void SnapdConnection::onError(const QLocalSocket::LocalSocketError &socketError)
|
||||
{
|
||||
qCWarning(dcSnapd()) << "Socket error" << socketError << errorString();
|
||||
}
|
||||
|
||||
void SnapdConnection::onStateChanged(const QLocalSocket::LocalSocketState &state)
|
||||
{
|
||||
switch (state) {
|
||||
case QLocalSocket::UnconnectedState:
|
||||
qCDebug(dcSnapd()) << "Disconnected from snapd.";
|
||||
break;
|
||||
case QLocalSocket::ConnectingState:
|
||||
qCDebug(dcSnapd()) << "Connecting to snapd...";
|
||||
break;
|
||||
case QLocalSocket::ConnectedState:
|
||||
qCDebug(dcSnapd()) << "Connected to snapd.";
|
||||
break;
|
||||
case QLocalSocket::ClosingState:
|
||||
qCDebug(dcSnapd()) << "Closing connection to snapd.";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SnapdConnection::onReadyRead()
|
||||
{
|
||||
QByteArray data = readAll();
|
||||
|
||||
if (m_debug)
|
||||
qCDebug(dcSnapd()) << "Data received:" << data;
|
||||
|
||||
// If we are not appending to a reply
|
||||
if (!m_chuncked) {
|
||||
|
||||
// Parse header
|
||||
int headerIndex = data.indexOf("\r\n\r\n");
|
||||
if (headerIndex < 0) {
|
||||
qCWarning(dcSnapd()) << "Invalid response format. Could not find header/payload mark.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_header = data.left(headerIndex);
|
||||
|
||||
if (m_debug)
|
||||
qCDebug(dcSnapd()) << "Header:" << m_header;
|
||||
|
||||
QByteArray payload = data.right(data.length() - (headerIndex));
|
||||
|
||||
if (m_debug)
|
||||
qCDebug(dcSnapd()) << "Payload" << payload;
|
||||
|
||||
// Check if this message is chuncked
|
||||
if (m_header.contains("chunked")) {
|
||||
|
||||
if (m_debug)
|
||||
qCDebug(dcSnapd()) << "Chuncked message receiving";
|
||||
|
||||
m_chuncked = true;
|
||||
m_payload.append(payload);
|
||||
|
||||
if (m_payload.endsWith("\r\n0\r\n\r\n")) {
|
||||
// Chuncked message finished
|
||||
processData();
|
||||
}
|
||||
} else {
|
||||
// Not chucked
|
||||
m_payload = payload;
|
||||
processData();
|
||||
}
|
||||
} else {
|
||||
m_payload.append(data);
|
||||
if (m_payload.endsWith("\r\n0\r\n\r\n")) {
|
||||
// Chuncked message finished
|
||||
processData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef SNAPDCONNECTION_H
|
||||
#define SNAPDCONNECTION_H
|
||||
|
||||
#include <QQueue>
|
||||
#include <QObject>
|
||||
#include <QLocalSocket>
|
||||
|
||||
#include "snapdreply.h"
|
||||
|
||||
class SnapdConnection : public QLocalSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SnapdConnection(QObject *parent = nullptr);
|
||||
|
||||
SnapdReply *get(const QString &path);
|
||||
SnapdReply *post(const QString &path, const QByteArray &payload);
|
||||
|
||||
bool isConnected() const;
|
||||
|
||||
private:
|
||||
bool m_chuncked = false;
|
||||
|
||||
QByteArray m_header;
|
||||
QByteArray m_payload;
|
||||
|
||||
bool m_connected = false;
|
||||
bool m_debug = false;
|
||||
|
||||
SnapdReply *m_currentReply = nullptr;
|
||||
QQueue<SnapdReply *> m_replyQueue;
|
||||
|
||||
void setConnected(const bool &connected);
|
||||
|
||||
// Helper methods
|
||||
QByteArray createRequestHeader(const QString &method, const QString &path, const QByteArray &payload = QByteArray());
|
||||
QByteArray getChunckedPayload(const QByteArray &payload);
|
||||
|
||||
void processData();
|
||||
void sendNextRequest();
|
||||
|
||||
private slots:
|
||||
void onConnected();
|
||||
void onDisconnected();
|
||||
void onError(const QLocalSocket::LocalSocketError &socketError);
|
||||
void onStateChanged(const QLocalSocket::LocalSocketState &state);
|
||||
void onReadyRead();
|
||||
|
||||
signals:
|
||||
void connectedChanged(const bool &connected);
|
||||
|
||||
};
|
||||
|
||||
#endif // SNAPDCONNECTION_H
|
||||
|
|
@ -0,0 +1,424 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2017 Simon Stürz <simon.stuerz@guh.io *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "snapdcontrol.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonParseError>
|
||||
|
||||
SnapdControl::SnapdControl(Device *device, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_device(device),
|
||||
m_snapdSocketPath("/run/snapd.socket")
|
||||
{
|
||||
m_snapConnection = new SnapdConnection(this);
|
||||
connect(m_snapConnection, &SnapdConnection::connectedChanged, this, &SnapdControl::onConnectedChanged);
|
||||
}
|
||||
|
||||
Device *SnapdControl::device()
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
bool SnapdControl::available() const
|
||||
{
|
||||
QFileInfo fileInfo(m_snapdSocketPath);
|
||||
if (!fileInfo.exists()) {
|
||||
qCWarning(dcSnapd()) << "The socket descriptor" << m_snapdSocketPath << "does not exist";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fileInfo.isReadable()) {
|
||||
qCWarning(dcSnapd()) << "The socket descriptor" << m_snapdSocketPath << "is not readable";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fileInfo.isWritable()) {
|
||||
qCWarning(dcSnapd()) << "The socket descriptor" << m_snapdSocketPath << "is not writable";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SnapdControl::connected() const
|
||||
{
|
||||
return m_snapConnection->isConnected();
|
||||
}
|
||||
|
||||
bool SnapdControl::enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void SnapdControl::loadSystemInfo()
|
||||
{
|
||||
if (!m_snapConnection)
|
||||
return;
|
||||
|
||||
if (!m_snapConnection->isConnected())
|
||||
return;
|
||||
|
||||
SnapdReply *reply = m_snapConnection->get("/v2/system-info");
|
||||
connect(reply, &SnapdReply::finished, this, &SnapdControl::onLoadSystemInfoFinished);
|
||||
}
|
||||
|
||||
void SnapdControl::loadSnapList()
|
||||
{
|
||||
if (!m_snapConnection)
|
||||
return;
|
||||
|
||||
if (!m_snapConnection->isConnected())
|
||||
return;
|
||||
|
||||
SnapdReply *reply = m_snapConnection->get("/v2/snaps");
|
||||
connect(reply, &SnapdReply::finished, this, &SnapdControl::onLoadSnapListFinished);
|
||||
}
|
||||
|
||||
void SnapdControl::loadRunningChanges()
|
||||
{
|
||||
if (!m_snapConnection)
|
||||
return;
|
||||
|
||||
if (!m_snapConnection->isConnected())
|
||||
return;
|
||||
|
||||
SnapdReply *reply = m_snapConnection->get("/v2/changes");
|
||||
connect(reply, &SnapdReply::finished, this, &SnapdControl::onLoadRunningChangesFinished);
|
||||
}
|
||||
|
||||
void SnapdControl::loadChange(const int &change)
|
||||
{
|
||||
if (!m_snapConnection)
|
||||
return;
|
||||
|
||||
if (!m_snapConnection->isConnected())
|
||||
return;
|
||||
|
||||
SnapdReply *reply = m_snapConnection->get(QString("/v2/changes/%1").arg(QString::number(change)));
|
||||
connect(reply, &SnapdReply::finished, this, &SnapdControl::onLoadChangeFinished);
|
||||
}
|
||||
|
||||
void SnapdControl::processChange(const QVariantMap &changeMap)
|
||||
{
|
||||
int changeId = changeMap.value("id").toInt();
|
||||
bool changeReady = changeMap.value("ready").toBool();
|
||||
QString changeKind = changeMap.value("kind").toString();
|
||||
QString changeStatus = changeMap.value("status").toString();
|
||||
QString changeSummary = changeMap.value("summary").toString();
|
||||
|
||||
qCDebug(dcSnapd()) << changeStatus << changeKind << changeSummary;
|
||||
|
||||
// Add this change if not alreade finishished or added
|
||||
if (!m_watchingChanges.contains(changeId) && !changeReady)
|
||||
m_watchingChanges.append(changeId);
|
||||
|
||||
// If change is on Doing, update the status
|
||||
if (changeStatus == "Doing") {
|
||||
device()->setStateValue(statusStateTypeId, changeSummary);
|
||||
}
|
||||
|
||||
if (changeReady) {
|
||||
qCDebug(dcSnapd()).noquote() << changeKind << (changeReady ? "finished." : "running.") << changeSummary;
|
||||
m_watchingChanges.removeAll(changeId);
|
||||
}
|
||||
}
|
||||
|
||||
bool SnapdControl::validAsyncResponse(const QVariantMap &responseMap)
|
||||
{
|
||||
if (!responseMap.contains("type"))
|
||||
return false;
|
||||
|
||||
if (responseMap.value("type") == "error")
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SnapdControl::onConnectedChanged(const bool &connected)
|
||||
{
|
||||
if (connected) {
|
||||
device()->setStateValue(snapdAvailableStateTypeId, true);
|
||||
update();
|
||||
} else {
|
||||
device()->setStateValue(snapdAvailableStateTypeId, false);
|
||||
}
|
||||
}
|
||||
|
||||
void SnapdControl::onLoadSystemInfoFinished()
|
||||
{
|
||||
SnapdReply *reply = static_cast<SnapdReply *>(sender());
|
||||
if (!reply->isValid()) {
|
||||
qCDebug(dcSnapd()) << "Load system info request finished with error" << reply->requestPath();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap result = reply->dataMap().value("result").toMap();
|
||||
QDateTime lastRefreshTime = QDateTime::fromString(result.value("refresh").toMap().value("last").toString(), Qt::ISODate);
|
||||
QDateTime nextRefreshTime = QDateTime::fromString(result.value("refresh").toMap().value("next").toString(), Qt::ISODate);
|
||||
|
||||
// Set update time information
|
||||
device()->setStateValue(lastUpdateTimeStateTypeId, lastRefreshTime.toTime_t());
|
||||
device()->setStateValue(nextUpdateTimeStateTypeId, nextRefreshTime.toTime_t());
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void SnapdControl::onLoadSnapListFinished()
|
||||
{
|
||||
SnapdReply *reply = static_cast<SnapdReply *>(sender());
|
||||
if (!reply->isValid()) {
|
||||
qCDebug(dcSnapd()) << "Load system info request finished with error" << reply->requestPath();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
emit snapListUpdated(reply->dataMap().value("result").toList());
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void SnapdControl::onLoadRunningChangesFinished()
|
||||
{
|
||||
SnapdReply *reply = static_cast<SnapdReply *>(sender());
|
||||
if (!reply->isValid()) {
|
||||
qCDebug(dcSnapd()) << "Load running changes request finished with error" << reply->requestPath();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (const QVariant &changeVariant, reply->dataMap().value("result").toList()) {
|
||||
processChange(changeVariant.toMap());
|
||||
}
|
||||
|
||||
if (reply->dataMap().value("result").toList().isEmpty() && m_watchingChanges.isEmpty()) {
|
||||
device()->setStateValue(updateRunningStateTypeId, false);
|
||||
device()->setStateValue(statusStateTypeId, "-");
|
||||
} else {
|
||||
device()->setStateValue(updateRunningStateTypeId, true);
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void SnapdControl::onLoadChangeFinished()
|
||||
{
|
||||
SnapdReply *reply = static_cast<SnapdReply *>(sender());
|
||||
if (!reply->isValid()) {
|
||||
qCDebug(dcSnapd()) << "Load change request finished with error" << reply->requestPath();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
processChange(reply->dataMap().value("result").toMap());
|
||||
|
||||
if (m_watchingChanges.isEmpty()) {
|
||||
device()->setStateValue(updateRunningStateTypeId, false);
|
||||
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void SnapdControl::onSnapRefreshFinished()
|
||||
{
|
||||
SnapdReply *reply = static_cast<SnapdReply *>(sender());
|
||||
if (!reply->isValid()) {
|
||||
qCDebug(dcSnapd()) << "Snap refresh request finished with error" << reply->requestPath();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
//qCDebug(dcSnapd()) << qUtf8Printable(QJsonDocument::fromVariant(reply->dataMap()).toJson(QJsonDocument::Indented));
|
||||
if (!validAsyncResponse(reply->dataMap())) {
|
||||
qCWarning(dcSnapd()) << "Async change request finished with error" << reply->dataMap().value("status").toString() << reply->dataMap().value("").toString();
|
||||
} else {
|
||||
loadChange(reply->dataMap().value("change").toInt());
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void SnapdControl::onSnapRevertFinished()
|
||||
{
|
||||
SnapdReply *reply = static_cast<SnapdReply *>(sender());
|
||||
if (!reply->isValid()) {
|
||||
qCDebug(dcSnapd()) << "Snap revert request finished with error" << reply->requestPath();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
//qCDebug(dcSnapd()) << qUtf8Printable(QJsonDocument::fromVariant(reply->dataMap()).toJson(QJsonDocument::Indented));
|
||||
if (!validAsyncResponse(reply->dataMap())) {
|
||||
qCWarning(dcSnapd()) << "Async change request finished with error" << reply->dataMap().value("status").toString() << reply->dataMap().value("").toString();
|
||||
} else {
|
||||
loadChange(reply->dataMap().value("change").toInt());
|
||||
}
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void SnapdControl::onCheckForUpdatesFinished()
|
||||
{
|
||||
SnapdReply *reply = static_cast<SnapdReply *>(sender());
|
||||
if (!reply->isValid()) {
|
||||
qCDebug(dcSnapd()) << "Snap check for updates request finished with error" << reply->requestPath();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
//qCDebug(dcSnapd()) << qUtf8Printable(QJsonDocument::fromVariant(reply->dataMap()).toJson(QJsonDocument::Indented));
|
||||
device()->setStateValue(updateAvailableStateTypeId, !reply->dataMap().value("result").toList().isEmpty());
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void SnapdControl::onChangeSnapChannelFinished()
|
||||
{
|
||||
SnapdReply *reply = static_cast<SnapdReply *>(sender());
|
||||
if (!reply->isValid()) {
|
||||
qCDebug(dcSnapd()) << "Change snap channel request finished with error" << reply->requestPath();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validAsyncResponse(reply->dataMap())) {
|
||||
qCWarning(dcSnapd()) << "Async change request finished with error" << reply->dataMap().value("status").toString() << reply->dataMap().value("").toString();
|
||||
} else {
|
||||
loadChange(reply->dataMap().value("change").toInt());
|
||||
}
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void SnapdControl::enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void SnapdControl::disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
|
||||
if (m_snapConnection) {
|
||||
m_snapConnection->close();
|
||||
}
|
||||
}
|
||||
|
||||
void SnapdControl::update()
|
||||
{
|
||||
if (!m_snapConnection)
|
||||
return;
|
||||
|
||||
if (!available())
|
||||
return;
|
||||
|
||||
if (!enabled())
|
||||
return;
|
||||
|
||||
// Try to reconnect if unconnected
|
||||
if (m_snapConnection->state() == QLocalSocket::UnconnectedState) {
|
||||
m_snapConnection->connectToServer(m_snapdSocketPath, QLocalSocket::ReadWrite);
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: this makes sure the state is realy connected (including connection initialisation stuff)
|
||||
if (!m_snapConnection->isConnected())
|
||||
return;
|
||||
|
||||
// Update information
|
||||
if (!m_watchingChanges.isEmpty()) {
|
||||
// We are watching currently changes
|
||||
foreach (const int &change, m_watchingChanges) {
|
||||
loadChange(change);
|
||||
}
|
||||
loadRunningChanges();
|
||||
} else {
|
||||
// Normal refresh
|
||||
loadSystemInfo();
|
||||
loadSnapList();
|
||||
checkForUpdates();
|
||||
loadRunningChanges();
|
||||
}
|
||||
}
|
||||
|
||||
void SnapdControl::snapRefresh()
|
||||
{
|
||||
if (!m_snapConnection)
|
||||
return;
|
||||
|
||||
if (!m_snapConnection->isConnected())
|
||||
return;
|
||||
|
||||
QVariantMap request;
|
||||
request.insert("action", "refresh");
|
||||
|
||||
qCDebug(dcSnapd()) << "Refresh all snaps";
|
||||
SnapdReply *reply = m_snapConnection->post("/v2/snaps", QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact));
|
||||
connect(reply, &SnapdReply::finished, this, &SnapdControl::onSnapRefreshFinished);
|
||||
}
|
||||
|
||||
void SnapdControl::changeSnapChannel(const QString &snapName, const QString &channel)
|
||||
{
|
||||
if (!m_snapConnection)
|
||||
return;
|
||||
|
||||
if (!m_snapConnection->isConnected())
|
||||
return;
|
||||
|
||||
QVariantMap request;
|
||||
request.insert("action", "refresh");
|
||||
request.insert("channel", channel);
|
||||
|
||||
qCDebug(dcSnapd()) << "Refresh snap" << snapName << "to channel" << channel;
|
||||
SnapdReply *reply = m_snapConnection->post(QString("/v2/snaps/%1").arg(snapName), QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact));
|
||||
connect(reply, &SnapdReply::finished, this, &SnapdControl::onChangeSnapChannelFinished);
|
||||
}
|
||||
|
||||
void SnapdControl::checkForUpdates()
|
||||
{
|
||||
if (!m_snapConnection)
|
||||
return;
|
||||
|
||||
if (!m_snapConnection->isConnected())
|
||||
return;
|
||||
|
||||
SnapdReply *reply = m_snapConnection->get("/v2/find?select=refresh");
|
||||
connect(reply, &SnapdReply::finished, this, &SnapdControl::onCheckForUpdatesFinished);
|
||||
}
|
||||
|
||||
void SnapdControl::snapRevert(const QString &snapName)
|
||||
{
|
||||
if (!m_snapConnection)
|
||||
return;
|
||||
|
||||
if (!m_snapConnection->isConnected())
|
||||
return;
|
||||
|
||||
QVariantMap request;
|
||||
request.insert("action", "revert");
|
||||
|
||||
qCDebug(dcSnapd()) << "Revert snap" << snapName;
|
||||
SnapdReply *reply = m_snapConnection->post(QString("/v2/snaps/%1").arg(snapName), QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact));
|
||||
connect(reply, &SnapdReply::finished, this, &SnapdControl::onSnapRevertFinished);
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2017 Simon Stürz <simon.stuerz@guh.io *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef SNAPDCONTROL_H
|
||||
#define SNAPDCONTROL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QLocalSocket>
|
||||
|
||||
#include "plugin/device.h"
|
||||
#include "snapdconnection.h"
|
||||
|
||||
class SnapdControl : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SnapdControl(Device *device, QObject *parent = nullptr);
|
||||
|
||||
Device *device();
|
||||
|
||||
bool available() const;
|
||||
bool connected() const;
|
||||
bool enabled() const;
|
||||
|
||||
private:
|
||||
Device *m_device = nullptr;
|
||||
SnapdConnection *m_snapConnection = nullptr;
|
||||
|
||||
QString m_snapdSocketPath;
|
||||
bool m_enabled = true;
|
||||
|
||||
QList<int> m_watchingChanges;
|
||||
|
||||
// Update calls
|
||||
void loadSystemInfo();
|
||||
void loadSnapList();
|
||||
void loadRunningChanges();
|
||||
void loadChange(const int &change);
|
||||
|
||||
void processChange(const QVariantMap &changeMap);
|
||||
bool validAsyncResponse(const QVariantMap &responseMap);
|
||||
|
||||
private slots:
|
||||
void onConnectedChanged(const bool &connected);
|
||||
|
||||
// Response handler for different requests
|
||||
void onLoadSystemInfoFinished();
|
||||
void onLoadSnapListFinished();
|
||||
void onLoadRunningChangesFinished();
|
||||
void onLoadChangeFinished();
|
||||
|
||||
void onSnapRefreshFinished();
|
||||
void onSnapRevertFinished();
|
||||
void onCheckForUpdatesFinished();
|
||||
void onChangeSnapChannelFinished();
|
||||
|
||||
signals:
|
||||
void snapListUpdated(const QVariantList &snapList);
|
||||
|
||||
public slots:
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
// Snapd request calls
|
||||
void update();
|
||||
void snapRefresh();
|
||||
void checkForUpdates();
|
||||
void snapRevert(const QString &snapName);
|
||||
void changeSnapChannel(const QString &snapName, const QString &channel);
|
||||
};
|
||||
|
||||
#endif // SNAPDCONTROL_H
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#include "snapdreply.h"
|
||||
|
||||
QString SnapdReply::requestPath() const
|
||||
{
|
||||
return m_requestPath;
|
||||
}
|
||||
|
||||
QString SnapdReply::requestMethod() const
|
||||
{
|
||||
return m_requestMethod;
|
||||
}
|
||||
|
||||
QByteArray SnapdReply::requestRawMessage() const
|
||||
{
|
||||
return m_requestRawMessage;
|
||||
}
|
||||
|
||||
int SnapdReply::statusCode() const
|
||||
{
|
||||
return m_statusCode;
|
||||
}
|
||||
|
||||
QString SnapdReply::statusMessage() const
|
||||
{
|
||||
return m_statusMessage;
|
||||
}
|
||||
|
||||
QHash<QString, QString> SnapdReply::header() const
|
||||
{
|
||||
return m_header;
|
||||
}
|
||||
|
||||
QVariantMap SnapdReply::dataMap() const
|
||||
{
|
||||
return m_dataMap;
|
||||
}
|
||||
|
||||
bool SnapdReply::isFinished() const
|
||||
{
|
||||
return m_isFinished;
|
||||
}
|
||||
|
||||
bool SnapdReply::isValid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
SnapdReply::SnapdReply(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SnapdReply::setRequestPath(const QString &requestPath)
|
||||
{
|
||||
m_requestPath = requestPath;
|
||||
}
|
||||
|
||||
void SnapdReply::setRequestMethod(const QString &requestMethod)
|
||||
{
|
||||
m_requestMethod = requestMethod;
|
||||
}
|
||||
|
||||
void SnapdReply::setRequestRawMessage(const QByteArray &rawMessage)
|
||||
{
|
||||
m_requestRawMessage = rawMessage;
|
||||
}
|
||||
|
||||
void SnapdReply::setStatusCode(const int &statusCode)
|
||||
{
|
||||
m_statusCode = statusCode;
|
||||
}
|
||||
|
||||
void SnapdReply::setStatusMessage(const QString &statusMessage)
|
||||
{
|
||||
m_statusMessage = statusMessage;
|
||||
}
|
||||
|
||||
void SnapdReply::setHeader(const QHash<QString, QString> header)
|
||||
{
|
||||
m_header = header;
|
||||
}
|
||||
|
||||
void SnapdReply::setDataMap(const QVariantMap &dataMap)
|
||||
{
|
||||
m_dataMap = dataMap;
|
||||
}
|
||||
|
||||
void SnapdReply::setFinished(const bool &valid)
|
||||
{
|
||||
m_isFinished = true;
|
||||
m_valid = valid;
|
||||
|
||||
emit finished();
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef SNAPDREPLY_H
|
||||
#define SNAPDREPLY_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QVariantMap>
|
||||
|
||||
class SnapdReply : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class SnapdConnection;
|
||||
|
||||
public:
|
||||
// Request
|
||||
QString requestPath() const;
|
||||
QString requestMethod() const;
|
||||
QByteArray requestRawMessage() const;
|
||||
|
||||
// Response
|
||||
int statusCode() const;
|
||||
QString statusMessage() const;
|
||||
QHash<QString, QString> header() const;
|
||||
QVariantMap dataMap() const;
|
||||
|
||||
bool isFinished() const;
|
||||
bool isValid() const;
|
||||
|
||||
private:
|
||||
explicit SnapdReply(QObject *parent = nullptr);
|
||||
|
||||
QString m_requestPath;
|
||||
QString m_requestMethod;
|
||||
QByteArray m_requestRawMessage;
|
||||
|
||||
int m_statusCode;
|
||||
QString m_statusMessage;
|
||||
QHash<QString, QString> m_header;
|
||||
QVariantMap m_dataMap;
|
||||
|
||||
bool m_isFinished = false;
|
||||
bool m_valid = false;
|
||||
|
||||
// Methods for SnapdConnection
|
||||
void setRequestPath(const QString &requestPath);
|
||||
void setRequestMethod(const QString &requestMethod);
|
||||
void setRequestRawMessage(const QByteArray &rawMessage);
|
||||
|
||||
void setStatusCode(const int &statusCode);
|
||||
void setStatusMessage(const QString &statusMessage);
|
||||
void setHeader(const QHash<QString, QString> header);
|
||||
void setDataMap(const QVariantMap &dataMap);
|
||||
void setFinished(const bool &valid = true);
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
};
|
||||
|
||||
#endif // SNAPDREPLY_H
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="de_DE">
|
||||
<context>
|
||||
<name>Snapd</name>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="65"/>
|
||||
<source>Snapd</source>
|
||||
<extracomment>The name of the plugin Snapd (b82bce59-59bf-48b3-b781-54a6f45800f3)</extracomment>
|
||||
<translation>Snapd</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="68"/>
|
||||
<source>Advanced mode</source>
|
||||
<extracomment>The name of the paramType (017fe4c5-fc41-41fe-8e67-08fdaccb89ea) of Snapd</extracomment>
|
||||
<translation>Fortgeschrittener Modus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="71"/>
|
||||
<source>Canonical</source>
|
||||
<extracomment>The name of the vendor (60582ddf-32ea-4fcd-a6f2-f3beaaf21517)</extracomment>
|
||||
<translation>Canonical</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="83"/>
|
||||
<source>System update available changed</source>
|
||||
<extracomment>The name of the autocreated EventType (a6b1d24b-d523-4516-9bce-5b467e5e09b2)</extracomment>
|
||||
<translation>Systemupdate Verfügbarkeit geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="86"/>
|
||||
<source>System update available</source>
|
||||
<extracomment>The name of the ParamType of StateType (a6b1d24b-d523-4516-9bce-5b467e5e09b2) of DeviceClass Update manager</extracomment>
|
||||
<translation>Systemupdate verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="95"/>
|
||||
<source>Last automatic system update time changed</source>
|
||||
<extracomment>The name of the autocreated EventType (c671545a-6bde-4c08-8e37-0d256841a3a5)</extracomment>
|
||||
<translation>Letztes automatisches Systemupdate geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="98"/>
|
||||
<source>Last automatic system update</source>
|
||||
<extracomment>The name of the ParamType of StateType (c671545a-6bde-4c08-8e37-0d256841a3a5) of DeviceClass Update manager</extracomment>
|
||||
<translation>Letztes automatisches Systemupdate</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="101"/>
|
||||
<source>Next automatic system update time changed</source>
|
||||
<extracomment>The name of the autocreated EventType (122c2423-a1d9-400f-80f8-b1f798975914)</extracomment>
|
||||
<translation>Nächstes automatisches Systemupdate geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="104"/>
|
||||
<source>Next automatic system update</source>
|
||||
<extracomment>The name of the ParamType of StateType (122c2423-a1d9-400f-80f8-b1f798975914) of DeviceClass Update manager</extracomment>
|
||||
<translation>Nächstes automatisches Systemupdate</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="125"/>
|
||||
<source>ID</source>
|
||||
<extracomment>The name of the paramType (9afb98fb-f717-4f4c-8009-1a6514054c5f) of Snap</extracomment>
|
||||
<translation>ID</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="128"/>
|
||||
<source>Summary</source>
|
||||
<extracomment>The name of the paramType (12b9a65f-970b-49b5-b1d0-1625fc6d8758) of Snap</extracomment>
|
||||
<translation>Zusammenfassung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="131"/>
|
||||
<source>Description</source>
|
||||
<extracomment>The name of the paramType (fe24c61b-e154-4259-b7ca-6f0602e9d1c3) of Snap</extracomment>
|
||||
<translation>Beschreibung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="134"/>
|
||||
<source>Developer</source>
|
||||
<extracomment>The name of the paramType (76ead9c5-0a18-40a2-b31d-f6bb6dfea0a5) of Snap</extracomment>
|
||||
<translation>Entwickler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="140"/>
|
||||
<source>Channel</source>
|
||||
<extracomment>The name of the ParamType of StateType (7be2b61e-3f59-4b92-b2bb-50d027bb92ff) of DeviceClass Snap</extracomment>
|
||||
<translation>Kanal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="143"/>
|
||||
<source>Set channel</source>
|
||||
<extracomment>The name of the autocreated ActionType (7be2b61e-3f59-4b92-b2bb-50d027bb92ff)</extracomment>
|
||||
<translation>Setze Kanal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="146"/>
|
||||
<source>Version changed</source>
|
||||
<extracomment>The name of the autocreated EventType (532a95f3-db29-427e-bb32-d5a22029e586)</extracomment>
|
||||
<translation>Version geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="149"/>
|
||||
<source>Version</source>
|
||||
<extracomment>The name of the ParamType of StateType (532a95f3-db29-427e-bb32-d5a22029e586) of DeviceClass Snap</extracomment>
|
||||
<translation>Version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="152"/>
|
||||
<source>Revision changed</source>
|
||||
<extracomment>The name of the autocreated EventType (f26a6404-e011-11e7-9224-2350048461eb)</extracomment>
|
||||
<translation>Revision geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="155"/>
|
||||
<source>Revision</source>
|
||||
<extracomment>The name of the ParamType of StateType (f26a6404-e011-11e7-9224-2350048461eb) of DeviceClass Snap</extracomment>
|
||||
<translation>Revision</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="158"/>
|
||||
<source>Rollback to previous version</source>
|
||||
<extracomment>The name of the ActionType e061dee6-62fc-45cc-9c9f-403c2be52939 of deviceClass Snap</extracomment>
|
||||
<translation>Zurücksetzen auf vorhergehende Version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="113"/>
|
||||
<source>Start update</source>
|
||||
<extracomment>The name of the ActionType 45626b75-f09d-4dd1-b6c4-ee33201b47b0 of deviceClass Update manager</extracomment>
|
||||
<translation>Starte Systemupdate</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="74"/>
|
||||
<source>Update manager</source>
|
||||
<extracomment>The name of the DeviceClass (d90cda58-4d8c-4b7f-a982-38e56a95b72a)</extracomment>
|
||||
<translation>Update Manager</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="77"/>
|
||||
<source>Update manager available changed</source>
|
||||
<extracomment>The name of the autocreated EventType (6b662b3e-fd12-4f24-be77-aec066f16d8c)</extracomment>
|
||||
<translation>Update Manager Verfügbarkeit geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="80"/>
|
||||
<source>Update manager available</source>
|
||||
<extracomment>The name of the ParamType of StateType (6b662b3e-fd12-4f24-be77-aec066f16d8c) of DeviceClass Update manager</extracomment>
|
||||
<translation>Update Manager verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="119"/>
|
||||
<source>Snap</source>
|
||||
<extracomment>The name of the DeviceClass (ff0840d7-fcfc-4403-9d9f-301610d5a437)</extracomment>
|
||||
<translation>Snap</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="89"/>
|
||||
<source>System update running changed</source>
|
||||
<extracomment>The name of the autocreated EventType (01ca7a22-5607-4c5e-a465-a2ae7e8b529c)</extracomment>
|
||||
<translation>Systemupdate aktiv geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="92"/>
|
||||
<source>System update running</source>
|
||||
<extracomment>The name of the ParamType of StateType (01ca7a22-5607-4c5e-a465-a2ae7e8b529c) of DeviceClass Update manager</extracomment>
|
||||
<translation>Systemupdate aktiv</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="107"/>
|
||||
<source>Status changed</source>
|
||||
<extracomment>The name of the autocreated EventType (4987aca3-3916-4cb3-938f-df6c99d04dbf)</extracomment>
|
||||
<translation>Status geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="110"/>
|
||||
<source>Status</source>
|
||||
<extracomment>The name of the ParamType of StateType (4987aca3-3916-4cb3-938f-df6c99d04dbf) of DeviceClass Update manager</extracomment>
|
||||
<translation>Status</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="122"/>
|
||||
<source>Name</source>
|
||||
<extracomment>The name of the paramType (4f38614d-8be0-48dc-a24d-cee9ff1f2a89) of Snap</extracomment>
|
||||
<translation>Name</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="137"/>
|
||||
<source>Channel changed</source>
|
||||
<extracomment>The name of the autocreated EventType (7be2b61e-3f59-4b92-b2bb-50d027bb92ff)</extracomment>
|
||||
<translation>Kanal geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="116"/>
|
||||
<source>Check for updates</source>
|
||||
<extracomment>The name of the ActionType 4738f2c9-666e-45b9-91d3-7bcbf722b669 of deviceClass Update manager</extracomment>
|
||||
<translation>Nach Aktualisierungen suchen</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1">
|
||||
<context>
|
||||
<name>Snapd</name>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="65"/>
|
||||
<source>Snapd</source>
|
||||
<extracomment>The name of the plugin Snapd (b82bce59-59bf-48b3-b781-54a6f45800f3)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="68"/>
|
||||
<source>Advanced mode</source>
|
||||
<extracomment>The name of the paramType (017fe4c5-fc41-41fe-8e67-08fdaccb89ea) of Snapd</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="71"/>
|
||||
<source>Canonical</source>
|
||||
<extracomment>The name of the vendor (60582ddf-32ea-4fcd-a6f2-f3beaaf21517)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="83"/>
|
||||
<source>System update available changed</source>
|
||||
<extracomment>The name of the autocreated EventType (a6b1d24b-d523-4516-9bce-5b467e5e09b2)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="86"/>
|
||||
<source>System update available</source>
|
||||
<extracomment>The name of the ParamType of StateType (a6b1d24b-d523-4516-9bce-5b467e5e09b2) of DeviceClass Update manager</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="95"/>
|
||||
<source>Last automatic system update time changed</source>
|
||||
<extracomment>The name of the autocreated EventType (c671545a-6bde-4c08-8e37-0d256841a3a5)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="98"/>
|
||||
<source>Last automatic system update</source>
|
||||
<extracomment>The name of the ParamType of StateType (c671545a-6bde-4c08-8e37-0d256841a3a5) of DeviceClass Update manager</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="101"/>
|
||||
<source>Next automatic system update time changed</source>
|
||||
<extracomment>The name of the autocreated EventType (122c2423-a1d9-400f-80f8-b1f798975914)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="104"/>
|
||||
<source>Next automatic system update</source>
|
||||
<extracomment>The name of the ParamType of StateType (122c2423-a1d9-400f-80f8-b1f798975914) of DeviceClass Update manager</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="125"/>
|
||||
<source>ID</source>
|
||||
<extracomment>The name of the paramType (9afb98fb-f717-4f4c-8009-1a6514054c5f) of Snap</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="128"/>
|
||||
<source>Summary</source>
|
||||
<extracomment>The name of the paramType (12b9a65f-970b-49b5-b1d0-1625fc6d8758) of Snap</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="131"/>
|
||||
<source>Description</source>
|
||||
<extracomment>The name of the paramType (fe24c61b-e154-4259-b7ca-6f0602e9d1c3) of Snap</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="134"/>
|
||||
<source>Developer</source>
|
||||
<extracomment>The name of the paramType (76ead9c5-0a18-40a2-b31d-f6bb6dfea0a5) of Snap</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="140"/>
|
||||
<source>Channel</source>
|
||||
<extracomment>The name of the ParamType of StateType (7be2b61e-3f59-4b92-b2bb-50d027bb92ff) of DeviceClass Snap</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="143"/>
|
||||
<source>Set channel</source>
|
||||
<extracomment>The name of the autocreated ActionType (7be2b61e-3f59-4b92-b2bb-50d027bb92ff)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="146"/>
|
||||
<source>Version changed</source>
|
||||
<extracomment>The name of the autocreated EventType (532a95f3-db29-427e-bb32-d5a22029e586)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="149"/>
|
||||
<source>Version</source>
|
||||
<extracomment>The name of the ParamType of StateType (532a95f3-db29-427e-bb32-d5a22029e586) of DeviceClass Snap</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="152"/>
|
||||
<source>Revision changed</source>
|
||||
<extracomment>The name of the autocreated EventType (f26a6404-e011-11e7-9224-2350048461eb)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="155"/>
|
||||
<source>Revision</source>
|
||||
<extracomment>The name of the ParamType of StateType (f26a6404-e011-11e7-9224-2350048461eb) of DeviceClass Snap</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="158"/>
|
||||
<source>Rollback to previous version</source>
|
||||
<extracomment>The name of the ActionType e061dee6-62fc-45cc-9c9f-403c2be52939 of deviceClass Snap</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="113"/>
|
||||
<source>Start update</source>
|
||||
<extracomment>The name of the ActionType 45626b75-f09d-4dd1-b6c4-ee33201b47b0 of deviceClass Update manager</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="74"/>
|
||||
<source>Update manager</source>
|
||||
<extracomment>The name of the DeviceClass (d90cda58-4d8c-4b7f-a982-38e56a95b72a)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="77"/>
|
||||
<source>Update manager available changed</source>
|
||||
<extracomment>The name of the autocreated EventType (6b662b3e-fd12-4f24-be77-aec066f16d8c)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="80"/>
|
||||
<source>Update manager available</source>
|
||||
<extracomment>The name of the ParamType of StateType (6b662b3e-fd12-4f24-be77-aec066f16d8c) of DeviceClass Update manager</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="119"/>
|
||||
<source>Snap</source>
|
||||
<extracomment>The name of the DeviceClass (ff0840d7-fcfc-4403-9d9f-301610d5a437)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="89"/>
|
||||
<source>System update running changed</source>
|
||||
<extracomment>The name of the autocreated EventType (01ca7a22-5607-4c5e-a465-a2ae7e8b529c)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="92"/>
|
||||
<source>System update running</source>
|
||||
<extracomment>The name of the ParamType of StateType (01ca7a22-5607-4c5e-a465-a2ae7e8b529c) of DeviceClass Update manager</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="107"/>
|
||||
<source>Status changed</source>
|
||||
<extracomment>The name of the autocreated EventType (4987aca3-3916-4cb3-938f-df6c99d04dbf)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="110"/>
|
||||
<source>Status</source>
|
||||
<extracomment>The name of the ParamType of StateType (4987aca3-3916-4cb3-938f-df6c99d04dbf) of DeviceClass Update manager</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="122"/>
|
||||
<source>Name</source>
|
||||
<extracomment>The name of the paramType (4f38614d-8be0-48dc-a24d-cee9ff1f2a89) of Snap</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="137"/>
|
||||
<source>Channel changed</source>
|
||||
<extracomment>The name of the autocreated EventType (7be2b61e-3f59-4b92-b2bb-50d027bb92ff)</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build-guh-plugins-Desktop-Debug/snapd/plugininfo.h" line="116"/>
|
||||
<source>Check for updates</source>
|
||||
<extracomment>The name of the ActionType 4738f2c9-666e-45b9-91d3-7bcbf722b669 of deviceClass Update manager</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
Loading…
Reference in New Issue