Cute provides an interaction model based on the signals and slots mechanism. On the server side, developers implement backend code by mapping classes containing specially-tagged signals and slots to endpoints. The Cute server fetches mapped classes from a user-specified shared library loaded during startup. Thus, developers have to compile all mapped classes into a shared library. In addition, the Cute client SDKs were designed such that clients interact with remote objects as if they were local.
The RemoteObject class is responsible for allowing clients to interact with remote objects on the server as if they were local. Instances of this class are responsible for creating the remote object on the server and enabling 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.
Remote objects are just instances of QObject-derived classes containing specially tagged signals and slots. Developers register these classes to the Cute server using the REGISTER_REMOTE_OBJECT macro. The REGISTER_REMOTE_OBJECT macro maps the registered classes to the given endpoint. The Cute server Business and Enterprise editions also support HTTP-based interaction.
Remote objects must have a single-argument constructor that receives an instance of a QSharedPointer<IConnectionInformation>. This instance gives connection-related information to remote object implementors.
The shared pointer to the IConnectionInformation passed when creating the remote object instance allows remote object implementors to fetch the session data provided when the client instantiated the RemoteObject, allowing clients to send authentication data to remote objects instantiated by the Cute server.
Tagging signals with the REMOTE_SIGNAL macro and slots with the REMOTE_SLOT macro set them as remote. Whenever a client connects to a valid endpoint, the Cute server creates an instance of the registered class, allowing clients to establish remote signal-slot connections. Clients can also call remote slots directly.
Minor modifications to QObject-derived classes are required to expose them, making them available for use as remote objects. The example below highlights how simple it is to modify a QObject-derived class to make it available for remote signal-slot interaction.
#include <QObject> class Calculator : public QObject { Q_OBJECT public slots: qint32 addIntegers(qint32 a, qint32 b) {return a+b;} };
The Calculator class is an ordinary, QObject-derived class with a public slot that adds two integers and returns their sum. Just two modifications are required to make the Calculator class available to clients on the network:
#include <QObject> // Include the Cute server SDK header #include <CuteServer.h> class Calculator : public QObject { Q_OBJECT public: Calculator(QSharedPointer<Cute::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;} };
And in a source file:
#include "Calculator.h" // Map the class to an endpoint REGISTER_REMOTE_OBJECT("/calculator", Calculator);
The REGISTER_REMOTE_OBJECT macro maps QObject-derived classes containing signals and slots tagged as remote to endpoints.
The Cute server uses WebSocket connections to perform interactions with remote objects. Cute shares WebSocket connections among remote objects according to host, port, proxy, and SSL configurations. However, the RemoteObject class allows clients to use an exclusive WebSocket connection for the remote object.
See interacting with Remote Objects for examples of how clients interact with remote objects.
The Cute server Business and Enterprise editions allow HTTP-based interaction by parsing HTTP requests and dispatching them to slots registered as HTTP handlers. Users tag slots with macros named after the HTTP verb they represent to set them as HTTP handlers. The Cute server supports the following HTTP verbs: DELETE, GET, PATCH, POST, and PUT.
Users can combine HTTP macros to inform that the slot can handle multiple HTTP request verbs. However, users cannot mix HTTP-based macros with the REMOTE_SLOT macro.
Below are the HTTP-based macros supported by the Cute server Business and Enterprise editions:
When registering a QObject-derived class containing HTTP handlers, Cute maps the HTTP handler to an absolute URL path made by the path set when registering the class with the subpath containing the HTTP handler slot name. Thus, for example, a class responsible for handling HTTP requests mapped to the /manage_items endpoint can be declared as follows:
#include <QObject> #include <CuteServer.h> class MyCrudClass : public QObject { Q_OBJECT public: MyCrudClass(QSharedPointer<Cute::IConnectionInformation> connInfo) {Q_UNUSED(connInfo);} public slots: // handle post and get requests in the same slot HTTP_POST HTTP_GET void postAndGetItem(QSharedPointer<Cute::Server::HttpBroker> httpBroker); // handle delete requests HTTP_DELETE void deleteItem(QSharedPointer<Cute::Server::HttpBroker> httpBroker); }
If the Cute server has a public IP pointed by example.com, then the Cute server will use the postAndGetItem slot to process all POST and GET HTTP requests targeting the http://example.com/manage_items/postAndGetItem endpoint. Also, the Cute server will use the deleteItem slot to handle every HTTP DELETE request targeting the http://example.com/manage_items/deleteItem endpoint.
It is important to observe that, unlike hostnames, URL paths are case-sensitive (see RFC 3986).
Remote object classes can have remote signals, slots, and HTTP handlers.
Whenever the Cute Server Business and Enterprise editions parse an HTTP request with a matching HTTP handler slot, the server creates an instance of the registered class containing the matching slot and calls the slot to handle the HTTP request.
The Cute server uses a broker to exchange the HTTP request/response with the HTTP handler to enable the remote object class to send the HTTP response later, after the HTTP handler slot returns. This allows the remote object class to send a request to a backend database and only send the HTTP response after the database responds.
When the remote object handling the HTTP request sends the HTTP response through the HttpBroker, the Cute server schedules the remote object for deletion by calling its deleteLater slot. If the HTTP response has the "Connection: close" header, the Cute Server closes the connection after sending the response to the client. Otherwise, the server keeps the connection open.
The Cute server creates a new remote object for each HTTP request received in the same connection.
The Cute server also supports pipelining. Thus, clients can send multiple requests before receiving any response from the server.
The Cute server processes all registered classes from a user-defined shared library loaded during startup. The Cute server Startup, Business, and Enterprise editions process the library with the file path given as the value of the remoteObjectsLib key in the configuration file.These libraries are shared libraries linked with the Cute server SDK. Thus, users must compile all classes containing remote signals and slots and HTTP handlers into a shared library.