File indexing completed on 2024-05-12 16:25:38

0001 /*
0002 
0003  * SPDX-FileCopyrightText: 2016 Riccardo Iaconelli <riccardo@kde.org>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  *
0007  */
0008 
0009 #pragma once
0010 
0011 #include "libruqolacore_export.h"
0012 #include "rocketchatmessage.h"
0013 #include "room.h"
0014 #include <QAbstractSocket>
0015 #include <QQueue>
0016 #include <QSslError>
0017 #include <functional>
0018 
0019 class QJsonObject;
0020 class QJsonDocument;
0021 class RocketChatMessage;
0022 class AbstractWebSocket;
0023 class RocketChatAccount;
0024 class DDPAuthenticationManager;
0025 class DDPManager;
0026 class LIBRUQOLACORE_EXPORT DDPClient : public QObject
0027 {
0028     Q_OBJECT
0029 public:
0030     enum MessageType {
0031         Persistent,
0032         Ephemeral,
0033     };
0034 
0035     explicit DDPClient(RocketChatAccount *account = nullptr, QObject *parent = nullptr);
0036     ~DDPClient() override;
0037 
0038     /**
0039      * @brief Call a method with name @param method and parameters @param params and @param messageType with an empty callback
0040      *
0041      * @param method The name of the method to call Rocket.Chat API for
0042      * @param params The parameters
0043      * @param messageType The type of message
0044      * @return unsigned int, the ID of the called method
0045      */
0046     quint64 method(const QString &method, const QJsonDocument &params, DDPClient::MessageType messageType = DDPClient::Ephemeral);
0047 
0048     /**
0049      * @brief Send message over network
0050      *
0051      * @param method The name of the method to call Rocket.Chat API for
0052      * @param params The parameters
0053      * @param callback The pointer to callback function
0054      * @param messageType The type of message
0055      * @return unsigned int, the ID of the called method
0056      */
0057     quint64 method(const QString &method,
0058                    const QJsonDocument &params,
0059                    const std::function<void(QJsonObject, RocketChatAccount *)> &callback,
0060                    DDPClient::MessageType messageType = DDPClient::Ephemeral);
0061 
0062     quint64 method(const RocketChatMessage::RocketChatMessageResult &result,
0063                    const std::function<void(QJsonObject, RocketChatAccount *)> &callback,
0064                    DDPClient::MessageType messageType = DDPClient::Ephemeral);
0065 
0066     /**
0067      * @brief Subscribes to a collection with name @param collection and parameters @param params
0068      *
0069      * @param collection The name of the collection
0070      * @param params The parameters
0071      */
0072     quint64 subscribe(const QString &collection, const QJsonArray &params);
0073 
0074     /**
0075      * @brief Registers a @class DDPManager object to an event, represented by
0076      *   a (collection name, event name) pair.
0077      *
0078      * @param collection the name of the collection to which the event belongs
0079      * @param event the name of the event to which subsribe the @class DDPManager object
0080      * @param ddpManager the @class DDPManager instance that will process event messages
0081      * @param subscriptionId a manager specific id that helps the manager keep track of
0082      *   the subscription
0083      */
0084     void registerSubscriber(const QString &collection, const QString &event, DDPManager *ddpManager, int subscriptionId);
0085 
0086     /**
0087      * @brief Deregisters a @class DDPManager object to from a given event, represented by
0088      *   a (collection name, event name) pair.
0089      *
0090      *   The (collection, event) pair should be enough to deregister the subscribed manager,
0091      *   but the extra parameters are helpful to debug if subscription/unsubscription parameters
0092      *   don't match.
0093      *
0094      * @param collection the name of the collection to which the event belongs
0095      * @param event the name of the event to which subsribe the @class DDPManager object
0096      * @param ddpManager the @class DDPManager instance that will process event messages
0097      * @param subscriptionId a manager specific id that helps the manager keep track of
0098      *   the subscription
0099      */
0100     void deregisterSubscriber(const QString &collection, const QString &event, DDPManager *ddpManager, int subscriptionId);
0101 
0102     /**
0103      * @brief Calls a method on the websocket and registers the DDPManager invoking it
0104      *   for later response dispatching.
0105      *
0106      * @param method the method to be invoked
0107      * @param params parameters of the call
0108      * @param ddpmanager the manager invoking the call
0109      * @param operationId a manaager specific id to keep track of the operation invoked
0110      *   through the method
0111      */
0112     quint64 invokeMethodAndRegister(const QString &method, const QJsonArray &params, DDPManager *ddpManager, int operationId);
0113 
0114     /**
0115      * @brief Deregister an API manager from responses to a method represented by its id.
0116      *
0117      *   Silmilarly to deregisterSubscriber(), the @param methodId parameter is enough
0118      *   to deregister manager from method responses, but the other parameters are added
0119      *   for debugging purposes.
0120      *
0121      * @param methodId the id of the method generated at invocation
0122      * @param manager the current manager subscribed to method responses
0123      * @param operationId the manager specific operation bound to the method invocation
0124      */
0125     void deregisterFromMethodResponse(quint64 methodId, DDPManager *ddpManager, int operationId);
0126 
0127     /**
0128      * @brief Calls method to log in the user with valid username and password
0129      */
0130     void login();
0131 
0132     /**
0133      * @brief Tries logging in if the client is connected or just sets a flag
0134      *   so a login will be tried on connection.
0135      */
0136     void enqueueLogin();
0137 
0138     /**
0139      * @brief Check whether websocket is connected at url
0140      *
0141      * @return true if connected, else false
0142      */
0143     [[nodiscard]] bool isConnected() const;
0144 
0145     /**
0146      * @brief Reconnects the websocket to new url
0147      */
0148     void onServerURLChange();
0149 
0150     /**
0151      * @brief Returns the queue used to cache unsent messages
0152      *
0153      *@return QQueue<QPair<QString,QJsonDocument>>, The m_messageQueue object
0154      */
0155     [[nodiscard]] QQueue<QPair<QString, QJsonDocument>> messageQueue() const;
0156 
0157     /**
0158      * @brief Returns standard cache path
0159      *
0160      *@def QString path
0161      */
0162     [[nodiscard]] QString cachePath() const;
0163 
0164     quint64 informTypingStatus(const QString &room, bool typing, const QString &userName);
0165 
0166     void setServerUrl(const QString &url);
0167     void start();
0168 
0169     [[nodiscard]] DDPAuthenticationManager *authenticationManager() const;
0170 
0171     quint64 joinRoom(const QString &roomId, const QString &joinCode);
0172     quint64 openDirectChannel(const QString &userId);
0173     void subscribeRoomMessage(const QString &roomId);
0174     quint64 setDefaultStatus(User::PresenceStatus status);
0175     quint64 createJitsiConfCall(const QString &roomId);
0176     quint64 userAutocomplete(const QString &pattern, const QString &exception);
0177     quint64 loadHistory(const QJsonArray &params);
0178     quint64 inputChannelAutocomplete(const QString &roomId, const QString &pattern, const QString &exceptions, bool threadDialog);
0179     quint64 inputUserAutocomplete(const QString &roomId, const QString &pattern, const QString &exceptions, bool threadDialog);
0180     quint64 unBlockUser(const QString &rid, const QString &userId);
0181     quint64 blockUser(const QString &rid, const QString &userId);
0182     quint64 deleteFileMessage(const QString &roomId, const QString &fileid, Room::RoomType channelType);
0183     quint64 setRoomEncrypted(const QString &roomId, bool encrypted);
0184     quint64 roomNameExists(const QString &roomId);
0185     quint64 streamNotifyUserOtrEnd(const QString &roomId, const QString &userId);
0186     quint64 streamNotifyUserOtrHandshake(const QString &userFrom, const QString &userTo, const QString &publicKey);
0187     quint64 streamNotifyUserOtrAcknowledge(const QString &roomId, const QString &userId, const QString &publicKey);
0188     quint64 deleteCustomSound(const QString &identifier);
0189     quint64 uploadCustomSound(const QByteArray &sound);
0190     void unsubscribe(quint64 registerId);
0191     quint64 listCustomSounds();
0192     quint64 enable2fa();
0193     quint64 disable2fa(const QString &code);
0194     quint64 validateTempToken2fa(const QString &code);
0195     quint64 regenerateCodes2fa(const QString &code);
0196     quint64 deleteOAuthApp(const QString &appId);
0197     quint64 addOAuthApp(const QString &name, bool active, const QString &redirectUrl);
0198     quint64 updateOAuthApp(const QString &name, bool active, const QString &redirectUrl);
0199     quint64 setAdminStatus(const QString &userId, bool admin);
0200     quint64 openRoom(const QString &roomId);
0201     quint64 getRoomById(const QString &roomId);
0202     quint64 bannerDismiss(const QString &bannerId);
0203     quint64 licenseGetModules();
0204     quint64 videoConferenceAccepted(const QString &roomId, const QString &callId, const QString &userId);
0205     quint64 videoConferenceRejected(const QString &roomId, const QString &callId, const QString &userId);
0206     quint64 videoConferenceCall(const QString &roomId, const QString &callId, const QString &userId);
0207     quint64 videoConferenceConfirmed(const QString &roomId, const QString &callId, const QString &userId);
0208 Q_SIGNALS:
0209     void connecting();
0210     void connectedChanged();
0211     void added(const QJsonObject &item);
0212     void changed(const QJsonObject &item);
0213     void removed(const QJsonObject &item);
0214     void socketError(QAbstractSocket::SocketError error, const QString &errorString);
0215     void disconnectedByServer();
0216     void wsClosedSocketError();
0217 
0218     /**
0219      * @brief Emitted whenever a result is received
0220      *
0221      * @param id The ID received in the method() call
0222      * @param result The response sent by server
0223      */
0224     void result(quint64 id, const QJsonDocument &result);
0225 
0226 private Q_SLOTS:
0227     void onWSConnected();
0228     void onTextMessageReceived(const QString &message);
0229     void onWSclosed();
0230     void onSslErrors(const QList<QSslError> &errors);
0231 
0232 private:
0233     Q_DISABLE_COPY(DDPClient)
0234     LIBRUQOLACORE_NO_EXPORT void initializeWebSocket();
0235     LIBRUQOLACORE_NO_EXPORT void connectWebSocket();
0236 
0237     LIBRUQOLACORE_NO_EXPORT QUrl adaptUrl(const QString &url);
0238 
0239     LIBRUQOLACORE_NO_EXPORT void pong();
0240     LIBRUQOLACORE_NO_EXPORT void executeSubsCallBack(const QJsonObject &root);
0241 
0242     QString mUrl;
0243     AbstractWebSocket *mWebSocket = nullptr;
0244 
0245     /**
0246      * @brief Unique message ID for each message sent over network
0247      */
0248     quint64 m_uid = 0;
0249 
0250     /**
0251      * @brief Stores callback function associated with each message
0252      *
0253      * @def QHash unsigned messageID and std::function<void (QJsonDocument)> pointer to callback
0254      */
0255     QHash<quint64, std::function<void(QJsonObject, RocketChatAccount *)>> m_callbackHash;
0256 
0257     /**
0258      * @brief stores subscription handlers for a given event on a given collection
0259      *
0260      * @def The key of the hash is a QPair<QString, QString>, where the first element
0261      *   is the collection (stream) name, and the second is the event name.
0262      *   Each value is a pair (DDPManager, int), where the int value is an internal
0263      *   reference for the manager to match internally method calls with responses.
0264      *   When a subscription response is received by the client, it will be dispatched
0265      *   to the corresponding manager iff both the collection and the event name match.
0266      */
0267     QHash<QPair<QString, QString>, QPair<DDPManager *, int>> mEventSubscriptionHash;
0268 
0269     /**
0270      * @brief stores subscription handlers for a given event on a given collection
0271      *
0272      * @def The key of the hash is the generated id of the called method.
0273      *   When a method response is received by the client, it will be dispatched
0274      *   to the corresponding manager iff the method call id matches.
0275      */
0276     QHash<int, QPair<DDPManager *, int>> mMethodResponseHash;
0277 
0278     bool m_connected = false;
0279 
0280     /**
0281      * @brief Abstract queue for all requests regarding network management
0282      *
0283      * @def QPair QString method and QJsonDocument params
0284      */
0285     QQueue<QPair<QString, QJsonDocument>> m_messageQueue;
0286 
0287     friend class Ruqola;
0288     RocketChatMessage *mRocketChatMessage = nullptr;
0289     RocketChatAccount *mRocketChatAccount = nullptr;
0290     DDPAuthenticationManager *mAuthenticationManager = nullptr;
0291 
0292     bool mLoginEnqueued = false;
0293 };