summaryrefslogtreecommitdiffstats
path: root/src/BobinkClient.cpp
diff options
context:
space:
mode:
authorThomas Vanbesien <tvanbesi@proton.me>2026-02-19 22:31:16 +0100
committerThomas Vanbesien <tvanbesi@proton.me>2026-02-19 22:31:16 +0100
commit364430e417600c68133673254b58b4d35608777a (patch)
tree3b4e3471f19239780a2df23ced27c84de266bf95 /src/BobinkClient.cpp
parent5fe029fd127dd70079a01eb6dfbd347954bba9de (diff)
downloadBobinkQtOpcUa-364430e417600c68133673254b58b4d35608777a.tar.gz
BobinkQtOpcUa-364430e417600c68133673254b58b4d35608777a.zip
Reorganize BobinkClient by domain and make s_instance private
Group header and source by domain (Connection, Discovery, PKI) so properties, methods, and signal handlers live together. Move enums before constructor, move s_instance to private, and add a public instance() accessor used by BobinkNode.
Diffstat (limited to 'src/BobinkClient.cpp')
-rw-r--r--src/BobinkClient.cpp325
1 files changed, 161 insertions, 164 deletions
diff --git a/src/BobinkClient.cpp b/src/BobinkClient.cpp
index 01f9912..6d1c608 100644
--- a/src/BobinkClient.cpp
+++ b/src/BobinkClient.cpp
@@ -30,12 +30,33 @@ ensurePkiDirs (const QString &base)
}
}
+static QString
+securityPolicyUri (BobinkClient::SecurityPolicy policy)
+{
+ switch (policy)
+ {
+ case BobinkClient::Basic256Sha256:
+ return QStringLiteral (
+ "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
+ case BobinkClient::Aes128_Sha256_RsaOaep:
+ return QStringLiteral (
+ "http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
+ case BobinkClient::Aes256_Sha256_RsaPss:
+ return QStringLiteral (
+ "http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
+ }
+ return {};
+}
+
+/* ======================================
+ * Construction
+ * ====================================== */
+
BobinkClient::BobinkClient (QObject *parent)
: QObject (parent), m_provider (new QOpcUaProvider (this)),
m_pkiDir (defaultPkiDir ())
{
- // Singleton pattern: construct only once
- Q_ASSERT(!s_instance);
+ Q_ASSERT (!s_instance);
ensurePkiDirs (m_pkiDir);
setupClient ();
autoDetectPki ();
@@ -87,9 +108,15 @@ BobinkClient::setupClient ()
}
/* ======================================
- * Connection properties
+ * Connection
* ====================================== */
+BobinkClient *
+BobinkClient::instance ()
+{
+ return s_instance;
+}
+
bool
BobinkClient::connected () const
{
@@ -132,10 +159,6 @@ BobinkClient::opcuaClient () const
return m_client;
}
-/* ======================================
- * Connection methods
- * ====================================== */
-
void
BobinkClient::connectToServer ()
{
@@ -166,24 +189,6 @@ BobinkClient::connectToServer ()
m_client->requestEndpoints (url);
}
-static QString
-securityPolicyUri (BobinkClient::SecurityPolicy policy)
-{
- switch (policy)
- {
- case BobinkClient::Basic256Sha256:
- return QStringLiteral (
- "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
- case BobinkClient::Aes128_Sha256_RsaOaep:
- return QStringLiteral (
- "http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
- case BobinkClient::Aes256_Sha256_RsaPss:
- return QStringLiteral (
- "http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
- }
- return {};
-}
-
void
BobinkClient::connectDirect (SecurityPolicy policy, SecurityMode mode)
{
@@ -263,8 +268,77 @@ BobinkClient::rejectCertificate ()
m_certLoop->quit ();
}
+void
+BobinkClient::handleStateChanged (QOpcUaClient::ClientState state)
+{
+ bool nowConnected = (state == QOpcUaClient::Connected);
+ if (m_connected != nowConnected)
+ {
+ m_connected = nowConnected;
+ emit connectedChanged ();
+ }
+}
+
+void
+BobinkClient::handleEndpointsReceived (
+ const QList<QOpcUaEndpointDescription> &endpoints,
+ QOpcUa::UaStatusCode statusCode, const QUrl &)
+{
+ if (statusCode != QOpcUa::Good || endpoints.isEmpty ())
+ {
+ emit connectionError (QStringLiteral ("Failed to retrieve endpoints"));
+ return;
+ }
+
+ QOpcUaEndpointDescription best = endpoints.first ();
+ for (const auto &ep : endpoints)
+ {
+ if (ep.securityLevel () > best.securityLevel ())
+ best = ep;
+ }
+
+ if (m_auth)
+ m_client->setAuthenticationInformation (
+ m_auth->toAuthenticationInformation ());
+
+ m_client->connectToEndpoint (best);
+}
+
+void
+BobinkClient::handleConnectError (QOpcUaErrorState *errorState)
+{
+ if (errorState->connectionStep ()
+ == QOpcUaErrorState::ConnectionStep::CertificateValidation)
+ {
+ // connectError uses BlockingQueuedConnection — the backend thread is
+ // blocked waiting for us to return. The errorState pointer is stack-
+ // allocated in the backend, so it is only valid during this call.
+ // Spin a local event loop so QML can show a dialog and call
+ // acceptCertificate() / rejectCertificate() while we stay in scope.
+ m_certAccepted = false;
+ emit certificateTrustRequested (
+ QStringLiteral ("The server certificate is not trusted. Accept?"));
+
+ QEventLoop loop;
+ m_certLoop = &loop;
+ QTimer::singleShot (30000, &loop, &QEventLoop::quit);
+ loop.exec ();
+ m_certLoop = nullptr;
+
+ errorState->setIgnoreError (m_certAccepted);
+ }
+ else
+ {
+ emit connectionError (
+ QStringLiteral ("Connection error at step %1, code 0x%2")
+ .arg (static_cast<int> (errorState->connectionStep ()))
+ .arg (static_cast<quint32> (errorState->errorCode ()), 8, 16,
+ QLatin1Char ('0')));
+ }
+}
+
/* ======================================
- * Discovery properties
+ * Discovery
* ====================================== */
QString
@@ -300,6 +374,67 @@ BobinkClient::servers () const
return m_serversCache;
}
+void
+BobinkClient::startDiscovery ()
+{
+ if (m_discoveryUrl.isEmpty () || !m_client)
+ return;
+
+ doDiscovery ();
+ m_discoveryTimer.start (m_discoveryInterval);
+
+ if (!m_discovering)
+ {
+ m_discovering = true;
+ emit discoveringChanged ();
+ }
+}
+
+void
+BobinkClient::stopDiscovery ()
+{
+ m_discoveryTimer.stop ();
+
+ if (m_discovering)
+ {
+ m_discovering = false;
+ emit discoveringChanged ();
+ }
+}
+
+void
+BobinkClient::doDiscovery ()
+{
+ if (!m_client || m_discoveryUrl.isEmpty ())
+ return;
+ QUrl url (m_discoveryUrl);
+ if (!url.isValid ())
+ return;
+ m_client->findServers (url);
+}
+
+void
+BobinkClient::handleFindServersFinished (
+ const QList<QOpcUaApplicationDescription> &servers,
+ QOpcUa::UaStatusCode statusCode, const QUrl &)
+{
+ if (statusCode != QOpcUa::Good)
+ return;
+
+ m_discoveredServers = servers;
+ m_serversCache.clear ();
+ for (const auto &s : m_discoveredServers)
+ {
+ QVariantMap entry;
+ entry[QStringLiteral ("serverName")] = s.applicationName ().text ();
+ entry[QStringLiteral ("applicationUri")] = s.applicationUri ();
+ entry[QStringLiteral ("discoveryUrls")]
+ = QVariant::fromValue (s.discoveryUrls ());
+ m_serversCache.append (entry);
+ }
+ emit serversChanged ();
+}
+
/* ======================================
* PKI
* ====================================== */
@@ -434,141 +569,3 @@ BobinkClient::applyPki ()
QStringLiteral ("PKI applied (no client certificate)"));
}
}
-
-/* ======================================
- * Discovery methods
- * ====================================== */
-
-void
-BobinkClient::startDiscovery ()
-{
- if (m_discoveryUrl.isEmpty () || !m_client)
- return;
-
- doDiscovery ();
- m_discoveryTimer.start (m_discoveryInterval);
-
- if (!m_discovering)
- {
- m_discovering = true;
- emit discoveringChanged ();
- }
-}
-
-void
-BobinkClient::stopDiscovery ()
-{
- m_discoveryTimer.stop ();
-
- if (m_discovering)
- {
- m_discovering = false;
- emit discoveringChanged ();
- }
-}
-
-void
-BobinkClient::doDiscovery ()
-{
- if (!m_client || m_discoveryUrl.isEmpty ())
- return;
- QUrl url (m_discoveryUrl);
- if (!url.isValid ())
- return;
- m_client->findServers (url);
-}
-
-/* ======================================
- * Private slots
- * ====================================== */
-
-void
-BobinkClient::handleStateChanged (QOpcUaClient::ClientState state)
-{
- bool nowConnected = (state == QOpcUaClient::Connected);
- if (m_connected != nowConnected)
- {
- m_connected = nowConnected;
- emit connectedChanged ();
- }
-}
-
-void
-BobinkClient::handleEndpointsReceived (
- const QList<QOpcUaEndpointDescription> &endpoints,
- QOpcUa::UaStatusCode statusCode, const QUrl &)
-{
- if (statusCode != QOpcUa::Good || endpoints.isEmpty ())
- {
- emit connectionError (QStringLiteral ("Failed to retrieve endpoints"));
- return;
- }
-
- QOpcUaEndpointDescription best = endpoints.first ();
- for (const auto &ep : endpoints)
- {
- if (ep.securityLevel () > best.securityLevel ())
- best = ep;
- }
-
- if (m_auth)
- m_client->setAuthenticationInformation (
- m_auth->toAuthenticationInformation ());
-
- m_client->connectToEndpoint (best);
-}
-
-void
-BobinkClient::handleConnectError (QOpcUaErrorState *errorState)
-{
- if (errorState->connectionStep ()
- == QOpcUaErrorState::ConnectionStep::CertificateValidation)
- {
- // connectError uses BlockingQueuedConnection — the backend thread is
- // blocked waiting for us to return. The errorState pointer is stack-
- // allocated in the backend, so it is only valid during this call.
- // Spin a local event loop so QML can show a dialog and call
- // acceptCertificate() / rejectCertificate() while we stay in scope.
- m_certAccepted = false;
- emit certificateTrustRequested (
- QStringLiteral ("The server certificate is not trusted. Accept?"));
-
- QEventLoop loop;
- m_certLoop = &loop;
- QTimer::singleShot (30000, &loop, &QEventLoop::quit);
- loop.exec ();
- m_certLoop = nullptr;
-
- errorState->setIgnoreError (m_certAccepted);
- }
- else
- {
- emit connectionError (
- QStringLiteral ("Connection error at step %1, code 0x%2")
- .arg (static_cast<int> (errorState->connectionStep ()))
- .arg (static_cast<quint32> (errorState->errorCode ()), 8, 16,
- QLatin1Char ('0')));
- }
-}
-
-void
-BobinkClient::handleFindServersFinished (
- const QList<QOpcUaApplicationDescription> &servers,
- QOpcUa::UaStatusCode statusCode, const QUrl &)
-{
- if (statusCode != QOpcUa::Good)
- return;
-
- m_discoveredServers = servers;
- m_serversCache.clear ();
- for (const auto &s : m_discoveredServers)
- {
- QVariantMap entry;
- entry[QStringLiteral ("serverName")] = s.applicationName ().text ();
- entry[QStringLiteral ("applicationUri")] = s.applicationUri ();
- entry[QStringLiteral ("discoveryUrls")]
- = QVariant::fromValue (s.discoveryUrls ());
- m_serversCache.append (entry);
- }
- emit serversChanged ();
-}