File indexing completed on 2024-05-12 05:22:15

0001 /*
0002  * This file is part of LibKGAPI library
0003  *
0004  * SPDX-FileCopyrightText: 2013 Daniel Vrátil <dvratil@redhat.com>
0005  *
0006  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007  */
0008 
0009 #pragma once
0010 
0011 #include "kgapicore_export.h"
0012 #include "types.h"
0013 
0014 #include <QObject>
0015 
0016 class QNetworkAccessManager;
0017 class QNetworkReply;
0018 class QNetworkRequest;
0019 
0020 namespace KGAPI2
0021 {
0022 
0023 /**
0024  * @headerfile job.h
0025  * @brief Abstract base class for all jobs in LibKGAPI
0026  *
0027  * Usual workflow of Job subclasses is to reimplement Job::start,
0028  * Job::dispatchRequest and Job::handleReply, then enqueue a QNetworkRequest using
0029  * Job::enqueueRequest. Authorization headers and standard query parameters will be
0030  * set by Job class. The request will automatically be scheduled in a queue and
0031  * dispatched by calling Job::dispatchRequest implementation. When a reply is received,
0032  * the Job will automatically perform error handling and if there is no error, the
0033  * reply is passed to implementation of Job::handleReply.
0034  *
0035  * Job is automatically started when program enters an event loop.
0036  *
0037  * @author Daniel Vrátil <dvratil@redhat.com>
0038  * @since 2.0
0039  */
0040 class KGAPICORE_EXPORT Job : public QObject
0041 {
0042     Q_OBJECT
0043 
0044     /**
0045      * @brief Maximum interval between requests.
0046      *
0047      * Some Google APIs have a quota on maximum amount of requests per account
0048      * per second. When this quota is exceeded, the Job will automatically increase
0049      * the interval between dispatching requests, wait for a while and then try
0050      * again. If however the interval is increased over @p maxTimeout, the job
0051      * will fail and finish immediately. By default @p maxTimeout is @p -1, which
0052      * allows the interval to be increased indefinitely.
0053      *
0054      * @see Job::maxTimeout, Job::setMaxTimeout
0055      */
0056     Q_PROPERTY(int maxTimeout READ maxTimeout WRITE setMaxTimeout)
0057 
0058     /**
0059      * @brief Whether the job is running
0060      *
0061      * This property indicates whether the job is running or not. The value is
0062      * set to @p true when the job is started (see Job::start) and back to
0063      * @p false right before Job::finished is emitted.
0064      *
0065      * @see Job::isRunning, Job::finished
0066      */
0067     Q_PROPERTY(bool isRunning READ isRunning NOTIFY finished)
0068 public:
0069     /**
0070      * @brief Constructor for jobs that don't require authentication
0071      *
0072      * @param parent
0073      */
0074     explicit Job(QObject *parent = nullptr);
0075 
0076     /**
0077      * @brief Constructor for jobs that require authentication
0078      *
0079      * @param account Account to use to authenticate the requests send by this job
0080      * @param parent
0081      * @see Job::Account, Job::setAccount
0082      */
0083     explicit Job(const AccountPtr &account, QObject *parent = nullptr);
0084 
0085     struct KGAPICORE_EXPORT StandardParams {
0086         static const QString PrettyPrint;
0087         static const QString Fields;
0088     };
0089 
0090     /**
0091      * @brief Destructor
0092      */
0093     ~Job() override;
0094 
0095     /**
0096      * @brief Error code
0097      *
0098      * This method can only be called after the job has emitted Job::finished
0099      * signal. Calling this method on a running job will always return
0100      * KGAPI2::NoError.
0101      *
0102      * @return Returns code of occurred error or KGAPI2::NoError when no error
0103      *         has occurred.
0104      */
0105     KGAPI2::Error error() const;
0106 
0107     /**
0108      * @brief Error string
0109      *
0110      * This method can only be called after the job has emitted Job::finished
0111      * signal. Calling this method on a running job will always return an empty
0112      * string.
0113      *
0114      * @return Returns localized description of error or an empty string if no
0115      * error has occurred.
0116      */
0117     QString errorString() const;
0118 
0119     /**
0120      * @brief Set maximum quota timeout
0121      *
0122      * Sets maximum interval for which the job should wait before trying to submit
0123      * a request that has previously failed due to exceeded quota.
0124      *
0125      * Default timeout is 1 seconds, then after every failed request the timeout
0126      * is increased exponentially until reaching @p maxTimeout.
0127      *
0128      * @param maxTimeout Maximum timeout (in seconds), or @p -1 for no timeout
0129      */
0130     void setMaxTimeout(int maxTimeout);
0131 
0132     /**
0133      * @brief Maximum quota limit.
0134      *
0135      * @return Returns maximum timeout in seconds or -1 if there is no timeout set.
0136      * @see Job::setMaxTimeout
0137      */
0138     int maxTimeout() const;
0139 
0140     /**
0141      * @brief Whether job is running
0142      *
0143      * A job is considered running from the moment it's started until
0144      * until Job::finished is emitted. Some methods should not be
0145      * called when a job is running.
0146      *
0147      * @return Returns whether this job is currently running.
0148      * @sa start()
0149      */
0150     bool isRunning() const;
0151 
0152     /**
0153      * @brief Set account to be used to authenticate requests
0154      *
0155      * By default, no account is set and all request are sent without any
0156      * authentication.
0157      *
0158      * @param account Account to use
0159      */
0160     void setAccount(const AccountPtr &account);
0161 
0162     /**
0163      * @brief Returns account used to authenticate requests
0164      *
0165      * For jobs that don't require authentication, this method returns a null
0166      * pointer.
0167      *
0168      * @return Am Account or a null pointer when no account was set.
0169      */
0170     AccountPtr account() const;
0171 
0172     /**
0173      * @brief Sets whether response will have indentations and line breaks.
0174      *
0175      * When this is false, it can reduce the response payload size,
0176      * which might lead to better performance in some environments.
0177      * Default is false.
0178      *
0179      * @param prettyPrint
0180      */
0181     void setPrettyPrint(bool prettyPrint);
0182 
0183     /**
0184      * @brief Returns prettyPrint query parameter.
0185      *
0186      * @return prettyPrint query parameter
0187      */
0188     bool prettyPrint() const;
0189 
0190     /**
0191      * @brief Set subset of fields to include in the response.
0192      *
0193      * Use for better performance.
0194      *
0195      * @param fields List of fields
0196      */
0197     void setFields(const QStringList &fields);
0198 
0199     static QString buildSubfields(const QString &field, const QStringList &fields);
0200 
0201     /**
0202      * @brief Returns fields selector.
0203      *
0204      * @return List of fields
0205      */
0206     QStringList fields() const;
0207 
0208     /**
0209      * @brief Restarts this job
0210      *
0211      * When a job finishes, it's possible to run it again, without having
0212      * to create a new job.
0213      *
0214      * The job will throw away all results retrieved in previous run and retrieve
0215      * everything again.
0216      *
0217      * @see Job::aboutToStart
0218      */
0219     void restart();
0220 
0221 Q_SIGNALS:
0222 
0223     /**
0224      * @brief Emitted when @p job has finished
0225      *
0226      * The signal is emitted every time, no matter whether the job is successful
0227      * or an error has occurred.
0228      *
0229      * Subclasses should never ever emit this signal directly.
0230      * Use Job::emitFinished instead.
0231      *
0232      * @param job The job that has finished
0233      * @sa emitFinished()
0234      */
0235     void finished(KGAPI2::Job *job);
0236 
0237     /**
0238      * @brief Emitted when a job progress changes.
0239      *
0240      * Note that some jobs might not provide progress information, thus this
0241      * signal will never be emitted.
0242      *
0243      * @param job The job that the information relates to
0244      * @param processed Amount of already processed items
0245      * @param total Total amount of items to process
0246      */
0247     void progress(KGAPI2::Job *job, int processed, int total);
0248 
0249 protected:
0250     /**
0251      * @brief Set job error to @p error
0252      *
0253      * @param error Error code to set
0254      * @see Job::error
0255      */
0256     void setError(KGAPI2::Error error);
0257 
0258     /**
0259      * @brief Set job error description to @p errorString
0260      *
0261      * @param errorString Error description to set
0262      * @see Job::errorString
0263      */
0264     void setErrorString(const QString &errorString);
0265 
0266     /**
0267      * @brief Emits Job::finished() signal
0268      *
0269      * Subclasses should always use this method instead of directly emitting
0270      * Job::finished().
0271      */
0272     virtual void emitFinished();
0273 
0274     /**
0275      * @brief This method is invoked right before finished() is emitted
0276      *
0277      * Subclasses can reimplement this method to do a final cleanup before
0278      * the Job::finished() signal is emitted.
0279      *
0280      * @note Note that after Job::finished() the job is not running anymore and
0281      *       therefore the job should not modify any data accessible by user.
0282      */
0283     virtual void aboutToFinish();
0284 
0285     /**
0286      * @brief Emit progress() signal
0287      *
0288      * Subclasses should always use this method instead of directly emitting
0289      * Job::progress().
0290      *
0291      * @param processed Amount of already processed items
0292      * @param total Total amount of items to process
0293      */
0294     virtual void emitProgress(int processed, int total);
0295 
0296     /**
0297      * @brief This method is invoked right before Job::start() is called.
0298      *
0299      * Subclasses should reset their internal state and call parent implementation.
0300      */
0301     virtual void aboutToStart();
0302 
0303     /**
0304      * @brief This method is invoked when job is started.
0305      *
0306      * Job is automatically started when application enters event loop.
0307      */
0308     virtual void start() = 0;
0309 
0310     /**
0311      * @brief Dispatches @p request via @p accessManager
0312      *
0313      * Because different types of request require different HTTP method to be
0314      * used, subclasses must reimplement this method and use respective HTTP
0315      * method to send the @p request via @p accessManager.
0316      *
0317      * @param accessManager QNetworkAccessManager used to dispatch the request
0318      * @param request Request to dispatch
0319      * @param data Data to sent in the body of the request
0320      * @param contentType Content-Type of @p data
0321      */
0322     virtual void dispatchRequest(QNetworkAccessManager *accessManager, const QNetworkRequest &request, const QByteArray &data, const QString &contentType) = 0;
0323 
0324     /**
0325      * @brief Called when a reply is received.
0326      *
0327      * Subclasses must reimplement this method to handle reply content.
0328      *
0329      * @param reply A reply received from server
0330      * @param rawData Raw content of the reply. Don't use QNetworkReply::readAll,
0331      *        because this method has already been called by Job and thus it would
0332      *        return nothing.
0333      */
0334     virtual void handleReply(const QNetworkReply *reply, const QByteArray &rawData) = 0;
0335 
0336     /**
0337      * @brief Enqueues @p request in dispatcher queue
0338      *
0339      * Subclasses should call this method to enqueue the @p request in main job
0340      * queue. The request is automatically dispatched, and reply is handled.
0341      * Authorization headers and standards query parameters will be applied.
0342      *
0343      * @param request Request to enqueue
0344      * @param data Data to be send in body of the request
0345      * @param contentType Content type of @p data
0346      */
0347     virtual void enqueueRequest(const QNetworkRequest &request, const QByteArray &data = QByteArray(), const QString &contentType = QString());
0348 
0349 private:
0350     class Private;
0351     Private *const d;
0352     friend class Private;
0353 
0354     friend class AuthJob;
0355 };
0356 
0357 } // namespace KGAPI2