Compare commits

..

10 Commits

Author SHA1 Message Date
Mike Tzou
d8cb552804 Merge pull request #12159 from thalieht/backportflags
Backport #12014: Use IP geolocation database by DB-IP instead of MaxMind
2020-03-13 18:38:35 +08:00
sledgehammer999
304e831b0c Use IP geolocation database by DB-IP instead of MaxMind 2020-03-12 01:05:44 +02:00
Mike Tzou
f16d219646 Merge pull request #11778 from FranciscoPombal/v4_1_x
WebUI: backport #11635 and #11756 to v4_1_x
2019-12-30 10:13:35 +08:00
FranciscoPombal
22b0160eaa WebUI: fix populating statistics window
Closes #11665
2019-12-29 14:19:57 +00:00
FranciscoPombal
d4f49c3666 WebUI: Prevent excessive sync requests
Don't sync main data if a request to do so is already in progress.

This prevents piling up of requests and bogging down slow/busy machines, since the current implementation of `/api/v2/sync/maindata` is very computationally intensive, especially with lots of torrents.

Everything gets updated on the next scheduled request anyway (via the timeout mechanism).
2019-12-29 14:19:27 +00:00
Mike Tzou
0b055d8fef Merge pull request #11472 from thalieht/backport_pausechecking
Backport
2019-11-19 12:05:31 +08:00
thalieht
21595fca9c Reallow to force recheck torrents that aren't fully started 2019-11-18 16:02:40 +02:00
thalieht
64ac48ee11 Reallow to pause checking torrents 2019-11-09 14:08:47 +02:00
Mike Tzou
5d98721593 Merge pull request #11437 from Chocobo1/backport
Fix integer narrowing on x86 (backport)
2019-11-02 11:58:50 +08:00
Chocobo1
598159552e Fix integer narrowing on x86
The f_type is an alias to `int` on 32-bit system and the switch cases
uses `unsigned int`.

Closes #11427.
2019-11-01 10:49:43 +08:00
11 changed files with 162 additions and 125 deletions

View File

@@ -13,8 +13,7 @@ It aims to be a good alternative to all other bittorrent clients
out there. qBittorrent is fast, stable and provides unicode
support as well as many features.
This product includes GeoLite data created by MaxMind, available from
https://www.maxmind.com/
The free [IP to Country Lite database](https://db-ip.com/db/download/ip-to-country-lite) by [DB-IP](https://db-ip.com/) is used for resolving the countries of peers. The database is licensed under the [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/).
### Installation:
For installation, follow the instructions from INSTALL file, but simple:

View File

@@ -1273,17 +1273,18 @@ void TorrentHandle::forceDHTAnnounce()
void TorrentHandle::forceRecheck()
{
if (m_startupState != Started) return;
if (!hasMetadata()) return;
m_nativeHandle.force_recheck();
m_unchecked = false;
if (isPaused()) {
if ((m_startupState != Started) || isPaused()) {
m_nativeHandle.stop_when_ready(true);
m_nativeHandle.auto_managed(true);
m_pauseWhenReady = true;
}
if ((m_startupState == Started) && isPaused())
m_pauseWhenReady = true;
}
void TorrentHandle::setSequentialDownload(bool b)
@@ -1351,30 +1352,27 @@ void TorrentHandle::toggleFirstLastPiecePriority()
void TorrentHandle::pause()
{
if (m_startupState != Started) return;
if (m_pauseWhenReady) return;
if (isChecking()) {
m_pauseWhenReady = true;
return;
}
if (isPaused()) return;
m_nativeHandle.auto_managed(false);
m_nativeHandle.pause();
if (m_startupState == Started) {
if (m_pauseWhenReady) {
m_nativeHandle.stop_when_ready(false);
m_pauseWhenReady = false;
}
// Libtorrent doesn't emit a torrent_paused_alert when the
// torrent is queued (no I/O)
// We test on the cached m_nativeStatus
if (isQueued())
m_session->handleTorrentPaused(this);
}
}
void TorrentHandle::resume(bool forced)
{
if (m_startupState != Started) return;
m_pauseWhenReady = false;
resume_impl(forced);
}

View File

@@ -44,10 +44,9 @@
#include "downloadmanager.h"
#include "private/geoipdatabase.h"
static const char DATABASE_URL[] = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz";
static const char GEOIP_FOLDER[] = "GeoIP";
static const char GEOIP_FILENAME[] = "GeoLite2-Country.mmdb";
static const int UPDATE_INTERVAL = 30; // Days between database updates
static const QString DATABASE_URL = QStringLiteral("https://download.db-ip.com/free/dbip-country-lite-%1.mmdb.gz");
static const char GEODB_FOLDER[] = "GeoDB";
static const char GEODB_FILENAME[] = "dbip-country-lite.mmdb";
using namespace Net;
@@ -96,29 +95,45 @@ void GeoIPManager::loadDatabase()
}
QString filepath = Utils::Fs::expandPathAbs(
QString("%1%2/%3").arg(specialFolderLocation(SpecialFolder::Data), GEOIP_FOLDER, GEOIP_FILENAME));
QString("%1%2/%3").arg(specialFolderLocation(SpecialFolder::Data), GEODB_FOLDER, GEODB_FILENAME));
QString error;
m_geoIPDatabase = GeoIPDatabase::load(filepath, error);
if (m_geoIPDatabase)
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.")
Logger::instance()->addMessage(tr("IP geolocation database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type(), m_geoIPDatabase->buildEpoch().toString()),
Log::INFO);
else
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING);
Logger::instance()->addMessage(tr("Couldn't load IP geolocation database. Reason: %1").arg(error), Log::WARNING);
manageDatabaseUpdate();
}
void GeoIPManager::manageDatabaseUpdate()
{
if (!m_geoIPDatabase || (m_geoIPDatabase->buildEpoch().daysTo(QDateTime::currentDateTimeUtc()) >= UPDATE_INTERVAL))
const auto expired = [](const QDateTime &testDateTime)
{
const QDate testDate = testDateTime.date();
const QDate curDate = QDateTime::currentDateTimeUtc().date();
if ((testDate.year() < curDate.year()) && (curDate.day() > 1))
return true;
if ((testDate.month() < curDate.month()) && (curDate.day() > 1))
return true;
return false;
};
if (!m_geoIPDatabase || expired(m_geoIPDatabase->buildEpoch()))
downloadDatabaseFile();
}
void GeoIPManager::downloadDatabaseFile()
{
DownloadHandler *handler = DownloadManager::instance()->download({DATABASE_URL});
const QDate curDate = QDateTime::currentDateTimeUtc().date();
const QString curUrl = DATABASE_URL.arg(curDate.toString("yyyy-MM"));
DownloadHandler *handler = DownloadManager::instance()->download({curUrl});
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &GeoIPManager::downloadFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &GeoIPManager::downloadFailed);
@@ -420,7 +435,7 @@ void GeoIPManager::downloadFinished(const QString &url, QByteArray data)
bool ok = false;
data = Utils::Gzip::decompress(data, &ok);
if (!ok) {
Logger::instance()->addMessage(tr("Could not decompress GeoIP database file."), Log::WARNING);
LogMsg(tr("Could not decompress IP geolocation database file."), Log::WARNING);
return;
}
@@ -431,28 +446,25 @@ void GeoIPManager::downloadFinished(const QString &url, QByteArray data)
if (m_geoIPDatabase)
delete m_geoIPDatabase;
m_geoIPDatabase = geoIPDatabase;
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.")
LogMsg(tr("IP geolocation database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type(), m_geoIPDatabase->buildEpoch().toString()),
Log::INFO);
QString targetPath = Utils::Fs::expandPathAbs(
specialFolderLocation(SpecialFolder::Data) + GEOIP_FOLDER);
const QString targetPath = Utils::Fs::expandPathAbs(
specialFolderLocation(SpecialFolder::Data) + GEODB_FOLDER);
if (!QDir(targetPath).exists())
QDir().mkpath(targetPath);
QFile targetFile(QString("%1/%2").arg(targetPath, GEOIP_FILENAME));
if (!targetFile.open(QFile::WriteOnly) || (targetFile.write(data) == -1)) {
Logger::instance()->addMessage(
tr("Couldn't save downloaded GeoIP database file."), Log::WARNING);
}
else {
Logger::instance()->addMessage(tr("Successfully updated GeoIP database."), Log::INFO);
}
QFile targetFile(QString("%1/%2").arg(targetPath, GEODB_FILENAME));
if (!targetFile.open(QFile::WriteOnly) || (targetFile.write(data) == -1))
LogMsg(tr("Couldn't save downloaded IP geolocation database file."), Log::WARNING);
else
LogMsg(tr("Successfully updated IP geolocation database."), Log::INFO);
}
else {
delete geoIPDatabase;
}
}
else {
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING);
LogMsg(tr("Couldn't load IP geolocation database. Reason: %1").arg(error), Log::WARNING);
}
}

View File

@@ -38,7 +38,6 @@
namespace
{
const qint32 MAX_FILE_SIZE = 67108864; // 64MB
const char DB_TYPE[] = "GeoLite2-Country";
const quint32 MAX_METADATA_SIZE = 131072; // 128KB
const char METADATA_BEGIN_MARK[] = "\xab\xcd\xefMaxMind.com";
const char DATA_SECTION_SEPARATOR[16] = {0};
@@ -144,7 +143,7 @@ GeoIPDatabase::~GeoIPDatabase()
QString GeoIPDatabase::type() const
{
return DB_TYPE;
return m_dbType;
}
quint16 GeoIPDatabase::ipVersion() const
@@ -255,11 +254,7 @@ bool GeoIPDatabase::parseMetadata(const QVariantHash &metadata, QString &error)
m_indexSize = m_nodeCount * m_nodeSize;
CHECK_METADATA_REQ(database_type, QString);
QString dbType = metadata.value("database_type").toString();
if (dbType != DB_TYPE) {
error = tr("Invalid database type: %1").arg(dbType);
return false;
}
m_dbType = metadata.value("database_type").toString();
CHECK_METADATA_REQ(build_epoch, ULongLong);
m_buildEpoch = QDateTime::fromTime_t(metadata.value("build_epoch").toULongLong());
@@ -272,7 +267,7 @@ bool GeoIPDatabase::parseMetadata(const QVariantHash &metadata, QString &error)
bool GeoIPDatabase::loadDB(QString &error) const
{
qDebug() << "Parsing MaxMindDB index tree...";
qDebug() << "Parsing IP geolocation database index tree...";
const int nodeSize = m_recordSize / 4; // in bytes
const int indexSize = m_nodeCount * nodeSize;

View File

@@ -93,6 +93,7 @@ private:
int m_indexSize;
int m_recordBytes;
QDateTime m_buildEpoch;
QString m_dbType;
// Search data
mutable QHash<quint32, QString> m_countries;
quint32 m_size;

View File

@@ -354,7 +354,7 @@ bool Utils::Fs::isNetworkFileSystem(const QString &path)
// Magic number references:
// 1. /usr/include/linux/magic.h
// 2. https://github.com/coreutils/coreutils/blob/master/src/stat.c
switch (buf.f_type) {
switch (static_cast<unsigned int>(buf.f_type)) {
case 0xFF534D42: // CIFS_MAGIC_NUMBER
case 0x6969: // NFS_SUPER_MAGIC
case 0x517B: // SMB_SUPER_MAGIC

View File

@@ -102,6 +102,14 @@ public:
labelLibtVer->setText(Utils::Misc::libtorrentVersionString());
labelBoostVer->setText(Utils::Misc::boostVersionString());
const QString DBIPText = QString(
"<html><head/><body><p>"
"%1"
" (<a href=\"https://db-ip.com/\">https://db-ip.com/</a>)</p></body></html>")
.arg(tr("The free IP to Country Lite database by DB-IP is used for resolving the countries of peers. "
"The database is licensed under the Creative Commons Attribution 4.0 International License"));
labelDBIP->setText(DBIPText);
Utils::Gui::resize(this);
show();
}

View File

@@ -314,11 +314,11 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="librariesTab">
<widget class="QWidget" name="SoftwareUsedTab">
<attribute name="title">
<string>Libraries</string>
<string>Software Used</string>
</attribute>
<layout class="QVBoxLayout" name="librariesTabLayout">
<layout class="QVBoxLayout" name="SoftwareUsedTabLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
@@ -430,6 +430,22 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelDBIP">
<property name="text">
<string notr="true">DB-IP license text</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">

View File

@@ -419,7 +419,7 @@ void AdvancedSettings::loadAdvancedSettings()
addRow(LIST_REFRESH, tr("Transfer list refresh interval"), &spinBoxListRefresh);
// Resolve Peer countries
checkBoxResolveCountries.setChecked(pref->resolvePeerCountries());
addRow(RESOLVE_COUNTRIES, tr("Resolve peer countries (GeoIP)"), &checkBoxResolveCountries);
addRow(RESOLVE_COUNTRIES, tr("Resolve peer countries"), &checkBoxResolveCountries);
// Resolve peer hosts
checkBoxResolveHosts.setChecked(pref->resolvePeerHostNames());
addRow(RESOLVE_HOSTS, tr("Resolve peer host names"), &checkBoxResolveHosts);

View File

@@ -41,6 +41,7 @@ var queueing_enabled = true;
var serverSyncMainDataInterval = 1500;
var customSyncMainDataInterval = null;
let syncRequestInProgress = false;
var clipboardEvent;
var CATEGORIES_ALL = 1;
@@ -334,7 +335,7 @@ window.addEvent('load', function() {
var syncMainData = function() {
var url = new URI('api/v2/sync/maindata');
url.setData('rid', syncMainDataLastResponseId);
new Request.JSON({
const request = new Request.JSON({
url: url,
noCache: true,
method: 'get',
@@ -342,8 +343,8 @@ window.addEvent('load', function() {
var errorDiv = $('error_div');
if (errorDiv)
errorDiv.set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]');
clearTimeout(syncMainDataTimer);
syncMainDataTimer = syncMainData.delay(2000);
syncRequestInProgress = false;
syncData(2000);
},
onSuccess: function(response) {
$('error_div').set('html', '');
@@ -426,18 +427,26 @@ window.addEvent('load', function() {
// re-select previously selected rows
torrentsTable.reselectRows(torrentsTableSelectedRows);
}
clearTimeout(syncMainDataTimer);
syncMainDataTimer = syncMainData.delay(getSyncMainDataInterval());
syncRequestInProgress = false;
syncData(getSyncMainDataInterval())
}
}).send();
});
syncRequestInProgress = true;
request.send();
};
updateMainData = function() {
torrentsTable.updateTable();
clearTimeout(syncMainDataTimer);
syncMainDataTimer = syncMainData.delay(100);
syncData(100);
};
const syncData = function(delay) {
if (!syncRequestInProgress){
clearTimeout(syncMainDataTimer);
syncMainDataTimer = syncMainData.delay(delay);
}
}
var processServerState = function() {
var transfer_info = friendlyUnit(serverState.dl_info_speed, true);
if (serverState.dl_rate_limit > 0)
@@ -459,7 +468,7 @@ window.addEvent('load', function() {
$('DHTNodes').set('html', 'QBT_TR(DHT: %1 nodes)QBT_TR[CONTEXT=StatusBar]'.replace("%1", serverState.dht_nodes));
// Statistics dialog
if (document.getElementById("statisticspage")) {
if (document.getElementById("statisticsContent")) {
$('AlltimeDL').set('html', friendlyUnit(serverState.alltime_dl, false));
$('AlltimeUL').set('html', friendlyUnit(serverState.alltime_ul, false));
$('TotalWastedSession').set('html', friendlyUnit(serverState.total_wasted_session, false));
@@ -607,8 +616,7 @@ window.addEvent('load', function() {
$("mainColumn").removeClass("invisible");
customSyncMainDataInterval = null;
clearTimeout(syncMainDataTimer);
syncMainDataTimer = syncMainData.delay(100);
syncData(100);
hideSearchTab();
};

View File

@@ -1,5 +1,6 @@
<h3>QBT_TR(User statistics)QBT_TR[CONTEXT=StatsDialog]</h3>
<table style="width:100%">
<div id="statisticsContent">
<h3>QBT_TR(User statistics)QBT_TR[CONTEXT=StatsDialog]</h3>
<table style="width:100%">
<tr>
<td>QBT_TR(All-time upload:)QBT_TR[CONTEXT=StatsDialog]</td>
<td id="AlltimeUL" class="statisticsValue"></td>
@@ -20,10 +21,9 @@
<td>QBT_TR(Connected peers:)QBT_TR[CONTEXT=StatsDialog]</td>
<td id="TotalPeerConnections" class="statisticsValue"></td>
</tr>
</table>
<h3>QBT_TR(Cache statistics)QBT_TR[CONTEXT=StatsDialog]</h3>
<table style="width:100%">
</table>
<h3>QBT_TR(Cache statistics)QBT_TR[CONTEXT=StatsDialog]</h3>
<table style="width:100%">
<tr>
<td>QBT_TR(Read cache hits:)QBT_TR[CONTEXT=StatsDialog]</td>
<td id="ReadCacheHits" class="statisticsValue"></td>
@@ -32,10 +32,9 @@
<td>QBT_TR(Total buffer size:)QBT_TR[CONTEXT=StatsDialog]</td>
<td id="TotalBuffersSize" class="statisticsValue"></td>
</tr>
</table>
<h3>QBT_TR(Performance statistics)QBT_TR[CONTEXT=StatsDialog]</h3>
<table style="width:100%">
</table>
<h3>QBT_TR(Performance statistics)QBT_TR[CONTEXT=StatsDialog]</h3>
<table style="width:100%">
<tr>
<td>QBT_TR(Write cache overload:)QBT_TR[CONTEXT=StatsDialog]</td>
<td id="WriteCacheOverload" class="statisticsValue"></td>
@@ -56,4 +55,5 @@
<td>QBT_TR(Total queued size:)QBT_TR[CONTEXT=StatsDialog]</td>
<td id="TotalQueuedSize" class="statisticsValue"></td>
</tr>
</table>
</table>
</div>