Update MQTT api a bit to be more flexible
This commit is contained in:
parent
6aa624c261
commit
b5919a534d
@ -52,9 +52,9 @@ quint16 MqttChannelImplementation::serverPort() const
|
|||||||
return m_serverPort;
|
return m_serverPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MqttChannelImplementation::topicPrefix() const
|
QStringList MqttChannelImplementation::topicPrefixList() const
|
||||||
{
|
{
|
||||||
return m_topicPrefix;
|
return m_topicPrefixList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttChannelImplementation::publish(const QString &topic, const QByteArray &payload)
|
void MqttChannelImplementation::publish(const QString &topic, const QByteArray &payload)
|
||||||
|
|||||||
@ -36,7 +36,7 @@ public:
|
|||||||
QString password() const override;
|
QString password() const override;
|
||||||
QHostAddress serverAddress() const override;
|
QHostAddress serverAddress() const override;
|
||||||
quint16 serverPort() const override;
|
quint16 serverPort() const override;
|
||||||
QString topicPrefix() const override;
|
QStringList topicPrefixList() const override;
|
||||||
|
|
||||||
void publish(const QString &topic, const QByteArray &payload) override;
|
void publish(const QString &topic, const QByteArray &payload) override;
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ private:
|
|||||||
QString m_password;
|
QString m_password;
|
||||||
QHostAddress m_serverAddress;
|
QHostAddress m_serverAddress;
|
||||||
quint16 m_serverPort;
|
quint16 m_serverPort;
|
||||||
QString m_topicPrefix;
|
QStringList m_topicPrefixList;
|
||||||
|
|
||||||
friend class MqttProviderImplementation;
|
friend class MqttProviderImplementation;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -37,18 +37,23 @@ MqttProviderImplementation::MqttProviderImplementation(MqttBroker *broker, QObje
|
|||||||
connect(broker, &MqttBroker::publishReceived, this, &MqttProviderImplementation::onPublishReceived);
|
connect(broker, &MqttBroker::publishReceived, this, &MqttProviderImplementation::onPublishReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttChannel *MqttProviderImplementation::createChannel(const DeviceId &deviceId, const QHostAddress &clientAddress)
|
MqttChannel *MqttProviderImplementation::createChannel(const QString &clientId, const QHostAddress &clientAddress, const QStringList &topicPrefixList)
|
||||||
{
|
{
|
||||||
if (m_broker->configurations().isEmpty()) {
|
if (m_broker->configurations().isEmpty()) {
|
||||||
qCWarning(dcMqtt) << "MQTT broker not running. Cannot create a channel for device" << deviceId;
|
qCWarning(dcMqtt) << "MQTT broker not running. Cannot create a channel for device" << clientId;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttChannelImplementation* channel = new MqttChannelImplementation();
|
MqttChannelImplementation* channel = new MqttChannelImplementation();
|
||||||
channel->m_clientId = deviceId.toString().remove(QRegExp("[{}-]"));
|
channel->m_clientId = clientId;
|
||||||
channel->m_username = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
channel->m_username = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
||||||
channel->m_password = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
channel->m_password = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
||||||
channel->m_topicPrefix = channel->m_clientId;
|
if (!topicPrefixList.isEmpty()) {
|
||||||
|
channel->m_topicPrefixList = topicPrefixList;
|
||||||
|
} else {
|
||||||
|
QString defaultTopicPrefix = channel->m_clientId;
|
||||||
|
channel->m_topicPrefixList.append(defaultTopicPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
||||||
@ -80,8 +85,10 @@ MqttChannel *MqttProviderImplementation::createChannel(const DeviceId &deviceId,
|
|||||||
policy.clientId = channel->clientId();
|
policy.clientId = channel->clientId();
|
||||||
policy.username = channel->username();
|
policy.username = channel->username();
|
||||||
policy.password = channel->password();
|
policy.password = channel->password();
|
||||||
policy.allowedPublishTopicFilters.append(QString("%1/#").arg(channel->m_topicPrefix));
|
foreach (const QString &topicPrefix, channel->m_topicPrefixList) {
|
||||||
policy.allowedSubscribeTopicFilters.append(QString("%1/#").arg(channel->m_topicPrefix));
|
policy.allowedPublishTopicFilters.append(QString("%1/#").arg(topicPrefix));
|
||||||
|
policy.allowedSubscribeTopicFilters.append(QString("%1/#").arg(topicPrefix));
|
||||||
|
}
|
||||||
m_broker->updatePolicy(policy);
|
m_broker->updatePolicy(policy);
|
||||||
|
|
||||||
return channel;
|
return channel;
|
||||||
@ -99,7 +106,7 @@ void MqttProviderImplementation::releaseChannel(MqttChannel *channel)
|
|||||||
delete channel;
|
delete channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttClient *MqttProviderImplementation::createInternalClient(const DeviceId &deviceId)
|
MqttClient *MqttProviderImplementation::createInternalClient(const QString &clientId)
|
||||||
{
|
{
|
||||||
|
|
||||||
ServerConfiguration preferredConfig;
|
ServerConfiguration preferredConfig;
|
||||||
@ -117,7 +124,6 @@ MqttClient *MqttProviderImplementation::createInternalClient(const DeviceId &dev
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString clientId = deviceId.toString().remove(QRegExp("[{}-]"));
|
|
||||||
MqttPolicy policy;
|
MqttPolicy policy;
|
||||||
policy.clientId = clientId;
|
policy.clientId = clientId;
|
||||||
policy.username = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
policy.username = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
||||||
@ -189,9 +195,16 @@ void MqttProviderImplementation::onPublishReceived(const QString &clientId, cons
|
|||||||
void MqttProviderImplementation::onPluginPublished(const QString &topic, const QByteArray &payload)
|
void MqttProviderImplementation::onPluginPublished(const QString &topic, const QByteArray &payload)
|
||||||
{
|
{
|
||||||
MqttChannelImplementation *channel = static_cast<MqttChannelImplementation*>(sender());
|
MqttChannelImplementation *channel = static_cast<MqttChannelImplementation*>(sender());
|
||||||
if (!topic.startsWith(channel->topicPrefix())) {
|
bool found = false;
|
||||||
|
foreach (const QString &topicPrefix, channel->topicPrefixList()) {
|
||||||
|
if (topicPrefix.startsWith(topicPrefix)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
qCWarning(dcMqtt) << "Attempt to publish to MQTT channel for client" << channel->clientId() << "but topic is not within allowed topic prefix. Discarding message.";
|
qCWarning(dcMqtt) << "Attempt to publish to MQTT channel for client" << channel->clientId() << "but topic is not within allowed topic prefix. Discarding message.";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
m_broker->publish(topic, payload);
|
m_broker->publish(topic, payload);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,10 +34,10 @@ class MqttProviderImplementation : public MqttProvider
|
|||||||
public:
|
public:
|
||||||
explicit MqttProviderImplementation(MqttBroker *broker, QObject *parent = nullptr);
|
explicit MqttProviderImplementation(MqttBroker *broker, QObject *parent = nullptr);
|
||||||
|
|
||||||
MqttChannel* createChannel(const DeviceId &deviceId, const QHostAddress &clientAddress) override;
|
MqttChannel* createChannel(const QString &clientId, const QHostAddress &clientAddress, const QStringList &topicPrefixList = QStringList()) override;
|
||||||
void releaseChannel(MqttChannel* channel) override;
|
void releaseChannel(MqttChannel* channel) override;
|
||||||
|
|
||||||
MqttClient* createInternalClient(const DeviceId &deviceId) override;
|
MqttClient* createInternalClient(const QString &clientId) override;
|
||||||
|
|
||||||
bool available() const override;
|
bool available() const override;
|
||||||
bool enabled() const override;
|
bool enabled() const override;
|
||||||
|
|||||||
@ -38,7 +38,7 @@ public:
|
|||||||
virtual QString password() const = 0;
|
virtual QString password() const = 0;
|
||||||
virtual QHostAddress serverAddress() const = 0;
|
virtual QHostAddress serverAddress() const = 0;
|
||||||
virtual quint16 serverPort() const = 0;
|
virtual quint16 serverPort() const = 0;
|
||||||
virtual QString topicPrefix() const = 0;
|
virtual QStringList topicPrefixList() const = 0;
|
||||||
|
|
||||||
virtual void publish(const QString &topic, const QByteArray &payload) = 0;
|
virtual void publish(const QString &topic, const QByteArray &payload) = 0;
|
||||||
|
|
||||||
|
|||||||
@ -146,11 +146,20 @@
|
|||||||
\sa HardwareResource, HardwareManager::mqttProvider()
|
\sa HardwareResource, HardwareManager::mqttProvider()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \fn MqttChannel *MqttProvider::createChannel(const DeviceId &deviceId, const QHostAddress &clientAddress);
|
/*! \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
|
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
|
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
|
clients connecting to the broker with those credentials will have access to subscribe and post to # within the
|
||||||
given topic prefix.
|
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.
|
||||||
|
|
||||||
|
\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)
|
\sa releaseChannel(MqttChannel *channel)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -38,10 +38,10 @@ class MqttProvider : public HardwareResource
|
|||||||
public:
|
public:
|
||||||
explicit MqttProvider(QObject *parent = nullptr);
|
explicit MqttProvider(QObject *parent = nullptr);
|
||||||
|
|
||||||
virtual MqttChannel* createChannel(const DeviceId &deviceId, const QHostAddress &clientAddress) = 0;
|
virtual MqttChannel* createChannel(const QString &clientId, const QHostAddress &clientAddress, const QStringList &topicPrefixList = QStringList()) = 0;
|
||||||
virtual void releaseChannel(MqttChannel *channel) = 0;
|
virtual void releaseChannel(MqttChannel *channel) = 0;
|
||||||
|
|
||||||
virtual MqttClient* createInternalClient(const DeviceId &deviceId) = 0;
|
virtual MqttClient* createInternalClient(const QString &clientId) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MQTTPROVIDER_H
|
#endif // MQTTPROVIDER_H
|
||||||
|
|||||||
Reference in New Issue
Block a user