Skip to content
Start free evaluation

pdcomm::opcua::qt_client_worker

Class

One-shot QThread that owns a native OPC UA client.

class qt_client_worker final : public QThread

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

run() connects, activates the session (anonymously or with the user name), emits ready(), then sends submitted requests in order, polls and emits completed() for each response. It ends after request_stop() or a fatal error and always emits stopped() last. A worker runs once; starting it again reports "restart-rejected".

Rules for the application:

  • Own the object until wait() returns; never destroy it from its own thread.
  • Connect every signal with a receiver context object and Qt::QueuedConnection, so handlers run in the receiver's thread and Qt disconnects them when the receiver dies. Never check a QPointer and then call a raw receiver pointer from another thread.
  • submit() and request_stop() are thread-safe. Every other member function belongs to the owner thread.

Failures follow the C ABI status of the native call:

  • Request failures end only their request, and the worker keeps serving the others: client::begin() rejects it with #PDCOMM_OPCUA_INVALID_INPUT or #PDCOMM_OPCUA_LIMIT (phase "begin"), or client::take() completes it with #PDCOMM_OPCUA_RUNTIME_ERROR because the server aborted the response or the response was invalid (phase "response"). They count as completed.
  • A full handle registry is not a failure: client::take() reports #PDCOMM_OPCUA_LIMIT and the native client keeps the response. The worker then retries only that take, because every other client call returns #PDCOMM_OPCUA_BUSY meanwhile, and delivers the response once the application releases responses. If the registry stays full for timeout_ms, the worker ends with #PDCOMM_OPCUA_LIMIT.
  • Every other native error ends the worker: connect, activation, poll (a lost connection, a request timeout, a security failure), close, and any other begin or take status, such as #PDCOMM_OPCUA_CLOSED after an invalid response closed the connection. The worker emits a "worker" failure, fails the remaining requests with phase "abort" and stops with reason "native-error".

From examples/opcua/qt/opcua_qt_client.cpp:

qt_client_configuration configuration;
configuration.endpoint = arguments[1].toUtf8();
configuration.anonymous = true;
// ... load certificate_der, private_key_pem and trusted_server_der
QObject receiver;  // Stable receiver context for every queued connection.
auto worker = std::make_unique<qt_client_worker>(configuration);
// The worker copied the configuration; wipe the caller copy of the key.
configuration.private_key_pem.fill('\0');
configuration.private_key_pem.clear();
QObject::connect(worker.get(), &qt_client_worker::ready, &receiver, [&](quintptr) {
  uint8_t request[256];
  const auto size = ua_encode_read(request, sizeof(request), 2, node);
  const auto status = worker->submit(QByteArray(reinterpret_cast<const char*>(request),
                                                static_cast<qsizetype>(size)), 1);
  if (status != PDCOMM_OPCUA_OK) {
    std::fprintf(stderr, "Error: submit rejected (SDK status %d)\n", static_cast<int>(status));
    worker->request_stop(qt_client_stop::abort);
  }
}, Qt::QueuedConnection);
QObject::connect(worker.get(), &qt_client_worker::completed, &receiver,
                 [&](qt_client_response_ptr response) {
  const auto body = response->value->copy();
  // ... decode the ReadResponse
  worker->request_stop(qt_client_stop::drain);
}, Qt::QueuedConnection);
QObject::connect(worker.get(), &qt_client_worker::failed, &receiver, [&](qt_client_failure failure) {
  std::fprintf(stderr, "Error: %s failed (SDK status %d): %s\n", failure.phase.toUtf8().constData(),
               static_cast<int>(failure.status), failure.text.toUtf8().constData());
  result = 3;
  worker->request_stop(qt_client_stop::abort);
}, Qt::QueuedConnection);
QObject::connect(worker.get(), &qt_client_worker::stopped, &receiver, [&](qt_client_terminal terminal) {
  std::printf("Worker stopped orderly=%s\n", terminal.orderly ? "true" : "false");
  std::fflush(stdout);
  application.quit();
}, Qt::QueuedConnection);
worker->start();
application.exec();
worker->wait();
worker.reset();

Members

completed

Event

A validated response arrived; the request has ended.

void completed(pdcomm::opcua::qt_client_response_ptr result)

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

Parameters

NameDescription
resultShared response with its correlation and metadata.

failed

Event

A request or the worker failed; see qt_client_failure.

void failed(pdcomm::opcua::qt_client_failure failure)

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

Parameters

NameDescription
failureCorrelation (0 for the worker), status, phase and text.

maximum_commands

Field

Maximum number of admitted requests that are queued or in flight.

static constexpr size_t maximum_commands = 64

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

maximum_queued_bytes

Field

Maximum size of one request and of all queued, unsent requests together (4 MiB).

static constexpr size_t maximum_queued_bytes = 4 * 1024 * 1024

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

operator=

Method

Copy assignment is disabled.

qt_client_worker& operator=(const qt_client_worker&) = delete

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

pending

Event

A request was sent to the server.

void pending(quint64 correlation, quint32 native_request_id)

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

Parameters

NameDescription
correlationApplication correlation of the request.
native_request_idNative request ID (the requestHandle).

qt_client_worker

Constructor

Copying is disabled.

qt_client_worker(const qt_client_worker&) = delete

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

qt_client_worker

Constructor

Creates a worker; start() begins the connection.

explicit qt_client_worker(qt_client_configuration configuration, QObject* parent = nullptr)

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

Parameters

NameDescription
configurationSettings; every member is copied into new allocations, including fromRawData arrays and secrets.
parentOptional QObject parent.

Notes

  • Throws error: with #PDCOMM_OPCUA_LIMIT if the endpoint, application URI or user name exceeds 4096 bytes, a certificate or key exceeds 64 KiB, or the user secret exceeds 16 KiB.

ready

Event

The session is activated and requests are being sent.

void ready(quintptr native_owner_thread)

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

Parameters

NameDescription
native_owner_threadQThread::currentThreadId() of the worker thread that owns the native client.

request_stop

Method

Asks the worker to stop; thread-safe.

void request_stop(qt_client_stop mode = qt_client_stop::drain)

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

Later submit() calls return #PDCOMM_OPCUA_CLOSED. With qt_client_stop::drain the worker completes every admitted request, then sends CloseSession and closes the channel. With qt_client_stop::abort it releases the client in its own thread without a protocol close and fails the remaining requests with phase "abort". An abort request is never downgraded to a drain. QThread::requestInterruption() also selects abort.

The worker checks the request between native calls; a blocking connect, activation, close or DNS lookup is not interrupted.

Parameters

NameDescription
modeqt_client_stop::drain (default) or qt_client_stop::abort.

stopped

Event

The worker has ended; always the last signal of a run.

void stopped(pdcomm::opcua::qt_client_terminal terminal)

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

Parameters

NameDescription
terminalFinal counters and reason.

submit

Method

Queues one UA Binary service request; thread-safe.

int32_t submit(const QByteArray& request, quint64 correlation)

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

Only copies the request: no native call runs in the calling thread, and the native last error text is not changed. Requests submitted before ready() are sent after activation, in submission order. An admitted request gets exactly one completed() or failed() signal once the worker runs. The correlation stays reserved until that signal.

Parameters

NameDescription
requestComplete encoded request, as for client::begin(); copied.
correlationNon-zero application ID, unique among the requests that have not ended yet.

Returns

Admission status, not an OPC UA StatusCode: #PDCOMM_OPCUA_OK; #PDCOMM_OPCUA_INVALID_INPUT for an empty request or correlation 0; #PDCOMM_OPCUA_BUSY for a correlation in use; #PDCOMM_OPCUA_LIMIT when the request exceeds 4 MiB or would exceed maximum_commands or maximum_queued_bytes; #PDCOMM_OPCUA_CLOSED after request_stop() or the end of the worker.

~qt_client_worker

Method

Requests an abort, waits for the thread and wipes the credentials.

~qt_client_worker() override

Declared in: #include <pdcomm/opcua/pdcomm_opcua_qt.hpp>

The wait is cooperative: a blocking connect, activation, close or DNS lookup finishes first, bounded by timeout_ms and the operating system. Destroying the worker from its own thread is a fatal error.