Cute   Learning Hub


Interacting with Remote Objects

With Cute, developers perform server-side programming by exposing QObject-derived classes containing specially-tagged signals and slots.

With the Cute client SDKs, clients interact with remote objects as if they were local. The RemoteObject class does all the work on the client-side. This class creates the remote object on the server and enables clients to interact with it as if the remote object's signals and slots belonged to the RemoteObject class instead. Clients can also call remote slots directly through the RemoteObject class.

The RemoteObject class acts as a proxy to remote signals and slots. Thus, remote signal-slot connections are established in client code using the string-based SIGNAL and SLOT macros.

The Cute client SDK shares WebSocket connections among remote objects possessing the same connection settings (host, port, proxy, and SSL configuration). Nevertheless, clients can request exclusive WebSocket connections when instantiating remote objects.

Upon successfully establishing a connection to the remote object, the RemoteObject class emits the connected signal. Otherwise, if an error occurs, the error signal is emitted instead. Clients do not need to wait for the connected signal to call remote slots or establish remote signal-slot connections. The RemoteObject class queues all these requests and performs them after connecting to the server's remote object.

Clients should consider all queued remote slot calls and signal-slot connections as failed if the RemoteObject class emits the error signal. In this case, clients should redo the connections and remote slot calls on a newly created RemoteObject instance.

Consider the Calculator class shown in the exposing remote objects section. The Calculator class is defined as follows:

#include <QObject>
// Include Cute Server SDK header
#include <CuteServer.h>

class Calculator : public QObject
{
    Q_OBJECT

public:
    Calculator(QSharedPointer<Cute::Server::IConnectionInformation> connInfo) {Q_UNUSED(connInfo);}

public slots:
    // tag the slot with the REMOTE_SLOT macro
    REMOTE_SLOT qint32 addIntegers(qint32 a, qint32 b) {return a+b;}
};

The Calculator class is registered with the Cute server as follows:

#include "Calculator.h"

// Map the class to an endpoint
REGISTER_REMOTE_OBJECT("/calculator", Calculator);

Suppose that the Cute server listens to port 8080 on all network interfaces (see Installing Server and Configuring Server). If example.com points to the server's public IP address, clients can establish a connection to instances of the Calculator class and call its remote slot directly as follows:

#include <QObject>
#include <QVariant>
#include <QSharedPointer>
// include the Cute Client SDK
#include <CuteClient.h>

using namespace Cute::Client;

class CalculatorClient : public QObject
{
    Q_OBJECT

public:
    CalculatorClient();

public slots:
    void onResponded(QVariant response)
    {
        qWarning("%s", qUtf8Printable(QString("%1 + %2 = %3").arg(a).arg(b).arg(response.value<qint32>())));
    }

private:
    const qint32 a = 3;
    const qint32 b = 5;
    RemoteObject remoteObject;
    QSharedPointer<IRemoteSlotResponse> slotResponse;
};

CalculatorClient::CalculatorClient() : remoteObject("Calculator", QUrl("cute://example.com:8080/calculator"))
{
    slotResponse = remoteObject.callRemoteSlot("addIntegers", a, b);
    QObject::connect(slotResponse.data(), &IRemoteSlotResponse::responded, this, &CalculatorClient::onResponded);
}

cute is the URL scheme used when interacting with remote objects on unencrypted connections, and, for encrypted connections, cutes should be used instead (for example, cutes://example.com:8443/an_endpoint). After creating the RemoteObject instance, it is possible to perform connections to remote signals and slots by using the RemoteObject::connect method, as shown below:

#include <QObject>
#include <CuteClient.h>
using Cute::Client::RemoteObject;

class CalculatorClient : public QObject
{
Q_OBJECT
public:
    CalculatorClient() : remoteObject("Calculator", QUrl("cutes://example.com:8080/calculator"))
    {
        RemoteObject::connect(this, SIGNAL(addIntegersRequested(qint32,qint32)),
        &remoteObject, SLOT(addIntegers(qint32,qint32)));
    }

signals:
    void addIntegersRequested(qint32 a, qint32 b);

private:
    RemoteObject remoteObject;
}