File indexing completed on 2023-05-30 09:06:28
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2011 Dennis Nienhüser <nienhueser@kde.org> 0004 // 0005 0006 #include "job.h" 0007 #include "logger.h" 0008 #include "upload.h" 0009 0010 #include <QDebug> 0011 #include <QDateTime> 0012 #include <QProcess> 0013 0014 Job::Job(const Region ®ion, const JobParameters ¶meters, QObject *parent) : 0015 QObject(parent), m_status(Waiting), m_region(region), m_parameters(parameters) 0016 { 0017 // nothing to do 0018 } 0019 0020 Job::Status Job::status() const 0021 { 0022 return m_status; 0023 } 0024 0025 QString Job::statusMessage() const 0026 { 0027 return m_statusMessage; 0028 } 0029 0030 Region Job::region() const 0031 { 0032 return m_region; 0033 } 0034 0035 void Job::setTransport(const QString &transport) 0036 { 0037 m_transport = transport; 0038 } 0039 0040 QString Job::transport() const 0041 { 0042 return m_transport; 0043 } 0044 0045 void Job::setProfile(const QString &profile) 0046 { 0047 m_profile = profile; 0048 } 0049 0050 void Job::setMonavSettings(const QString &filename) 0051 { 0052 m_monavSettings = filename; 0053 } 0054 0055 bool Job::operator ==(const Job &other) const 0056 { 0057 return m_transport == other.m_transport && m_region == other.m_region; 0058 } 0059 0060 void Job::run() 0061 { 0062 if (download() && monav() && search() && package() && upload()) { 0063 // Nothing to do. 0064 } 0065 0066 cleanup(); 0067 emit finished(this); 0068 } 0069 0070 void Job::changeStatus(Job::Status status, const QString &message) 0071 { 0072 QString statusType; 0073 switch (status) { 0074 case Waiting: statusType = "waiting"; break; 0075 case Downloading: statusType = "downloading"; break; 0076 case Routing: statusType = "routing"; break; 0077 case Search: statusType = "search"; break; 0078 case Packaging: statusType = "packaging"; break; 0079 case Uploading: statusType = "uploading"; break; 0080 case Finished: statusType = "finished"; break; 0081 case Error: statusType = "error"; break; 0082 } 0083 0084 Logger::instance().setStatus(m_region.id() + QLatin1Char('_') + m_transport, 0085 m_region.name() + QLatin1String(" (") + m_transport + QLatin1Char(')'), statusType, message); 0086 m_statusMessage = message; 0087 m_status = status; 0088 } 0089 0090 bool Job::download() 0091 { 0092 changeStatus(Downloading, "Downloading data."); 0093 qDebug() << "Saving file to " << osmFile().absoluteFilePath(); 0094 if (osmFile().exists()) { 0095 QDateTime now = QDateTime::currentDateTime(); 0096 if (osmFile().lastModified().daysTo(now) > 7) { 0097 qDebug() << "Old file is outdated, re-downloading " << osmFile().absoluteFilePath(); 0098 QFile::remove(osmFile().absoluteFilePath()); 0099 } else { 0100 qDebug() << "Old file is still ok, reusing" << osmFile().absoluteFilePath(); 0101 return true; 0102 } 0103 } 0104 0105 QProcess wget; 0106 QStringList arguments; 0107 QString url = m_region.pbfFile(); 0108 arguments << "-O" << osmFile().absoluteFilePath() << url; 0109 qDebug() << "Downloading " << url; 0110 wget.start("wget", arguments); 0111 wget.waitForFinished(1000 * 60 * 60 * 12); // wait up to 12 hours for download to complete 0112 if (wget.exitStatus() == QProcess::NormalExit && wget.exitCode() == 0) { 0113 return true; 0114 } else { 0115 qDebug() << "Failed to download " << url; 0116 QFile::remove(osmFile().absoluteFilePath()); 0117 changeStatus(Error, QLatin1String("Error downloading .osm.pbf file: ") + wget.readAllStandardError()); 0118 return false; 0119 } 0120 } 0121 0122 //bool Job::marble() 0123 //{ 0124 // changeStatus(Routing, "Extracting bounding box."); 0125 // QStringList arguments; 0126 // arguments << "--name" << m_region.name(); 0127 // arguments << "--version" << "0.2"; 0128 // arguments << "--date" << QDateTime::currentDateTime().toString("yyyy/dd/MM"); 0129 // arguments << "--transport" << m_transport; 0130 // arguments << "--payload" << targetFile().fileName(); 0131 // arguments << m_parameters.base().absoluteFilePath("poly/" + m_region.polyFile()); 0132 // arguments << monavDir().absoluteFilePath() + QLatin1String("/marble.kml"); 0133 // QProcess poly2kml; 0134 // poly2kml.start("poly2kml", arguments); 0135 // poly2kml.waitForFinished(1000 * 60 * 30); // wait up to half an hour for poly2kml to convert the data 0136 // if (poly2kml.exitStatus() == QProcess::NormalExit && poly2kml.exitCode() == 0) { 0137 // qDebug() << "Processed kml file for marble"; 0138 // return true; 0139 // } else { 0140 // qDebug() << "poly2kml exiting with status " << poly2kml.exitCode(); 0141 // changeStatus(Error, "Error creating marble.kml: " + poly2kml.readAllStandardError()); 0142 // return false; 0143 // } 0144 //} 0145 0146 bool Job::monav() 0147 { 0148 QString const status = QString("Generating offline routing map from %1 (%2).").arg(osmFile().fileName()).arg(Region::fileSize(osmFile())); 0149 changeStatus(Routing, status); 0150 QStringList arguments; 0151 arguments << QLatin1String("-s=") + m_monavSettings; 0152 arguments << QLatin1String("-i=") + osmFile().absoluteFilePath(); 0153 arguments << QLatin1String("-o=") + monavDir().absoluteFilePath(); 0154 arguments << "-pi=OpenStreetMap Importer" << "-pro=Contraction Hierarchies"; 0155 arguments << "-pg=GPS Grid" << "-di"; 0156 arguments << QLatin1String("-dro=") + m_transport; 0157 arguments << QLatin1String("--profile=") + m_profile; 0158 arguments << "-dd" /*<< "-dc"*/; 0159 QProcess monav; 0160 monav.start("monav-preprocessor", arguments); 0161 monav.waitForFinished(1000 * 60 * 60 * 6); // wait up to 6 hours for monav to convert the data 0162 if (monav.exitStatus() == QProcess::NormalExit && monav.exitCode() == 0) { 0163 qDebug() << "Processed osm file for monav"; 0164 } else { 0165 qDebug() << "monav exiting with status " << monav.exitCode(); 0166 changeStatus(Error, QLatin1String("Routing map conversion failed: ") + monav.readAllStandardError()); 0167 return false; 0168 } 0169 0170 QFile pluginsFile(monavDir().absoluteFilePath() + QLatin1String("/plugins.ini")); 0171 pluginsFile.open(QFile::WriteOnly | QFile::Truncate); 0172 QTextStream pluginsStream(&pluginsFile); 0173 pluginsStream << "[General]\nrouter=Contraction Hierarchies\nrenderer=Mapnik Renderer\ngpsLookup=GPS Grid\naddressLookup=Unicode Tournament Trie\n"; 0174 pluginsFile.close(); 0175 0176 QFileInfo subdir = QFileInfo(monavDir().absoluteFilePath() + QLatin1String("/routing_") + m_transport.toLower()); 0177 if (subdir.exists() && subdir.isDir()) { 0178 QFileInfoList files = QDir(subdir.absoluteFilePath()).entryInfoList(QDir::Files); 0179 for(const QFileInfo &file: files) { 0180 if (!QFile::rename(file.absoluteFilePath(), monavDir().absoluteFilePath() + QLatin1Char('/') + file.fileName())) { 0181 changeStatus(Error, "Unable to move monav files to target directory."); 0182 return false; 0183 } 0184 } 0185 QDir("/").rmdir(subdir.absoluteFilePath()); 0186 } else { 0187 changeStatus(Error, "Unable to find files created by monav"); 0188 return false; 0189 } 0190 0191 return true; 0192 } 0193 0194 bool Job::search() 0195 { 0196 QString const status = QString("Generating offline search database from %1 (%2).").arg(osmFile().fileName()).arg(Region::fileSize(osmFile())); 0197 changeStatus(Search, status); 0198 QStringList arguments; 0199 arguments << "--name" << m_region.name(); 0200 arguments << "--version" << "0.3"; 0201 arguments << "--date" << QDateTime::currentDateTime().toString("MM/dd/yy"); 0202 arguments << "--transport" << m_transport; 0203 arguments << "--payload" << targetFile().fileName(); 0204 arguments << osmFile().absoluteFilePath(); 0205 arguments << searchFile().absoluteFilePath(); 0206 QFileInfo kmlFile(monavDir().absoluteFilePath() + QLatin1String("/marble.kml")); 0207 arguments << kmlFile.absoluteFilePath(); 0208 QProcess osmAddresses; 0209 osmAddresses.start("osm-addresses", arguments); 0210 osmAddresses.waitForFinished(1000 * 60 * 60 * 18); // wait up to 18 hours for osm-addresses to convert the data 0211 if (osmAddresses.exitStatus() == QProcess::NormalExit && osmAddresses.exitCode() == 0) { 0212 searchFile().refresh(); 0213 if (!searchFile().exists()) { 0214 qDebug() << "osm-addresses did not create the .sqlite file"; 0215 changeStatus(Error, "Unknown error when creating the search database"); 0216 return false; 0217 } else if (searchFile().size() < 8000) { 0218 qDebug() << "The .sqlite database has a suspiciously small size."; 0219 changeStatus(Error, "Search database is too small. Too little memory?"); 0220 return false; 0221 } 0222 0223 kmlFile.refresh(); 0224 if (!kmlFile.exists()) { 0225 qDebug() << "File marble.kml has not been generated."; 0226 changeStatus(Error, "Failed to generate marble.kml. Too little memory?"); 0227 return false; 0228 } 0229 0230 return true; 0231 } else { 0232 qDebug() << "osm-addresses exiting with status " << osmAddresses.exitCode(); 0233 changeStatus(Error, QLatin1String("Error creating search database: ") + osmAddresses.readAllStandardError()); 0234 return false; 0235 } 0236 } 0237 0238 bool Job::package() 0239 { 0240 changeStatus(Packaging, "Creating archive."); 0241 QStringList arguments; 0242 arguments << "czf" << targetFile().absoluteFilePath() << "earth/monav/" << "earth/placemarks"; 0243 QProcess tar; 0244 tar.setWorkingDirectory(m_parameters.base().absolutePath() + QLatin1String("/data/") + m_region.id()); 0245 tar.start("tar", arguments); 0246 tar.waitForFinished(1000 * 60 * 60); // wait up to 1 hour for tar to package things 0247 if (tar.exitStatus() == QProcess::NormalExit && tar.exitCode() == 0) { 0248 qDebug() << "Packaged tar file"; 0249 return true; 0250 } else { 0251 changeStatus(Error, QLatin1String("Packaging failed: ") + tar.readAllStandardError()); 0252 return false; 0253 } 0254 } 0255 0256 bool Job::upload() 0257 { 0258 changeStatus(Uploading, "Uploading file"); 0259 if (targetFile().exists()) { 0260 Upload::instance().uploadAndDelete(m_region, targetFile(), m_transport); 0261 return true; 0262 } 0263 0264 changeStatus(Error, "Target file does not exist."); 0265 return false; 0266 } 0267 0268 bool Job::cleanup() 0269 { 0270 if (!m_parameters.cacheData()) { 0271 QFile::remove(osmFile().absoluteFilePath()); 0272 } 0273 0274 QFileInfo subdir = QFileInfo(monavDir().absoluteFilePath()); 0275 if (subdir.exists() && subdir.isDir()) { 0276 QFileInfoList files = QDir(subdir.absoluteFilePath()).entryInfoList(QDir::Files); 0277 for(const QFileInfo &file: files) { 0278 QFile::remove(file.absoluteFilePath()); 0279 } 0280 } 0281 0282 QFile::remove(searchFile().absoluteFilePath()); 0283 return true; 0284 } 0285 0286 QFileInfo Job::osmFile() 0287 { 0288 m_parameters.base().mkdir("download"); 0289 QFileInfo result(m_parameters.base(), QLatin1String("download/") + m_region.id() + QLatin1String(".osm.pbf")); 0290 return result; 0291 } 0292 0293 QFileInfo Job::monavDir() 0294 { 0295 QString const subdir = QLatin1String("data/") + m_region.id() + QLatin1String("/earth/monav/") + m_transport.toLower() + QLatin1Char('/') + m_region.path(); 0296 m_parameters.base().mkpath(subdir); 0297 QFileInfo result(m_parameters.base(), subdir); 0298 return result; 0299 } 0300 0301 QFileInfo Job::targetFile() 0302 { 0303 m_parameters.base().mkdir("finished"); 0304 QFileInfo result(m_parameters.base(), QLatin1String("finished/") + m_region.id() + QLatin1Char('_') + m_transport.toLower() + QLatin1String(".tar.gz")); 0305 return result; 0306 } 0307 0308 QFileInfo Job::searchFile() 0309 { 0310 QString const subdir = QLatin1String("data/") + m_region.id() + QLatin1String("/earth/placemarks/") + QFileInfo(m_region.path()).path(); 0311 m_parameters.base().mkpath(subdir); 0312 QFileInfo result(m_parameters.base(), subdir + QLatin1Char('/') + m_region.id() + QLatin1String(".sqlite")); 0313 return result; 0314 } 0315 0316 #include "moc_job.cpp"