Merge PR #104: renamed HTTP commander vendor, fixed segfault on device removed
This commit is contained in:
commit
741ba4e65e
@ -1,7 +1,7 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> *
|
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
|
||||||
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
|
* Copyright (C) 2018 Simon Stürz <simon.stuerz@nymea.io> *
|
||||||
* *
|
* *
|
||||||
* This file is part of nymea. *
|
* This file is part of nymea. *
|
||||||
* *
|
* *
|
||||||
@ -26,26 +26,33 @@
|
|||||||
#include "plugininfo.h"
|
#include "plugininfo.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\page httpcommander.html
|
||||||
|
\title HTTP commander
|
||||||
|
\brief Plugin for generic HTTP commands
|
||||||
|
\ingroup plugins
|
||||||
|
\ingroup nymea-plugins
|
||||||
|
This plug-in supports generic HTTP calls like get, put, post
|
||||||
|
\chapter Plugin properties
|
||||||
|
Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses}
|
||||||
|
and \l{Vendor}{Vendors} of this \l{DevicePlugin}.
|
||||||
|
For more details how to read this JSON file please check out the documentation for \l{The plugin JSON File}.
|
||||||
|
\quotefile plugins/deviceplugins/denon/devicepluginhttpcommander.json
|
||||||
|
*/
|
||||||
|
|
||||||
DevicePluginHttpCommander::DevicePluginHttpCommander()
|
DevicePluginHttpCommander::DevicePluginHttpCommander()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
DevicePluginHttpCommander::~DevicePluginHttpCommander()
|
|
||||||
{
|
|
||||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DevicePluginHttpCommander::init()
|
|
||||||
{
|
|
||||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
|
|
||||||
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginHttpCommander::onPluginTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceManager::DeviceSetupStatus DevicePluginHttpCommander::setupDevice(Device *device)
|
DeviceManager::DeviceSetupStatus DevicePluginHttpCommander::setupDevice(Device *device)
|
||||||
{
|
{
|
||||||
qDebug(dcHttpCommander()) << "Setup device" << device->name() << device->params();
|
qDebug(dcHttpCommander()) << "Setup device" << device->name() << device->params();
|
||||||
|
|
||||||
// Get
|
if(!m_pluginTimer) {
|
||||||
|
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);
|
||||||
|
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginHttpCommander::onPluginTimer);
|
||||||
|
}
|
||||||
|
|
||||||
if (device->deviceClassId() == httpGetCommanderDeviceClassId) {
|
if (device->deviceClassId() == httpGetCommanderDeviceClassId) {
|
||||||
QUrl url = device->paramValue(httpGetCommanderDeviceUrlParamTypeId).toUrl();
|
QUrl url = device->paramValue(httpGetCommanderDeviceUrlParamTypeId).toUrl();
|
||||||
if (!url.isValid()) {
|
if (!url.isValid()) {
|
||||||
@ -56,28 +63,23 @@ DeviceManager::DeviceSetupStatus DevicePluginHttpCommander::setupDevice(Device *
|
|||||||
return DeviceManager::DeviceSetupStatusSuccess;
|
return DeviceManager::DeviceSetupStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put
|
|
||||||
if (device->deviceClassId() == httpPutCommanderDeviceClassId) {
|
if (device->deviceClassId() == httpPutCommanderDeviceClassId) {
|
||||||
QUrl url = device->paramValue(httpPutCommanderDeviceUrlParamTypeId).toUrl();
|
QUrl url = device->paramValue(httpPutCommanderDeviceUrlParamTypeId).toUrl();
|
||||||
if (!url.isValid()) {
|
if (!url.isValid()) {
|
||||||
qDebug(dcHttpCommander()) << "Given URL is not valid";
|
qDebug(dcHttpCommander()) << "Given URL is not valid";
|
||||||
return DeviceManager::DeviceSetupStatusFailure;
|
return DeviceManager::DeviceSetupStatusFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeviceManager::DeviceSetupStatusSuccess;
|
return DeviceManager::DeviceSetupStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post
|
|
||||||
if (device->deviceClassId() == httpPostCommanderDeviceClassId) {
|
if (device->deviceClassId() == httpPostCommanderDeviceClassId) {
|
||||||
QUrl url = device->paramValue(httpPostCommanderDeviceUrlParamTypeId).toUrl();
|
QUrl url = device->paramValue(httpPostCommanderDeviceUrlParamTypeId).toUrl();
|
||||||
if (!url.isValid()) {
|
if (!url.isValid()) {
|
||||||
qDebug(dcHttpCommander()) << "Given URL is not valid";
|
qDebug(dcHttpCommander()) << "Given URL is not valid";
|
||||||
return DeviceManager::DeviceSetupStatusFailure;
|
return DeviceManager::DeviceSetupStatusFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeviceManager::DeviceSetupStatusSuccess;
|
return DeviceManager::DeviceSetupStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeviceManager::DeviceSetupStatusFailure;
|
return DeviceManager::DeviceSetupStatusFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,16 +89,6 @@ void DevicePluginHttpCommander::postSetupDevice(Device *device)
|
|||||||
if (device->deviceClassId() == httpGetCommanderDeviceClassId) {
|
if (device->deviceClassId() == httpGetCommanderDeviceClassId) {
|
||||||
makeGetCall(device);
|
makeGetCall(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device->deviceClassId() == httpPostCommanderDeviceClassId) {
|
|
||||||
//TODO find a way to check it the URL is reachable
|
|
||||||
device->setStateValue(httpPostCommanderConnectedStateTypeId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device->deviceClassId() == httpPutCommanderDeviceClassId) {
|
|
||||||
//TODO find a way to check it the URL is reachable
|
|
||||||
device->setStateValue(httpPutCommanderConnectedStateTypeId, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -124,10 +116,10 @@ DeviceManager::DeviceError DevicePluginHttpCommander::executeAction(Device *devi
|
|||||||
|
|
||||||
// check if this is the "press" action
|
// check if this is the "press" action
|
||||||
if (action.actionTypeId() == httpPutCommanderPutActionTypeId) {
|
if (action.actionTypeId() == httpPutCommanderPutActionTypeId) {
|
||||||
|
|
||||||
QUrl url = device->paramValue(httpPutCommanderDeviceUrlParamTypeId).toUrl();
|
QUrl url = device->paramValue(httpPutCommanderDeviceUrlParamTypeId).toUrl();
|
||||||
url.setPort(device->paramValue(httpPutCommanderDevicePortParamTypeId).toInt());
|
url.setPort(device->paramValue(httpPutCommanderDevicePortParamTypeId).toInt());
|
||||||
QByteArray payload = action.param(httpPutCommanderPutActionDataParamTypeId).value().toByteArray();
|
QByteArray payload = action.param(httpPutCommanderPutActionDataParamTypeId).value().toByteArray();
|
||||||
|
|
||||||
QNetworkReply *reply = hardwareManager()->networkManager()->put(QNetworkRequest(url), payload);
|
QNetworkReply *reply = hardwareManager()->networkManager()->put(QNetworkRequest(url), payload);
|
||||||
connect(reply, &QNetworkReply::finished, this, &DevicePluginHttpCommander::onPutRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, &DevicePluginHttpCommander::onPutRequestFinished);
|
||||||
|
|
||||||
@ -145,7 +137,7 @@ void DevicePluginHttpCommander::makeGetCall(Device *device)
|
|||||||
url.setPort(device->paramValue(httpGetCommanderDevicePortParamTypeId).toInt());
|
url.setPort(device->paramValue(httpGetCommanderDevicePortParamTypeId).toInt());
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setUrl(url);
|
request.setUrl(url);
|
||||||
request.setRawHeader("User-Agent", "guhIO 1.0");
|
request.setRawHeader("User-Agent", "nymea 1.0");
|
||||||
|
|
||||||
QNetworkReply *reply = hardwareManager()->networkManager()->get(request);
|
QNetworkReply *reply = hardwareManager()->networkManager()->get(request);
|
||||||
connect(reply, &QNetworkReply::finished, this, &DevicePluginHttpCommander::onGetRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, &DevicePluginHttpCommander::onGetRequestFinished);
|
||||||
@ -176,16 +168,12 @@ void DevicePluginHttpCommander::onGetRequestFinished()
|
|||||||
|
|
||||||
Device *device = m_httpRequests.take(reply);
|
Device *device = m_httpRequests.take(reply);
|
||||||
device->setStateValue(httpGetCommanderResponseStateTypeId, data);
|
device->setStateValue(httpGetCommanderResponseStateTypeId, data);
|
||||||
|
device->setStateValue(httpGetCommanderStatusStateTypeId, true);
|
||||||
|
|
||||||
// Check HTTP status code
|
// Check HTTP status code
|
||||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString();
|
qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString();
|
||||||
device->setStateValue(httpGetCommanderConnectedStateTypeId, false);
|
|
||||||
reply->deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
device->setStateValue(httpGetCommanderConnectedStateTypeId, true);
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,16 +191,12 @@ void DevicePluginHttpCommander::onPostRequestFinished()
|
|||||||
|
|
||||||
Device *device = m_httpRequests.take(reply);
|
Device *device = m_httpRequests.take(reply);
|
||||||
device->setStateValue(httpPostCommanderResponseStateTypeId, data);
|
device->setStateValue(httpPostCommanderResponseStateTypeId, data);
|
||||||
|
device->setStateValue(httpPostCommanderStatusStateTypeId, status);
|
||||||
|
|
||||||
// Check HTTP status code
|
// Check HTTP status code
|
||||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString();
|
qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString();
|
||||||
device->setStateValue(httpPostCommanderConnectedStateTypeId, false);
|
|
||||||
reply->deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
device->setStateValue(httpPostCommanderConnectedStateTypeId, true);
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,26 +214,30 @@ void DevicePluginHttpCommander::onPutRequestFinished()
|
|||||||
|
|
||||||
Device *device = m_httpRequests.take(reply);
|
Device *device = m_httpRequests.take(reply);
|
||||||
device->setStateValue(httpPutCommanderResponseStateTypeId, data);
|
device->setStateValue(httpPutCommanderResponseStateTypeId, data);
|
||||||
|
device->setStateValue(httpPutCommanderStatusStateTypeId, status);
|
||||||
|
|
||||||
// Check HTTP status code
|
// Check HTTP status code
|
||||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString();
|
qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString();
|
||||||
device->setStateValue(httpPutCommanderConnectedStateTypeId, false);
|
|
||||||
reply->deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
device->setStateValue(httpPutCommanderConnectedStateTypeId, true);
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DevicePluginHttpCommander::deviceRemoved(Device *device)
|
void DevicePluginHttpCommander::deviceRemoved(Device *device)
|
||||||
{
|
{
|
||||||
if (m_httpRequests.values().contains(device)) {
|
if ((device->deviceClassId() == httpPostCommanderDeviceClassId) ||
|
||||||
QNetworkReply *reply = m_httpRequests.key(device);
|
(device->deviceClassId() == httpPutCommanderDeviceClassId) ||
|
||||||
m_httpRequests.remove(reply);
|
(device->deviceClassId() == httpGetCommanderDeviceClassId)) {
|
||||||
// Note: will be deleted once finished
|
|
||||||
|
while (m_httpRequests.values().contains(device)) {
|
||||||
|
QNetworkReply *reply = m_httpRequests.key(device);
|
||||||
|
m_httpRequests.remove(reply);
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myDevices().empty()) {
|
||||||
|
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> *
|
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
|
||||||
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
|
* Copyright (C) 2018 Simon Stürz <simon.stuerz@nymea.io> *
|
||||||
* *
|
* *
|
||||||
* This file is part of nymea. *
|
* This file is part of nymea. *
|
||||||
* *
|
* *
|
||||||
@ -29,6 +29,7 @@
|
|||||||
#include "plugintimer.h"
|
#include "plugintimer.h"
|
||||||
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
#include <QHostInfo>
|
||||||
|
|
||||||
class DevicePluginHttpCommander : public DevicePlugin
|
class DevicePluginHttpCommander : public DevicePlugin
|
||||||
{
|
{
|
||||||
@ -39,9 +40,7 @@ class DevicePluginHttpCommander : public DevicePlugin
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DevicePluginHttpCommander();
|
explicit DevicePluginHttpCommander();
|
||||||
~DevicePluginHttpCommander();
|
|
||||||
|
|
||||||
void init() override;
|
|
||||||
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
||||||
void postSetupDevice(Device *device) override;
|
void postSetupDevice(Device *device) override;
|
||||||
void deviceRemoved(Device *device) override;
|
void deviceRemoved(Device *device) override;
|
||||||
|
|||||||
@ -4,16 +4,16 @@
|
|||||||
"id": "4e62670c-6268-4487-8dff-cccca498731a",
|
"id": "4e62670c-6268-4487-8dff-cccca498731a",
|
||||||
"vendors": [
|
"vendors": [
|
||||||
{
|
{
|
||||||
"name": "httpCommander",
|
"displayName": "nymea",
|
||||||
"displayName": "HTTP commander",
|
"name": "nymea",
|
||||||
"id": "45d7c941-7690-43c9-92fc-fab36e1cebd0",
|
"id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6",
|
||||||
"deviceClasses": [
|
"deviceClasses": [
|
||||||
{
|
{
|
||||||
"id": "b101abdf-86fd-4d2e-a657-ee76044235bd",
|
"id": "b101abdf-86fd-4d2e-a657-ee76044235bd",
|
||||||
"name": "httpPostCommander",
|
"name": "httpPostCommander",
|
||||||
"displayName": "HTTP post commander",
|
"displayName": "HTTP post",
|
||||||
"createMethods": ["user"],
|
"createMethods": ["user"],
|
||||||
"interfaces": ["connectable"],
|
"interfaces": [ ],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "020f672e-cc9a-4b74-92dd-a92a93ab1d23",
|
"id": "020f672e-cc9a-4b74-92dd-a92a93ab1d23",
|
||||||
@ -21,7 +21,7 @@
|
|||||||
"displayName": "Address",
|
"displayName": "Address",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"inputType": "None",
|
"inputType": "None",
|
||||||
"defaultValue": "https://nymea.io"
|
"defaultValue": "https://httpbin.org/post"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "37830ea8-2249-46e6-aaca-12164928a81a",
|
"id": "37830ea8-2249-46e6-aaca-12164928a81a",
|
||||||
@ -34,11 +34,11 @@
|
|||||||
"stateTypes": [
|
"stateTypes": [
|
||||||
{
|
{
|
||||||
"id": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39",
|
"id": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39",
|
||||||
"name": "connected",
|
"name": "status",
|
||||||
"displayName": "Reachable",
|
"displayName": "Status code",
|
||||||
"displayNameEvent": "Reachability changed",
|
"displayNameEvent": "Status code changed",
|
||||||
"type": "bool",
|
"type": "int",
|
||||||
"defaultValue": false
|
"defaultValue": 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "69f32ec8-114d-43f4-9241-1f6a57261f32",
|
"id": "69f32ec8-114d-43f4-9241-1f6a57261f32",
|
||||||
@ -69,9 +69,9 @@
|
|||||||
{
|
{
|
||||||
"id": "05bf65f5-ff13-43e3-b6ae-77019e79d8a1",
|
"id": "05bf65f5-ff13-43e3-b6ae-77019e79d8a1",
|
||||||
"name": "httpPutCommander",
|
"name": "httpPutCommander",
|
||||||
"displayName": "HTTP put commander",
|
"displayName": "HTTP put",
|
||||||
"createMethods": ["user"],
|
"createMethods": ["user"],
|
||||||
"interfaces": ["connectable"],
|
"interfaces": [ ],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "1a3fcb23-931b-4ba1-b134-c49b656c76f7",
|
"id": "1a3fcb23-931b-4ba1-b134-c49b656c76f7",
|
||||||
@ -79,7 +79,7 @@
|
|||||||
"displayName": "Address",
|
"displayName": "Address",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"inputType": "None",
|
"inputType": "None",
|
||||||
"defaultValue": "https://nymea.io"
|
"defaultValue": "https://httpbin.org/put"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "db994349-1105-4ce5-b6fe-6fd38fbc436a",
|
"id": "db994349-1105-4ce5-b6fe-6fd38fbc436a",
|
||||||
@ -91,12 +91,12 @@
|
|||||||
],
|
],
|
||||||
"stateTypes": [
|
"stateTypes": [
|
||||||
{
|
{
|
||||||
"id": "d102ff86-b773-48e3-a7a5-e138cb541f49",
|
"id": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39",
|
||||||
"name": "connected",
|
"name": "status",
|
||||||
"displayName": "Reachable",
|
"displayName": "Status code",
|
||||||
"displayNameEvent": "Reachability changed",
|
"displayNameEvent": "Status code changed",
|
||||||
"type": "bool",
|
"type": "int",
|
||||||
"defaultValue": false
|
"defaultValue": 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "69f32ec8-114d-43f4-9241-1f6a57261f32",
|
"id": "69f32ec8-114d-43f4-9241-1f6a57261f32",
|
||||||
@ -129,7 +129,7 @@
|
|||||||
"name": "httpGetCommander",
|
"name": "httpGetCommander",
|
||||||
"displayName": "HTTP get",
|
"displayName": "HTTP get",
|
||||||
"createMethods": ["user"],
|
"createMethods": ["user"],
|
||||||
"interfaces": ["connectable"],
|
"interfaces": [ ],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "477b544b-b631-4526-a4ef-c712ff5f955d",
|
"id": "477b544b-b631-4526-a4ef-c712ff5f955d",
|
||||||
@ -137,7 +137,7 @@
|
|||||||
"displayName": "URL or IPv4 Address",
|
"displayName": "URL or IPv4 Address",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"inputType": "None",
|
"inputType": "None",
|
||||||
"defaultValue": "https://nymea.io"
|
"defaultValue": "https://httpbin.org/get"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "bee8b151-815a-4159-9d8a-42b76e99b42c",
|
"id": "bee8b151-815a-4159-9d8a-42b76e99b42c",
|
||||||
@ -149,12 +149,12 @@
|
|||||||
],
|
],
|
||||||
"stateTypes":[
|
"stateTypes":[
|
||||||
{
|
{
|
||||||
"id": "0d63f815-efd1-488a-9bfa-e9f6bda540d2",
|
"id": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39",
|
||||||
"name": "connected",
|
"name": "status",
|
||||||
"displayName": "Reachable",
|
"displayName": "Status code",
|
||||||
"displayNameEvent": "Reachability changed",
|
"displayNameEvent": "Status code changed",
|
||||||
"type": "bool",
|
"type": "int",
|
||||||
"defaultValue": false
|
"defaultValue": 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "d81f0644-b94e-48ed-ae48-1b8ff6cebc0c",
|
"id": "d81f0644-b94e-48ed-ae48-1b8ff6cebc0c",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user