diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 68b4a26..22bbe01 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,153 +1,156 @@ add_subdirectory(graphql) set(kpublictransport_srcs departurereply.cpp departurerequest.cpp journeyreply.cpp journeyrequest.cpp locationreply.cpp locationrequest.cpp manager.cpp reply.cpp requestcontext.cpp vehiclelayoutreply.cpp vehiclelayoutrequest.cpp backends/abstractbackend.cpp backends/cache.cpp backends/deutschebahnbackend.cpp backends/deutschebahnvehiclelayoutparser.cpp backends/efabackend.cpp backends/efaparser.cpp backends/efacompactparser.cpp backends/efaxmlparser.cpp backends/hafasbackend.cpp backends/hafasparser.cpp backends/hafasmgatebackend.cpp backends/hafasmgateparser.cpp backends/hafasquerybackend.cpp backends/hafasqueryparser.cpp backends/navitiabackend.cpp backends/navitiaparser.cpp backends/otp/otp.qrc backends/scopedxmlstreamreader.cpp datatypes/attribution.cpp datatypes/attributionutil.cpp datatypes/backend.cpp datatypes/departure.cpp datatypes/departureutil.cpp datatypes/disruption.cpp datatypes/journey.cpp datatypes/journeyutil.cpp datatypes/json.cpp datatypes/line.cpp datatypes/location.cpp datatypes/locationutil.cpp datatypes/mergeutil.cpp datatypes/notesutil.cpp datatypes/platform.cpp datatypes/platformutils.cpp datatypes/vehicle.cpp models/abstractquerymodel.cpp models/backendmodel.cpp models/departurequerymodel.cpp models/journeyquerymodel.cpp models/locationquerymodel.cpp models/vehiclelayoutquerymodel.cpp networks/networks.qrc ) ecm_qt_declare_logging_category(kpublictransport_srcs HEADER logging.h IDENTIFIER KPublicTransport::Log CATEGORY_NAME org.kde.kpublictransport) add_library(KPublicTransport ${kpublictransport_srcs}) generate_export_header(KPublicTransport BASE_NAME KPublicTransport) set_target_properties(KPublicTransport PROPERTIES VERSION ${KPUBLICTRANSPORT_VERSION_STRING} SOVERSION ${KPUBLICTRANSPORT_SOVERSION} EXPORT_NAME KPublicTransport ) target_include_directories(KPublicTransport PUBLIC "$") target_link_libraries(KPublicTransport PUBLIC Qt5::Gui PRIVATE Qt5::Network ZLIB::ZLIB ) ecm_generate_headers(KPublicTransport_FORWARDING_HEADERS HEADER_NAMES DepartureReply DepartureRequest JourneyReply JourneyRequest LocationReply LocationRequest Manager Reply VehicleLayoutReply VehicleLayoutRequest PREFIX KPublicTransport REQUIRED_HEADERS KPublicTransport_HEADERS ) # # ### for testing only ecm_generate_headers(KPublicTransport_Backends_FORWARDING_HEADERS HEADER_NAMES Cache HafasMgateParser NavitiaParser PREFIX KPublicTransport REQUIRED_HEADERS KPublicTransport_Backends_HEADERS RELATIVE backends ) ecm_generate_headers(KPublicTransport_Datatypes_FORWARDING_HEADERS HEADER_NAMES Attribution Backend Datatypes Departure Disruption Journey Line Location Platform Vehicle PREFIX KPublicTransport REQUIRED_HEADERS KPublicTransport_Datatypes_HEADERS RELATIVE datatypes ) ecm_generate_headers(KPublicTransport_Models_FORWARDING_HEADERS HEADER_NAMES AbstractQueryModel BackendModel DepartureQueryModel JourneyQueryModel LocationQueryModel VehicleLayoutQueryModel PREFIX KPublicTransport REQUIRED_HEADERS KPublicTransport_Models_HEADERS RELATIVE models ) install(TARGETS KPublicTransport EXPORT KPublicTransportTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES org_kde_kpublictransport.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) install(FILES ${KPublicTransport_FORWARDING_HEADERS} ${KPublicTransport_Datatypes_FORWARDING_HEADERS} ${KPublicTransport_Models_FORWARDING_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPublicTransport ) install(FILES ${KPublicTransport_HEADERS} ${KPublicTransport_Datatypes_HEADERS} ${KPublicTransport_Models_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kpublictransport_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kpublictransport ) add_subdirectory(qmlplugin) if (TARGET Qt5::Quick) add_subdirectory(quick) endif() +if (NOT CROSS_COMPILING) + add_subdirectory(tools) +endif() diff --git a/src/networks/de_nw_muenster.json b/src/networks/de_nw_muenster.json new file mode 100644 index 0000000..0b8f2ac --- /dev/null +++ b/src/networks/de_nw_muenster.json @@ -0,0 +1,30 @@ +{ + "KPlugin": { + "Description": "Local public transport in and around Münster, Germany.", + "Name": "Münster, Germany" + }, + "filter": { + "geo": [ + [ + 6.245927900000001, + 52.483627500000004 + ], + [ + 8.3234834, + 52.483627500000004 + ], + [ + 8.3234834, + 51.4769823 + ], + [ + 6.245927900000001, + 51.4769823 + ] + ] + }, + "options": { + "endpoint": "https://api.digitransit.codeformuenster.org/routing/v1/routers/cfm/" + }, + "type": "otp" +} diff --git a/src/networks/fi_17_helsinki.json b/src/networks/fi_17_helsinki.json new file mode 100644 index 0000000..43de1dd --- /dev/null +++ b/src/networks/fi_17_helsinki.json @@ -0,0 +1,35 @@ +{ + "KPlugin": { + "Description": "Local public transport in and around Helsinki, Finland.", + "Name": "Helsinki" + }, + "attribution": { + "license": "CC-BY-4.0", + "licenseUrl": "https://creativecommons.org/licenses/by/4.0/", + "name": "© Helsinki Region Transport" + }, + "filter": { + "geo": [ + [ + 19.5364379883, + 66.5802673946 + ], + [ + 29.5712215851, + 66.5802673946 + ], + [ + 29.5712215851, + 59.7865148075 + ], + [ + 19.5364379883, + 59.7865148075 + ] + ] + }, + "options": { + "endpoint": "https://api.digitransit.fi/routing/v1/routers/hsl/" + }, + "type": "otp" +} diff --git a/src/networks/fi_digitransit.json b/src/networks/fi_digitransit.json new file mode 100644 index 0000000..ad99bd8 --- /dev/null +++ b/src/networks/fi_digitransit.json @@ -0,0 +1,30 @@ +{ + "KPlugin": { + "Description": "Public transport in Finland.", + "Name": "Digitransit Finland" + }, + "filter": { + "geo": [ + [ + 19.3167101, + 70.1383835 + ], + [ + 37.653402, + 70.1383835 + ], + [ + 37.653402, + 55.776771 + ], + [ + 19.3167101, + 55.776771 + ] + ] + }, + "options": { + "endpoint": "https://api.digitransit.fi/routing/v1/routers/finland/" + }, + "type": "otp" +} diff --git a/src/networks/fi_waltti.json b/src/networks/fi_waltti.json new file mode 100644 index 0000000..90971b4 --- /dev/null +++ b/src/networks/fi_waltti.json @@ -0,0 +1,30 @@ +{ + "KPlugin": { + "Description": "Public transport in Waltti regions in Finland.", + "Name": "Waltti" + }, + "filter": { + "geo": [ + [ + 19.3167101, + 70.1383835 + ], + [ + 31.5841445, + 70.1383835 + ], + [ + 31.5841445, + 59.723203000000005 + ], + [ + 19.3167101, + 59.723203000000005 + ] + ] + }, + "options": { + "endpoint": "https://api.digitransit.fi/routing/v1/routers/waltti/" + }, + "type": "otp" +} diff --git a/src/networks/it_21_piemonte.json b/src/networks/it_21_piemonte.json new file mode 100644 index 0000000..3b7d3ab --- /dev/null +++ b/src/networks/it_21_piemonte.json @@ -0,0 +1,30 @@ +{ + "KPlugin": { + "Description": "Local public transport in the Piemonte region in Italy.", + "Name": "Muoversi in Piemonte" + }, + "filter": { + "geo": [ + [ + 0, + 46.468669600000005 + ], + [ + 11.276394, + 46.468669600000005 + ], + [ + 11.276394, + -6.927976224346821e-05 + ], + [ + 0, + -6.927976224346821e-05 + ] + ] + }, + "options": { + "endpoint": "https://map.muoversinpiemonte.it/otp/routers/mip/" + }, + "type": "otp" +} diff --git a/src/networks/it_21_torino.json b/src/networks/it_21_torino.json new file mode 100644 index 0000000..9dbf0a3 --- /dev/null +++ b/src/networks/it_21_torino.json @@ -0,0 +1,30 @@ +{ + "KPlugin": { + "Description": "Local public transport in and around Torino, Italy.", + "Name": "Muoversi a Torino" + }, + "filter": { + "geo": [ + [ + 6.63299, + 46.11542 + ], + [ + 11.276394, + 46.11542 + ], + [ + 11.276394, + 43.776881 + ], + [ + 6.63299, + 43.776881 + ] + ] + }, + "options": { + "endpoint": "https://mapi.5t.torino.it/routing/v1/routers/mat/" + }, + "type": "otp" +} diff --git a/src/networks/us_ca_la_metro.json b/src/networks/us_ca_la_metro.json new file mode 100644 index 0000000..5343f26 --- /dev/null +++ b/src/networks/us_ca_la_metro.json @@ -0,0 +1,30 @@ +{ + "KPlugin": { + "Description": "Public transport in and around Los Angles, US.", + "Name": "Los Angeles Metro" + }, + "filter": { + "geo": [ + [ + -119.5779026, + 34.809949 + ], + [ + -116.51300990000001, + 34.809949 + ], + [ + -116.51300990000001, + 33.193150638074 + ], + [ + -119.5779026, + 33.193150638074 + ] + ] + }, + "options": { + "endpoint": "https://otp.metroservices.io/otp/routers/default/" + }, + "type": "otp" +} diff --git a/src/networks/us_ga_marta.json b/src/networks/us_ga_marta.json new file mode 100644 index 0000000..0346716 --- /dev/null +++ b/src/networks/us_ga_marta.json @@ -0,0 +1,30 @@ +{ + "KPlugin": { + "Description": "Public transport in and around Atlanta, Georgia, US.", + "Name": "Marta" + }, + "filter": { + "geo": [ + [ + -84.98234160000001, + 34.4726225 + ], + [ + -83.6618736, + 34.4726225 + ], + [ + -83.6618736, + 33.269431100000006 + ], + [ + -84.98234160000001, + 33.269431100000006 + ] + ] + }, + "options": { + "endpoint": "https://opentrip.atlantaregion.com/otp/routers/default" + }, + "type": "otp" +} diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt new file mode 100644 index 0000000..ba179c6 --- /dev/null +++ b/src/tools/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(otpprobe otpprobe.cpp) +target_link_libraries(otpprobe Qt5::Network) + +add_custom_target(run-otp-probe COMMAND otpprobe ${CMAKE_SOURCE_DIR}/src/networks) diff --git a/src/tools/otpprobe.cpp b/src/tools/otpprobe.cpp new file mode 100644 index 0000000..ecc1c43 --- /dev/null +++ b/src/tools/otpprobe.cpp @@ -0,0 +1,113 @@ +/* + Copyright (C) 2020 Volker Krause + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static void fillNetworkConfig(QNetworkReply *reply, QJsonObject &obj) +{ + const auto desc = QJsonDocument::fromJson(reply->readAll()).object(); + QRectF boundingBox; + boundingBox.setBottom(desc.value(QLatin1String("lowerLeftLatitude")).toDouble()); + boundingBox.setLeft(desc.value(QLatin1String("lowerLeftLongitude")).toDouble()); + boundingBox.setTop(desc.value(QLatin1String("upperRightLatitude")).toDouble()); + boundingBox.setRight(desc.value(QLatin1String("upperRightLongitude")).toDouble()); + QJsonArray geoFilter; + for (const auto &point : {boundingBox.topLeft(), boundingBox.topRight(), boundingBox.bottomRight(), boundingBox.bottomLeft()}) { + QJsonArray p; + p.push_back(point.x()); + p.push_back(point.y()); + geoFilter.push_back(p); + } + QJsonObject filter; + filter.insert(QStringLiteral("geo"), geoFilter); + obj.insert(QStringLiteral("filter"), filter); +} + +/** Inspects OTP-based backends and queries their bounding boxes. */ +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + if (app.arguments().size() <= 1) { + std::cerr << "Usage: " << argv[0] << " [path to network configs]" << std::endl; + return 1; + } + + QNetworkAccessManager nam; + nam.setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); + + int jobCount = 0; + QDirIterator it(app.arguments().at(1), QDir::Files); + while (it.hasNext()) { + const auto fileName = it.next(); + QFile f(fileName); + if (!f.fileName().endsWith(QLatin1String(".json"))) { + continue; + } + if (!f.open(QFile::ReadOnly)) { + qWarning() << "Failed to open" << f.fileName() << f.errorString(); + continue; + } + + QJsonParseError docError; + const auto doc = QJsonDocument::fromJson(f.readAll(), &docError); + if (docError.error != QJsonParseError::NoError) { + qWarning() << "JSON parser error in" << fileName << docError.errorString(); + continue; + } + const auto obj = doc.object(); + if (obj.value(QLatin1String("type")).toString() != QLatin1String("otp")) { + continue; + } + + qDebug() << "Updating" << fileName; + const auto url = obj.value(QLatin1String("options")).toObject().value(QLatin1String("endpoint")).toString(); + ++jobCount; + auto reply = nam.get(QNetworkRequest(QUrl(url))); + QObject::connect(reply, &QNetworkReply::finished, &nam, [reply, &jobCount, obj, fileName]() { + if (reply->error() == QNetworkReply::NoError) { + auto newConfig = obj; + fillNetworkConfig(reply, newConfig); + QFile f(fileName); + if (!f.open(QFile::WriteOnly)) { + qWarning() << "Failed to open network config for writing:" << fileName << f.errorString(); + } else { + f.write(QJsonDocument(newConfig).toJson()); + } + } else { + qWarning() << reply->errorString(); + } + reply->deleteLater(); + --jobCount; + if (jobCount == 0) { + QCoreApplication::quit(); + } + }); + } + + return jobCount ? app.exec() : 0; +}