File indexing completed on 2024-05-12 04:42:39

0001 /*
0002     SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "openjourneyplannerbackend.h"
0008 #include "openjourneyplannerparser.h"
0009 #include "openjourneyplannerrequestbuilder.h"
0010 #include "cache.h"
0011 
0012 #include <KPublicTransport/Journey>
0013 #include <KPublicTransport/JourneyReply>
0014 #include <KPublicTransport/JourneyRequest>
0015 #include <KPublicTransport/Location>
0016 #include <KPublicTransport/LocationReply>
0017 #include <KPublicTransport/LocationRequest>
0018 #include <KPublicTransport/Stopover>
0019 #include <KPublicTransport/StopoverReply>
0020 #include <KPublicTransport/StopoverRequest>
0021 
0022 #include <QNetworkAccessManager>
0023 #include <QNetworkReply>
0024 #include <QNetworkRequest>
0025 
0026 using namespace KPublicTransport;
0027 
0028 AbstractBackend::Capabilities OpenJourneyPlannerBackend::capabilities() const
0029 {
0030     return AbstractBackend::CanQueryArrivals |
0031         (m_endpoint.scheme() == QLatin1String("https") ? AbstractBackend::Secure : AbstractBackend::NoCapability);
0032 }
0033 
0034 bool OpenJourneyPlannerBackend::needsLocationQuery(const Location &loc, [[maybe_unused]] AbstractBackend::QueryType type) const
0035 {
0036     return !loc.hasCoordinate() && loc.identifier(QStringLiteral("uic")).isEmpty(); // ### TODO configure identifier type
0037 }
0038 
0039 bool OpenJourneyPlannerBackend::queryLocation(const LocationRequest &request, LocationReply *reply, QNetworkAccessManager *nam) const
0040 {
0041     if ((request.types() & Location::Stop) == 0) {
0042         return false;
0043     }
0044 
0045     const auto postData = requestBuilder().buildLocationInformationRequest(request);
0046     const auto netReq = networkRequest();
0047     logRequest(request, netReq, postData);
0048     const auto netReply = nam->post(netReq, postData);
0049     netReply->setParent(reply);
0050     QObject::connect(netReply, &QNetworkReply::finished, reply, [this, netReply, reply]() {
0051         netReply->deleteLater();
0052         const auto data = netReply->readAll();
0053         logReply(reply, netReply, data);
0054 
0055         if (netReply->error() != QNetworkReply::NoError) {
0056             addError(reply, Reply::NetworkError, netReply->errorString());
0057             return;
0058         }
0059 
0060         auto p = parser();
0061         auto locs = p.parseLocationInformationResponse(data);
0062         if (p.hasError()) {
0063             addError(reply, Reply::NotFoundError, p.errorMessage());
0064         } else {
0065             Cache::addLocationCacheEntry(backendId(), reply->request().cacheKey(), locs, {});
0066             addResult(reply, std::move(locs));
0067         }
0068     });
0069 
0070     return true;
0071 }
0072 
0073 bool OpenJourneyPlannerBackend::queryStopover(const StopoverRequest &request, StopoverReply *reply, QNetworkAccessManager *nam) const
0074 {
0075     const auto postData = requestBuilder().buildStopEventRequest(request);
0076     const auto netReq = networkRequest();
0077     logRequest(request, netReq, postData);
0078     const auto netReply = nam->post(netReq, postData);
0079     netReply->setParent(reply);
0080     QObject::connect(netReply, &QNetworkReply::finished, reply, [this, netReply, reply]() {
0081         netReply->deleteLater();
0082         const auto data = netReply->readAll();
0083         logReply(reply, netReply, data);
0084 
0085         if (netReply->error() != QNetworkReply::NoError) {
0086             addError(reply, Reply::NetworkError, netReply->errorString());
0087             return;
0088         }
0089 
0090         auto p = parser();
0091         auto stops = p.parseStopEventResponse(data);
0092         if (p.hasError()) {
0093             addError(reply, Reply::NotFoundError, p.errorMessage());
0094         } else {
0095             // TODO caching
0096             addResult(reply, this, std::move(stops));
0097         }
0098     });
0099 
0100     return true;
0101 }
0102 
0103 bool OpenJourneyPlannerBackend::queryJourney(const JourneyRequest &request, JourneyReply *reply, QNetworkAccessManager *nam) const
0104 {
0105     const auto postData = requestBuilder().buildTripRequest(request);
0106     const auto netReq = networkRequest();
0107     logRequest(request, netReq, postData);
0108     const auto netReply = nam->post(netReq, postData);
0109     netReply->setParent(reply);
0110     QObject::connect(netReply, &QNetworkReply::finished, reply, [this, netReply, reply]() {
0111         netReply->deleteLater();
0112         const auto data = netReply->readAll();
0113         logReply(reply, netReply, data);
0114 
0115         if (netReply->error() != QNetworkReply::NoError) {
0116             addError(reply, Reply::NetworkError, netReply->errorString());
0117             return;
0118         }
0119 
0120         auto p = parser();
0121         auto jnys = p.parseTripResponse(data);
0122         if (p.hasError()) {
0123             addError(reply, Reply::NotFoundError, p.errorMessage());
0124         } else {
0125             // TODO caching
0126             addResult(reply, this, std::move(jnys));
0127         }
0128     });
0129 
0130     return true;
0131 }
0132 
0133 QNetworkRequest OpenJourneyPlannerBackend::networkRequest() const
0134 {
0135     QNetworkRequest req(m_endpoint);
0136     req.setHeader(QNetworkRequest::ContentTypeHeader, m_contentType);
0137     if (!m_authorization.isEmpty()) {
0138         req.setRawHeader("Authorization", m_authorization.toUtf8());
0139     }
0140     return req;
0141 }
0142 
0143 OpenJourneyPlannerRequestBuilder OpenJourneyPlannerBackend::requestBuilder() const
0144 {
0145     OpenJourneyPlannerRequestBuilder builder;
0146     builder.setRequestorRef(m_requestorRef);
0147     builder.setUseTrias(m_useTrias);
0148     return builder;
0149 }
0150 
0151 OpenJourneyPlannerParser OpenJourneyPlannerBackend::parser() const
0152 {
0153     OpenJourneyPlannerParser p;
0154     p.setLocationIdentifierType(backendId());
0155     p.setUicLocationIdentifierType(m_uicLocationIdentifierType);
0156     return p;
0157 }