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 }