Add more flexible createChannel API to the MQTT provider resource

This commit is contained in:
Michael Zanetti 2021-05-28 14:14:11 +02:00
parent be68d925be
commit f8f2cf8fc2
5 changed files with 77 additions and 3 deletions

View File

@ -47,17 +47,41 @@ MqttProviderImplementation::MqttProviderImplementation(MqttBroker *broker, QObje
connect(broker, &MqttBroker::publishReceived, this, &MqttProviderImplementation::onPublishReceived);
}
MqttChannel *MqttProviderImplementation::createChannel(const QHostAddress &clientAddress, const QStringList &topicPrefixList)
{
QString clientId;
// Generate a clientId that hasn't been used yet.
do {
clientId = QUuid::createUuid().toString().remove(QRegExp("[{}-]")).left(16);
} while (m_createdChannels.contains(clientId));
return createChannel(clientId, clientAddress, topicPrefixList);
}
MqttChannel *MqttProviderImplementation::createChannel(const QString &clientId, const QHostAddress &clientAddress, const QStringList &topicPrefixList)
{
QString username = QUuid::createUuid().toString().remove(QRegExp("[{}-]")).left(16);
QString password = QUuid::createUuid().toString().remove(QRegExp("[{}-]")).left(16);
return createChannel(clientId, username, password, clientAddress, topicPrefixList);
}
MqttChannel *MqttProviderImplementation::createChannel(const QString &clientId, const QString &username, const QString &password, const QHostAddress &clientAddress, const QStringList &topicPrefixList)
{
if (m_broker->configurations().isEmpty()) {
qCWarning(dcMqtt) << "MQTT broker not running. Cannot create a channel for thing" << clientId;
return nullptr;
}
if (m_createdChannels.contains(clientId)) {
qCWarning(dcMqtt()) << "ClientId" << clientId << "already in use. Cannot create channel.";
return nullptr;
}
MqttChannelImplementation* channel = new MqttChannelImplementation();
channel->m_clientId = clientId;
channel->m_username = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
channel->m_password = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
channel->m_username = username;
channel->m_password = password;
if (!topicPrefixList.isEmpty()) {
channel->m_topicPrefixList = topicPrefixList;
} else {

View File

@ -44,7 +44,9 @@ class MqttProviderImplementation : public MqttProvider
public:
explicit MqttProviderImplementation(MqttBroker *broker, QObject *parent = nullptr);
MqttChannel* createChannel(const QHostAddress &clientAddress, const QStringList &topicPrefixList = QStringList()) override;
MqttChannel* createChannel(const QString &clientId, const QHostAddress &clientAddress, const QStringList &topicPrefixList = QStringList()) override;
MqttChannel* createChannel(const QString &clientId, const QString &username, const QString &password, const QHostAddress &clientAddress, const QStringList &topicPrefixList = QStringList()) override;
void releaseChannel(MqttChannel* channel) override;
MqttClient* createInternalClient(const QString &clientId) override;

View File

@ -154,15 +154,61 @@
\sa HardwareResource, HardwareManager::mqttProvider()
*/
/*! \fn MqttChannel *MqttProvider::createChannel(const QHostAddress &clientAddress, const QString &topicPrefix);
Creates a new MQTT channel on the internal broker. The returned channel will have the required details for the
client device to connect to the broker. A temporaray clientId/user/password combination will be created and
clients connecting to the broker with those credentials will have access to subscribe and post to # within the
given \a topicPrefixList.
The given \a clientAddress will be matched against available MQTT servers in the system and a proper server address
will be returned in the MqttChannel object. The client should be configured to connect to this server address.
\a topicPrefixList will be used to generate the policy for this MQTT client by appending "/#" to it. This will allow the
client to publish and subscribe to topics within "<topicPrefix>/#". See The MQTT specification on topic filters for more details.
It is good practice to isolate clients as much as possible the topics should be as restrictive as possible to avoid devices
snooping in on other things on the MQTT broker. If no topicPrefix is provided, a default of "<clientId>" Id is generated,
resulting in a policy of "<clientId>/#". At this point it is not allowed for plugins to publish/subscribe to # or $ topics.
\sa releaseChannel(MqttChannel *channel)
*/
/*! \fn MqttChannel *MqttProvider::createChannel(const QString &clientId, const QHostAddress &clientAddress, const QString &topicPrefix);
Creates a new MQTT channel on the internal broker. The returned channel will have the required details for the
client device to connect to the broker. A temporaray user/password combination will be created and
clients connecting to the broker with those credentials will have access to subscribe and post to # within the
given \a topicPrefixList.
\a clientId must be unique within the system or the channel creation will fail.
The given \a clientAddress will be matched against available MQTT servers in the system and a proper server address
will be returned in the MqttChannel object. The client should be configured to connect to this server address.
\a topicPrefixList will be used to generate the policy for this MQTT client by appending "/#" to it. This will allow the
client to publish and subscribe to topics within "<topicPrefix>/#". See The MQTT specification on topic filters for more details.
It is good practice to isolate clients as much as possible the topics should be as restrictive as possible to avoid devices
snooping in on other things on the MQTT broker. If no topicPrefix is provided, a default of "<clientId>" Id is generated,
resulting in a policy of "<clientId>/#". At this point it is not allowed for plugins to publish/subscribe to # or $ topics.
\sa releaseChannel(MqttChannel *channel)
*/
/*! \fn MqttChannel *MqttProvider::createChannel(const QString &clientId, const QString &username, const QString &password, const QHostAddress &clientAddress, const QString &topicPrefix);
Creates a new MQTT channel on the internal broker. The returned channel will have the required details for the
client device to connect to the broker. Clients connecting to the broker with those credentials will have access to
subscribe and post to # within the given \a topicPrefixList.
\a clientId must be unique within the system or the channel creation will fail. If a mqtt client allows to configure the
clientId, using it's deviceId is likely a good idea.
The given \a username and \a password will be used to create the policy for the client. Note: While it is technically
possible and allowed to use an empty user/password combination, a plugin developer should not do so unless the client
is not capable of providing login information. In most cases a plugin developer should use the overloaded method
that autogenerates a user and password combination instead. This method might be useful if a client cannot deal with
the auto generated credentials for whatever reason and a plugin requires to override them.
The given \a clientAddress will be matched against available MQTT servers in the system and a proper server address
will be returned in the MqttChannel object. The client should be configured to connect to this server address.
\a topicPrefixList will be used to generate the policy for this MQTT client by appending "/#" to it. This will allow the
client to publish and subscribe to topics within "<topicPrefix>/#". See The MQTT specification on topic filters for more details.
It is good practice to isolate clients as much as possible the topics should be as restrictive as possible to avoid devices

View File

@ -46,7 +46,9 @@ class MqttProvider : public HardwareResource
public:
explicit MqttProvider(QObject *parent = nullptr);
virtual MqttChannel* createChannel(const QHostAddress &clientAddress, const QStringList &topicPrefixList = QStringList()) = 0;
virtual MqttChannel* createChannel(const QString &clientId, const QHostAddress &clientAddress, const QStringList &topicPrefixList = QStringList()) = 0;
virtual MqttChannel* createChannel(const QString &clientId, const QString &username, const QString &password, const QHostAddress &clientAddress, const QStringList &topicPrefixList = QStringList()) = 0;
virtual void releaseChannel(MqttChannel *channel) = 0;
virtual MqttClient* createInternalClient(const QString &clientId) = 0;

View File

@ -8,7 +8,7 @@ JSON_PROTOCOL_VERSION_MAJOR=5
JSON_PROTOCOL_VERSION_MINOR=5
JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}"
LIBNYMEA_API_VERSION_MAJOR=7
LIBNYMEA_API_VERSION_MINOR=0
LIBNYMEA_API_VERSION_MINOR=1
LIBNYMEA_API_VERSION_PATCH=0
LIBNYMEA_API_VERSION="$${LIBNYMEA_API_VERSION_MAJOR}.$${LIBNYMEA_API_VERSION_MINOR}.$${LIBNYMEA_API_VERSION_PATCH}"