File indexing completed on 2024-05-12 04:42:32
0001 /* 0002 SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KPUBLICTRANSPORT_ABSTRACTBACKEND_H 0008 #define KPUBLICTRANSPORT_ABSTRACTBACKEND_H 0009 0010 #include "kpublictransport_export.h" 0011 0012 #include "reply.h" 0013 #include "requestcontext_p.h" 0014 0015 #include <KPublicTransport/Attribution> 0016 0017 #include <QFlags> 0018 #include <QJsonObject> 0019 #include <QPolygonF> 0020 #include <QSslCertificate> 0021 #include <QSslKey> 0022 #include <QTimeZone> 0023 #include <QVariant> 0024 0025 class QNetworkAccessManager; 0026 class QNetworkReply; 0027 class QNetworkRequest; 0028 0029 namespace KPublicTransport { 0030 0031 class JourneyReply; 0032 class JourneyRequest; 0033 class Location; 0034 class LocationReply; 0035 class LocationRequest; 0036 class StopoverReply; 0037 class StopoverRequest; 0038 class VehicleLayoutReply; 0039 class VehicleLayoutRequest; 0040 0041 /** Abstract base class for transport provider backends. 0042 * @internal exported for tooling only 0043 */ 0044 class KPUBLICTRANSPORT_EXPORT AbstractBackend 0045 { 0046 Q_GADGET 0047 Q_PROPERTY(QString customCaCertificate WRITE setCustomCaCertificate) 0048 /** PKCS#12 client certificate bundle. */ 0049 Q_PROPERTY(QString pkcs12 WRITE setPkcs12) 0050 public: 0051 AbstractBackend(); 0052 virtual ~AbstractBackend(); 0053 0054 /** Identifier for this backend. 0055 * Use e.g. for distinguishing backend-specific cache locations etc. 0056 */ 0057 QString backendId() const; 0058 void setBackendId(const QString &id); 0059 0060 /** Static timezone for all times used by and provided by the backend. 0061 * Set to invalid if the backend supports multiple timezones. 0062 */ 0063 QTimeZone timeZone() const; 0064 void setTimeZone(const QTimeZone &tz); 0065 0066 /** Supported languages. 0067 * This matters for backends that require us to ask for humand readable strings 0068 * in a specific language (as opposed to providing all possible translations by default). 0069 * The first language in QLocale::uiLanguages found in this list should be requested. 0070 * @see preferredLanguage() 0071 */ 0072 QStringList supportedLanguages() const; 0073 void setSupportedLanguages(const QStringList &langs); 0074 0075 /** Returns the language that should be requested. 0076 * This is essentially the first language in QLocale::uiLanguages that is also found 0077 * in the list of supported languages, if that's not the case the first supported 0078 * language of the backend, or if that's not set, English by default. 0079 */ 0080 QString preferredLanguage() const; 0081 0082 /** Called after all settings have been set on this backend. */ 0083 virtual void init(); 0084 0085 enum Capability { 0086 NoCapability = 0, 0087 Secure = 1, ///< uses transport encryption 0088 CanQueryNextJourney = 2, ///< supports querying for later journeys 0089 CanQueryPreviousJourney = 4, ///< supports query for earlier journeys 0090 CanQueryNextDeparture = 8, ///< supports querying for later departures 0091 CanQueryPreviousDeparture = 16, ///< supports query for earlier departures 0092 CanQueryArrivals = 32, ///< supports querying arrival stopovers at a given location 0093 }; 0094 Q_DECLARE_FLAGS(Capabilities, Capability) 0095 0096 /** Returns the capabilities of this backend. */ 0097 virtual Capabilities capabilities() const; 0098 /** Checks if this backend has @p capability. */ 0099 inline bool hasCapability(Capability capability) const { return capabilities() & capability; }; 0100 0101 /** Returns the static attribution information for this backend. */ 0102 Attribution attribution() const; 0103 /** Sets the static attribution information for this backend. */ 0104 void setAttribution(const Attribution &attr); 0105 0106 /** Type of query. 0107 * @see needsLocationQuery 0108 */ 0109 enum class QueryType { 0110 Departure, 0111 Journey 0112 }; 0113 /** Returns whether or not a location query has to be performed for the given 0114 * Location before doing departure or journey queries for it. 0115 */ 0116 virtual bool needsLocationQuery(const Location &loc, QueryType type) const; 0117 0118 /** Perform a journey query. 0119 * @return @c true if performing an async operation, @c false otherwise. 0120 */ 0121 virtual bool queryJourney(const JourneyRequest &request, JourneyReply *reply, QNetworkAccessManager *nam) const; 0122 0123 /** Perform a departure query. 0124 * @return @c true if performing an async operation, @c false otherwise. 0125 */ 0126 virtual bool queryStopover(const StopoverRequest &request, StopoverReply *reply, QNetworkAccessManager *nam) const; 0127 0128 /** Perform a location query. 0129 * @return @c true if performing an async operation, @c false otherwise. 0130 */ 0131 virtual bool queryLocation(const LocationRequest &request, LocationReply *reply, QNetworkAccessManager *nam) const; 0132 0133 /** Perform a vehicle layout query. 0134 * @return @c true if performing an async operation, @c false otherwise. 0135 */ 0136 virtual bool queryVehicleLayout(const VehicleLayoutRequest &request, VehicleLayoutReply *reply, QNetworkAccessManager *nam) const; 0137 0138 protected: 0139 /** Helper function to call non-public Reply API. */ 0140 template <typename T, typename ...Args> inline static void addResult(T *reply, Args&&... args) 0141 { 0142 reply->addResult(std::forward<Args>(args)...); 0143 } 0144 0145 template <typename T> inline void addError(T *reply, Reply::Error error, const QString &errorMsg) const 0146 { 0147 reply->addError(this, error, errorMsg); 0148 } 0149 0150 static void addAttributions(Reply *reply, std::vector<Attribution> &&attributions); 0151 0152 /** Extract the request context for the current backend from @p request. */ 0153 template <typename ReqT> inline RequestContext requestContext(const ReqT &request) const 0154 { 0155 return request.context(this); 0156 } 0157 /** Extract the backend-specific data from the request context for the current backend from @p request. */ 0158 template <typename ReqT> inline QVariant requestContextData(const ReqT &request) const 0159 { 0160 return request.context(this).backendData; 0161 } 0162 0163 template <typename RepT> inline void setNextRequestContext(RepT *reply, const QVariant &data) const 0164 { 0165 reply->setNextContext(this, data); 0166 } 0167 template <typename RepT> inline void setPreviousRequestContext(RepT *reply, const QVariant &data) const 0168 { 0169 reply->setPreviousContext(this, data); 0170 } 0171 0172 /** Check if network logging is enabled. 0173 * Done automatically in logRequest/logReply, but can be useful for backends if producing 0174 * the necessary input is expensive. 0175 */ 0176 bool isLoggingEnabled() const; 0177 0178 template <typename ReqT> 0179 void logRequest(const ReqT &request, const QNetworkRequest &netRequest, const QByteArray &postData = {}) const 0180 { 0181 if (!isLoggingEnabled()) { 0182 return; 0183 } 0184 0185 logRequest(ReqT::staticMetaObject.className() + 18, ReqT::toJson(request), netRequest, postData); 0186 } 0187 0188 template <typename RepT> 0189 void logReply(RepT *reply, QNetworkReply *netReply, const QByteArray &data) const 0190 { 0191 if (!isLoggingEnabled()) { 0192 return; 0193 } 0194 0195 logReply(reply->metaObject()->className() + 18, netReply, data); 0196 } 0197 0198 /** Apply custom SSL workaround on the given network request. */ 0199 void applySslConfiguration(QNetworkRequest &request) const; 0200 0201 private: 0202 Q_DISABLE_COPY(AbstractBackend) 0203 QString logDir() const; 0204 void logRequest(const char *typeName, const QJsonObject &requestData, const QNetworkRequest &netRequest, const QByteArray &postData) const; 0205 void logReply(const char *typeName, QNetworkReply *netReply, const QByteArray &data) const; 0206 void setCustomCaCertificate(const QString &caCert); 0207 void setPkcs12(const QString &pkcs12Name); 0208 0209 QString m_backendId; 0210 Attribution m_attribution; 0211 QTimeZone m_timeZone; 0212 QStringList m_supportedLanguages; 0213 QList<QSslCertificate> m_customCaCerts; 0214 QSslCertificate m_clientCert; 0215 QSslKey m_privateKey; 0216 }; 0217 0218 Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractBackend::Capabilities) 0219 0220 class AbstractAsyncTask : public QObject 0221 { 0222 Q_OBJECT 0223 0224 public: 0225 AbstractAsyncTask(QObject *parent = nullptr) : QObject(parent) {} 0226 0227 Q_SIGNAL void finished(); 0228 }; 0229 0230 /// 0231 /// Helper to return a value asynchronously 0232 /// 0233 template <typename T> 0234 class AsyncTask : public AbstractAsyncTask 0235 { 0236 std::optional<T> m_result; 0237 0238 public: 0239 using AbstractAsyncTask::AbstractAsyncTask; 0240 0241 void reportFinished(T &&result) { 0242 m_result = std::move(result); 0243 Q_EMIT finished(); 0244 } 0245 0246 const std::optional<T> &result() const { 0247 return m_result; 0248 } 0249 }; 0250 0251 template <> 0252 class AsyncTask<void> : public AbstractAsyncTask 0253 { 0254 public: 0255 using AbstractAsyncTask::AbstractAsyncTask; 0256 0257 void reportFinished() { 0258 Q_EMIT finished(); 0259 } 0260 }; 0261 0262 } 0263 0264 #endif // KPUBLICTRANSPORT_ABSTRACTBACKEND_H