23 #include "ip2cupdater.h" 25 #include <QCryptographicHash> 27 #include <QNetworkAccessManager> 28 #include <QTemporaryFile> 34 IP2CUpdater::IP2CUpdater(QObject *parent)
37 pCurrentNetworkReply =
nullptr;
38 pNetworkAccessManager =
new QNetworkAccessManager();
41 IP2CUpdater::~IP2CUpdater()
45 if (pNetworkAccessManager !=
nullptr)
46 pNetworkAccessManager->deleteLater();
49 void IP2CUpdater::abort()
51 if (pCurrentNetworkReply !=
nullptr)
53 pCurrentNetworkReply->disconnect();
54 pCurrentNetworkReply->abort();
55 pCurrentNetworkReply->deleteLater();
57 pCurrentNetworkReply =
nullptr;
60 void IP2CUpdater::checksumDownloadFinished()
62 if (handleRedirect(*pCurrentNetworkReply, SLOT(checksumDownloadFinished())))
65 if (pCurrentNetworkReply->error() != QNetworkReply::NoError)
67 gLog << tr(
"IP2C checksum check network error: %1").arg(pCurrentNetworkReply->errorString());
69 emit updateNeeded(UpdateCheckError);
73 QByteArray remoteMd5 = pCurrentNetworkReply->readAll();
74 remoteMd5 = remoteMd5.trimmed();
76 pCurrentNetworkReply->deleteLater();
77 pCurrentNetworkReply =
nullptr;
80 QFile file(this->lastAsyncCallPath);
81 if (file.open(QIODevice::ReadOnly))
83 localMd5 = QCryptographicHash::hash(file.readAll(), QCryptographicHash::Md5);
84 localMd5 = localMd5.toHex().toLower();
87 gLog << tr(
"Comparing IP2C hashes: local = %1, remote = %2").arg(
88 QString(localMd5)).arg(QString(remoteMd5));
89 bool needed = localMd5 != remoteMd5;
91 gLog << tr(
"IP2C update needed.");
92 emit updateNeeded(needed ? UpdateNeeded : UpToDate);
95 const QUrl IP2CUpdater::dbChecksumUrl()
97 return QUrl(
"https://doomseeker.drdteam.org/ip2c/md5");
100 const QUrl IP2CUpdater::dbDownloadUrl()
102 return QUrl(
"https://doomseeker.drdteam.org/ip2c/geolite2.gz");
105 void IP2CUpdater::downloadDatabase(
const QString &savePath)
107 this->lastAsyncCallPath = savePath;
108 get(dbDownloadUrl(), SLOT(downloadFinished()));
111 void IP2CUpdater::downloadFinished()
113 if (handleRedirect(*pCurrentNetworkReply, SLOT(downloadFinished())))
116 QByteArray data = pCurrentNetworkReply->readAll();
118 pCurrentNetworkReply->deleteLater();
119 pCurrentNetworkReply =
nullptr;
122 QTemporaryFile tmpFile;
127 QString tmpFilePath = tmpFile.fileName();
129 QByteArray uncompressedData;
130 gzFile gz = gzopen(tmpFilePath.toUtf8().constData(),
"rb");
133 static const int CHUNK_SIZE = 128 * 1024;
134 char chunk[CHUNK_SIZE];
136 while ((bytesRead = gzread(gz, chunk, CHUNK_SIZE)) != 0)
138 uncompressedData.append(QByteArray(chunk, bytesRead));
142 retrievedData = uncompressedData;
146 emit databaseDownloadFinished(retrievedData);
149 bool IP2CUpdater::handleRedirect(QNetworkReply &reply,
const char *finishedSlot)
151 QUrl possibleRedirectUrl = reply.attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
152 QUrl url = reply.request().url();
153 if (!possibleRedirectUrl.isEmpty() && possibleRedirectUrl != url)
156 if (possibleRedirectUrl.isRelative())
157 possibleRedirectUrl = url.resolved(possibleRedirectUrl);
158 get(possibleRedirectUrl, finishedSlot);
164 void IP2CUpdater::get(
const QUrl &url,
const char *finishedSlot)
167 retrievedData.clear();
169 QNetworkRequest request;
173 pCurrentNetworkReply = pNetworkAccessManager->get(request);
174 this->connect(pCurrentNetworkReply, SIGNAL(downloadProgress(qint64,qint64)),
175 SIGNAL(downloadProgress(qint64,qint64)));
176 this->connect(pCurrentNetworkReply, SIGNAL(finished()), finishedSlot);
181 rollbackData.clear();
182 QFile file(databasePath);
183 if (file.open(QIODevice::ReadOnly))
185 rollbackData = file.readAll();
192 bool IP2CUpdater::isWorking()
const 194 return pCurrentNetworkReply !=
nullptr;
199 QFile file(filePath);
202 emit updateNeeded(UpdateNeeded);
206 this->lastAsyncCallPath = filePath;
207 gLog << tr(
"Checking if IP2C database at '%1' needs updating.").arg(filePath);
208 get(dbChecksumUrl(), SLOT(checksumDownloadFinished()));
213 bool bSuccess = save(rollbackData, savePath);
214 rollbackData.clear();
219 bool IP2CUpdater::save(
const QByteArray &saveWhat,
const QString &savePath)
221 if (saveWhat.isEmpty())
224 QFile file(savePath);
225 if (file.open(QIODevice::WriteOnly))
227 file.write(saveWhat);
236 return save(retrievedData, savePath);
bool saveDownloadedData(const QString &savePath)
Saves recently downloaded data to the specified file.
static QString userAgent()
WWW User Agent used for HTTP communications.
bool getRollbackData(const QString &databasePath)
Obtains rollback data from specified file.
void needsUpdate(const QString &filePath)
Checks if IP2C file must be updated.
bool rollback(const QString &savePath)
Saves rollback data to the specified file. This data must be first obtained through the getRollbackDa...