KPublicTransport

assetrepository.cpp
1 /*
2  SPDX-FileCopyrightText: 2020 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "assetrepository_p.h"
8 #include "logging.h"
9 
10 #include <KPublicTransport/Attribution>
11 
12 #include <QDebug>
13 #include <QDir>
14 #include <QFileInfo>
15 #include <QJsonArray>
16 #include <QJsonDocument>
17 #include <QNetworkAccessManager>
18 #include <QNetworkReply>
19 #include <QStandardPaths>
20 #include <QUrl>
21 
22 using namespace KPublicTransport;
23 
24 AssetRepository* AssetRepository::s_instance = nullptr;
25 
26 AssetRepository::AssetRepository(QObject *parent)
27  : QObject(parent)
28 {
29  if (!s_instance) {
30  s_instance = this;
31  }
32 }
33 
34 AssetRepository::~AssetRepository()
35 {
36  if (s_instance == this) {
37  s_instance = nullptr;
38  }
39 }
40 
41 AssetRepository* AssetRepository::instance()
42 {
43  return s_instance;
44 }
45 
46 void AssetRepository::setNetworkAccessManager(QNetworkAccessManager *nam)
47 {
48  m_nam = nam;
49 }
50 
51 static QString cachePath()
52 {
53  return QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/org.kde.kpublictransport/assets/");
54 }
55 
56 QString AssetRepository::localFile(const QUrl& url)
57 {
58  if (!url.isValid() || url.fileName().isEmpty()) {
59  return {};
60  }
61 
62  QFileInfo fi(cachePath() + url.fileName());
63  if (fi.exists() && fi.size() > 0) {
64  return fi.absoluteFilePath();
65  }
66  return {};
67 }
68 
69 bool AssetRepository::download(const QUrl &url)
70 {
71  if (!url.isValid() || url.scheme() != QLatin1String("https") || url.fileName().isEmpty() || !m_nam) {
72  return false;
73  }
74 
75  if (QFileInfo::exists(cachePath() + url.fileName())) { // already downloaded, or persistent error
76  return false;
77  }
78 
79  if (std::find(m_queue.begin(), m_queue.end(), url) != m_queue.end()) {
80  return false;
81  }
82 
83  m_queue.push_back(url);
84  if (m_queue.size() == 1) {
85  downloadNext();
86  }
87  return true;
88 }
89 
90 bool AssetRepository::isQueueEmpty()
91 {
92  return m_queue.empty();
93 }
94 
95 void AssetRepository::downloadNext()
96 {
97  if (m_queue.empty()) {
98  Q_EMIT downloadFinished();
99  return;
100  }
101 
102  QNetworkRequest req(m_queue.front());
103  auto reply = m_nam->get(req);
104  connect(reply, &QNetworkReply::finished, this, [this, reply]() {
105  reply->deleteLater();
106 
107  switch (reply->error()) {
109  {
110  QDir().mkpath(cachePath());
111  QFile f(cachePath() + reply->request().url().fileName());
112  if (!f.open(QFile::WriteOnly)) {
113  qWarning() << "Failed to open file for storing asset" << f.errorString() << f.fileName();
114  } else {
115  f.write(reply->readAll());
116  }
117  break;
118  }
119  // persistent errors, empty file prevents forther
124  {
125  qWarning() << reply->errorString();
126  QDir().mkpath(cachePath());
127  QFile f(cachePath() + reply->request().url().fileName());
129  break;
130  }
131  // transient errors
132  default:
133  qWarning() << reply->errorString();
134  break;
135  }
136 
137  m_queue.pop_front();
138  downloadNext();
139  });
140 }
141 
142 const std::vector<Attribution>& AssetRepository::attributions() const
143 {
144  if (m_attributions.empty()) {
145  QFile f(QStringLiteral(":/org.kde.kpublictransport/assets/asset-attributions.json"));
146  if (!f.open(QFile::ReadOnly)) {
147  qCWarning(Log) << f.fileName() << f.errorString();
148  return m_attributions;
149  }
150 
151  m_attributions = Attribution::fromJson(QJsonDocument::fromJson(f.readAll()).array());
152  }
153 
154  return m_attributions;
155 }
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
Query operations and data types for accessing realtime public transport information from online servi...
Definition: attribution.cpp:16
QString writableLocation(QStandardPaths::StandardLocation type)
QString errorString() const const
static Attribution fromJson(const QJsonObject &obj)
Deserialize an Attribution object from JSON.
Definition: attribution.cpp:48
QString absoluteFilePath() const const
bool isEmpty() const const
virtual bool open(QIODevice::OpenMode mode) override
QString scheme() const const
void push_back(QChar ch)
bool exists() const const
bool isValid() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString fileName(QUrl::ComponentFormattingOptions options) const const
Q_EMITQ_EMIT
bool mkpath(const QString &dirPath) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 23 2021 23:05:20 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.