Implemented share limit by seeding time

This commit is contained in:
Naikel Aparicio
2016-02-07 13:01:50 -04:30
parent f4a6242711
commit 9ba00d7035
16 changed files with 661 additions and 162 deletions

View File

@@ -46,7 +46,7 @@ namespace BitTorrent
TriStateBool addForced;
TriStateBool addPaused;
QVector<int> filePriorities; // used if TorrentInfo is set
bool ignoreShareRatio = false;
bool ignoreShareLimits = false;
bool skipChecking = false;
TriStateBool createSubfolder;
};

View File

@@ -235,6 +235,7 @@ Session::Session(QObject *parent)
, m_isAddTrackersEnabled(BITTORRENT_SESSION_KEY("AddTrackersEnabled"), false)
, m_additionalTrackers(BITTORRENT_SESSION_KEY("AdditionalTrackers"))
, m_globalMaxRatio(BITTORRENT_SESSION_KEY("GlobalMaxRatio"), -1, [](qreal r) { return r < 0 ? -1. : r;})
, m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY("GlobalMaxSeedingMinutes"), -1, lowerLimited(-1))
, m_isAddTorrentPaused(BITTORRENT_SESSION_KEY("AddTorrentPaused"), false)
, m_isCreateTorrentSubfolder(BITTORRENT_SESSION_KEY("CreateTorrentSubfolder"), true)
, m_isAppendExtensionEnabled(BITTORRENT_SESSION_KEY("AddExtensionToIncompleteFiles"), false)
@@ -287,9 +288,9 @@ Session::Session(QObject *parent)
initResumeFolder();
m_bigRatioTimer = new QTimer(this);
m_bigRatioTimer->setInterval(10000);
connect(m_bigRatioTimer, SIGNAL(timeout()), SLOT(processBigRatios()));
m_seedingLimitTimer = new QTimer(this);
m_seedingLimitTimer->setInterval(10000);
connect(m_seedingLimitTimer, SIGNAL(timeout()), SLOT(processShareLimits()));
// Set severity level of libtorrent session
int alertMask = libt::alert::error_notification
@@ -411,7 +412,7 @@ Session::Session(QObject *parent)
m_statistics = new Statistics(this);
updateRatioTimer();
updateSeedingLimitTimer();
populateAdditionalTrackers();
enableTracker(isTrackerEnabled());
@@ -800,7 +801,23 @@ void Session::setGlobalMaxRatio(qreal ratio)
if (ratio != globalMaxRatio()) {
m_globalMaxRatio = ratio;
updateRatioTimer();
updateSeedingLimitTimer();
}
}
int Session::globalMaxSeedingMinutes() const
{
return m_globalMaxSeedingMinutes;
}
void Session::setGlobalMaxSeedingMinutes(int minutes)
{
if (minutes < 0)
minutes = -1;
if (minutes != globalMaxSeedingMinutes()) {
m_globalMaxSeedingMinutes = minutes;
updateSeedingLimitTimer();
}
}
@@ -1415,36 +1432,56 @@ void Session::populateAdditionalTrackers()
}
}
void Session::processBigRatios()
void Session::processShareLimits()
{
qDebug("Process big ratios...");
qDebug("Processing share limits...");
qreal globalMaxRatio = this->globalMaxRatio();
foreach (TorrentHandle *const torrent, m_torrents) {
if (torrent->isSeed()
&& (torrent->ratioLimit() != TorrentHandle::NO_RATIO_LIMIT)
&& !torrent->isForced()) {
const qreal ratio = torrent->realRatio();
qreal ratioLimit = torrent->ratioLimit();
if (ratioLimit == TorrentHandle::USE_GLOBAL_RATIO) {
// If Global Max Ratio is really set...
ratioLimit = globalMaxRatio;
if (ratioLimit < 0) continue;
}
qDebug("Ratio: %f (limit: %f)", ratio, ratioLimit);
Q_ASSERT(ratioLimit >= 0.f);
if (torrent->isSeed() && !torrent->isForced()) {
if (torrent->ratioLimit() != TorrentHandle::NO_RATIO_LIMIT) {
const qreal ratio = torrent->realRatio();
qreal ratioLimit = torrent->ratioLimit();
if (ratioLimit == TorrentHandle::USE_GLOBAL_RATIO)
// If Global Max Ratio is really set...
ratioLimit = globalMaxRatio();
if ((ratio <= TorrentHandle::MAX_RATIO) && (ratio >= ratioLimit)) {
Logger* const logger = Logger::instance();
if (maxRatioAction() == Remove) {
logger->addMessage(tr("'%1' reached the maximum ratio you set. Removing...").arg(torrent->name()));
deleteTorrent(torrent->hash());
if (ratioLimit >= 0) {
qDebug("Ratio: %f (limit: %f)", ratio, ratioLimit);
if ((ratio <= TorrentHandle::MAX_RATIO) && (ratio >= ratioLimit)) {
Logger* const logger = Logger::instance();
if (m_maxRatioAction == Remove) {
deleteTorrent(torrent->hash());
logger->addMessage(tr("'%1' reached the maximum ratio you set. Removed.").arg(torrent->name()));
}
else if (!torrent->isPaused()) {
torrent->pause();
logger->addMessage(tr("'%1' reached the maximum ratio you set. Paused.").arg(torrent->name()));
}
}
}
else {
// Pause it
if (!torrent->isPaused()) {
logger->addMessage(tr("'%1' reached the maximum ratio you set. Pausing...").arg(torrent->name()));
torrent->pause();
}
if (torrent->seedingTimeLimit() != TorrentHandle::NO_SEEDING_TIME_LIMIT) {
const int seedingTimeInMinutes = torrent->seedingTime() / 60;
int seedingTimeLimit = torrent->seedingTimeLimit();
if (seedingTimeLimit == TorrentHandle::USE_GLOBAL_SEEDING_TIME)
// If Global Seeding Time Limit is really set...
seedingTimeLimit = globalMaxSeedingMinutes();
if (seedingTimeLimit >= 0) {
qDebug("Seeding Time: %d (limit: %d)", seedingTimeInMinutes, seedingTimeLimit);
if ((seedingTimeInMinutes <= TorrentHandle::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit)) {
Logger* const logger = Logger::instance();
if (m_maxRatioAction == Remove) {
deleteTorrent(torrent->hash());
logger->addMessage(tr("'%1' reached the maximum seeding time you set. Removed.").arg(torrent->name()));
}
else if (!torrent->isPaused()) {
torrent->pause();
logger->addMessage(tr("'%1' reached the maximum seeding time you set. Paused.").arg(torrent->name()));
}
}
}
}
@@ -2926,21 +2963,22 @@ bool Session::isKnownTorrent(const InfoHash &hash) const
|| m_loadedMetadata.contains(hash));
}
void Session::updateRatioTimer()
void Session::updateSeedingLimitTimer()
{
if ((globalMaxRatio() == -1) && !hasPerTorrentRatioLimit()) {
if (m_bigRatioTimer->isActive())
m_bigRatioTimer->stop();
if ((globalMaxRatio() == -1) && !hasPerTorrentRatioLimit()
&& (globalMaxSeedingMinutes() == TorrentHandle::NO_SEEDING_TIME_LIMIT) && !hasPerTorrentSeedingTimeLimit()) {
if (m_seedingLimitTimer->isActive())
m_seedingLimitTimer->stop();
}
else if (!m_bigRatioTimer->isActive()) {
m_bigRatioTimer->start();
else if (!m_seedingLimitTimer->isActive()) {
m_seedingLimitTimer->start();
}
}
void Session::handleTorrentRatioLimitChanged(TorrentHandle *const torrent)
void Session::handleTorrentShareLimitChanged(TorrentHandle *const torrent)
{
Q_UNUSED(torrent);
updateRatioTimer();
updateSeedingLimitTimer();
}
void Session::saveTorrentResumeData(TorrentHandle *const torrent, bool finalSave)
@@ -3119,6 +3157,14 @@ bool Session::hasPerTorrentRatioLimit() const
return false;
}
bool Session::hasPerTorrentSeedingTimeLimit() const
{
foreach (TorrentHandle *const torrent, m_torrents)
if (torrent->seedingTimeLimit() >= 0) return true;
return false;
}
void Session::initResumeFolder()
{
m_resumeFolderPath = Utils::Fs::expandPathAbs(specialFolderLocation(SpecialFolder::Data) + RESUME_FOLDER);
@@ -3528,8 +3574,9 @@ void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle)
saveTorrentResumeData(torrent);
}
if ((torrent->ratioLimit() >= 0) && !m_bigRatioTimer->isActive())
m_bigRatioTimer->start();
if (((torrent->ratioLimit() >= 0) || (torrent->seedingTimeLimit() >= 0))
&& !m_seedingLimitTimer->isActive())
m_seedingLimitTimer->start();
// Send torrent addition signal
emit torrentAdded(torrent);
@@ -3875,6 +3922,7 @@ namespace
torrentData.savePath = Profile::instance().fromPortablePath(
Utils::Fs::fromNativePath(QString::fromStdString(fast.dict_find_string_value("qBt-savePath"))));
torrentData.ratioLimit = QString::fromStdString(fast.dict_find_string_value("qBt-ratioLimit")).toDouble();
torrentData.seedingTimeLimit = fast.dict_find_int_value("qBt-seedingTimeLimit", TorrentHandle::USE_GLOBAL_SEEDING_TIME);
// **************************************************************************************
// Workaround to convert legacy label to category
// TODO: Should be removed in future

View File

@@ -245,6 +245,8 @@ namespace BitTorrent
qreal globalMaxRatio() const;
void setGlobalMaxRatio(qreal ratio);
int globalMaxSeedingMinutes() const;
void setGlobalMaxSeedingMinutes(int minutes);
bool isDHTEnabled() const;
void setDHTEnabled(bool enabled);
bool isLSDEnabled() const;
@@ -395,7 +397,7 @@ namespace BitTorrent
void bottomTorrentsPriority(const QStringList &hashes);
// TorrentHandle interface
void handleTorrentRatioLimitChanged(TorrentHandle *const torrent);
void handleTorrentShareLimitChanged(TorrentHandle *const torrent);
void handleTorrentSavePathChanged(TorrentHandle *const torrent);
void handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory);
void handleTorrentSavingModeChanged(TorrentHandle *const torrent);
@@ -455,7 +457,7 @@ namespace BitTorrent
void configureDeferred();
void readAlerts();
void refresh();
void processBigRatios();
void processShareLimits();
void generateResumeData(bool final = false);
void handleIPFilterParsed(int ruleCount);
void handleIPFilterError();
@@ -473,6 +475,7 @@ namespace BitTorrent
~Session();
bool hasPerTorrentRatioLimit() const;
bool hasPerTorrentSeedingTimeLimit() const;
void initResumeFolder();
@@ -503,7 +506,7 @@ namespace BitTorrent
const QByteArray &fastresumeData = QByteArray());
bool findIncompleteFiles(TorrentInfo &torrentInfo, QString &savePath) const;
void updateRatioTimer();
void updateSeedingLimitTimer();
void exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
void saveTorrentResumeData(TorrentHandle *const torrent, bool finalSave = false);
@@ -578,6 +581,7 @@ namespace BitTorrent
CachedSettingValue<bool> m_isAddTrackersEnabled;
CachedSettingValue<QString> m_additionalTrackers;
CachedSettingValue<qreal> m_globalMaxRatio;
CachedSettingValue<int> m_globalMaxSeedingMinutes;
CachedSettingValue<bool> m_isAddTorrentPaused;
CachedSettingValue<bool> m_isCreateTorrentSubfolder;
CachedSettingValue<bool> m_isAppendExtensionEnabled;
@@ -628,7 +632,7 @@ namespace BitTorrent
bool m_useProxy;
QTimer *m_refreshTimer;
QTimer *m_bigRatioTimer;
QTimer *m_seedingLimitTimer;
QTimer *m_resumeDataTimer;
Statistics *m_statistics;
// IP filtering

View File

@@ -81,6 +81,7 @@ AddTorrentData::AddTorrentData()
, addForced(false)
, addPaused(false)
, ratioLimit(TorrentHandle::USE_GLOBAL_RATIO)
, seedingTimeLimit(TorrentHandle::USE_GLOBAL_SEEDING_TIME)
{
}
@@ -102,7 +103,8 @@ AddTorrentData::AddTorrentData(const AddTorrentParams &params)
? Session::instance()->isAddTorrentPaused()
: params.addPaused == TriStateBool::True)
, filePriorities(params.filePriorities)
, ratioLimit(params.ignoreShareRatio ? TorrentHandle::NO_RATIO_LIMIT : TorrentHandle::USE_GLOBAL_RATIO)
, ratioLimit(params.ignoreShareLimits ? TorrentHandle::NO_RATIO_LIMIT : TorrentHandle::USE_GLOBAL_RATIO)
, seedingTimeLimit(params.ignoreShareLimits ? TorrentHandle::NO_SEEDING_TIME_LIMIT : TorrentHandle::USE_GLOBAL_SEEDING_TIME)
{
}
@@ -169,7 +171,11 @@ TorrentState::operator int() const
const qreal TorrentHandle::USE_GLOBAL_RATIO = -2.;
const qreal TorrentHandle::NO_RATIO_LIMIT = -1.;
const int TorrentHandle::USE_GLOBAL_SEEDING_TIME = -2;
const int TorrentHandle::NO_SEEDING_TIME_LIMIT = -1;
const qreal TorrentHandle::MAX_RATIO = 9999.;
const int TorrentHandle::MAX_SEEDING_TIME = 525600;
// The new libtorrent::create_torrent constructor appeared after 1.0.11 in RC_1_0
// and after 1.1.1 in RC_1_1. Since it fixed an ABI incompatibility with previous versions
@@ -209,6 +215,7 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
, m_category(data.category)
, m_hasSeedStatus(data.hasSeedStatus)
, m_ratioLimit(data.ratioLimit)
, m_seedingTimeLimit(data.seedingTimeLimit)
, m_tempPathDisabled(data.disableTempPath)
, m_hasMissingFiles(false)
, m_hasRootFolder(data.hasRootFolder)
@@ -581,6 +588,11 @@ qreal TorrentHandle::ratioLimit() const
return m_ratioLimit;
}
int TorrentHandle::seedingTimeLimit() const
{
return m_seedingTimeLimit;
}
QString TorrentHandle::filePath(int index) const
{
return m_torrentInfo.filePath(index);
@@ -907,24 +919,38 @@ qulonglong TorrentHandle::eta() const
{
if (isPaused()) return MAX_ETA;
const SpeedSampleAvg speed_average = m_speedMonitor.average();
const SpeedSampleAvg speedAverage = m_speedMonitor.average();
if (isSeed()) {
if (speed_average.upload == 0) return MAX_ETA;
qreal maxRatioValue = maxRatio();
int maxSeedingTimeValue = maxSeedingTime();
if ((maxRatioValue < 0) && (maxSeedingTimeValue < 0)) return MAX_ETA;
qreal max_ratio = maxRatio();
if (max_ratio < 0) return MAX_ETA;
qlonglong ratioEta = MAX_ETA;
qlonglong realDL = totalDownload();
if (realDL <= 0)
realDL = wantedSize();
if ((speedAverage.upload > 0) && (maxRatioValue >= 0)) {
return ((realDL * max_ratio) - totalUpload()) / speed_average.upload;
qlonglong realDL = totalDownload();
if (realDL <= 0)
realDL = wantedSize();
ratioEta = ((realDL * maxRatioValue) - totalUpload()) / speedAverage.upload;
}
qlonglong seedingTimeEta = MAX_ETA;
if (maxSeedingTimeValue >= 0) {
seedingTimeEta = (maxSeedingTimeValue * 60) - seedingTime();
if (seedingTimeEta < 0)
seedingTimeEta = 0;
}
return qMin(ratioEta, seedingTimeEta);
}
if (!speed_average.download) return MAX_ETA;
if (!speedAverage.download) return MAX_ETA;
return (wantedSize() - completedSize()) / speed_average.download;
return (wantedSize() - completedSize()) / speedAverage.download;
}
QVector<qreal> TorrentHandle::filesProgress() const
@@ -1105,6 +1131,23 @@ qreal TorrentHandle::maxRatio(bool *usesGlobalRatio) const
return ratioLimit;
}
int TorrentHandle::maxSeedingTime(bool *usesGlobalSeedingTime) const
{
int seedingTimeLimit = m_seedingTimeLimit;
if (seedingTimeLimit == USE_GLOBAL_SEEDING_TIME) {
seedingTimeLimit = m_session->globalMaxSeedingMinutes();
if (usesGlobalSeedingTime)
*usesGlobalSeedingTime = true;
}
else {
if (usesGlobalSeedingTime)
*usesGlobalSeedingTime = false;
}
return seedingTimeLimit;
}
qreal TorrentHandle::realRatio() const
{
boost::int64_t upload = m_nativeStatus.all_time_upload;
@@ -1572,6 +1615,7 @@ void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert
}
resumeData["qBt-savePath"] = m_useAutoTMM ? "" : Profile::instance().toPortablePath(m_savePath).toStdString();
resumeData["qBt-ratioLimit"] = QString::number(m_ratioLimit).toStdString();
resumeData["qBt-seedingTimeLimit"] = QString::number(m_seedingTimeLimit).toStdString();
resumeData["qBt-category"] = m_category.toStdString();
resumeData["qBt-name"] = m_name.toStdString();
resumeData["qBt-seedStatus"] = m_hasSeedStatus;
@@ -1878,7 +1922,21 @@ void TorrentHandle::setRatioLimit(qreal limit)
if (m_ratioLimit != limit) {
m_ratioLimit = limit;
m_needSaveResumeData = true;
m_session->handleTorrentRatioLimitChanged(this);
m_session->handleTorrentShareLimitChanged(this);
}
}
void TorrentHandle::setSeedingTimeLimit(int limit)
{
if (limit < USE_GLOBAL_SEEDING_TIME)
limit = NO_SEEDING_TIME_LIMIT;
else if (limit > MAX_SEEDING_TIME)
limit = MAX_SEEDING_TIME;
if (m_seedingTimeLimit != limit) {
m_seedingTimeLimit = limit;
m_needSaveResumeData = true;
m_session->handleTorrentShareLimitChanged(this);
}
}

View File

@@ -106,6 +106,7 @@ namespace BitTorrent
QVector<int> filePriorities;
// for resumed torrents
qreal ratioLimit;
int seedingTimeLimit;
AddTorrentData();
AddTorrentData(const AddTorrentParams &params);
@@ -169,7 +170,11 @@ namespace BitTorrent
static const qreal USE_GLOBAL_RATIO;
static const qreal NO_RATIO_LIMIT;
static const int USE_GLOBAL_SEEDING_TIME;
static const int NO_SEEDING_TIME_LIMIT;
static const qreal MAX_RATIO;
static const int MAX_SEEDING_TIME;
TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle,
const AddTorrentData &data);
@@ -251,6 +256,7 @@ namespace BitTorrent
qreal progress() const;
QDateTime addedTime() const;
qreal ratioLimit() const;
int seedingTimeLimit() const;
QString filePath(int index) const;
QString fileName(int index) const;
@@ -313,6 +319,7 @@ namespace BitTorrent
QVector<int> pieceAvailability() const;
qreal distributedCopies() const;
qreal maxRatio(bool *usesGlobalRatio = 0) const;
int maxSeedingTime(bool *usesGlobalSeedingTime = 0) const;
qreal realRatio() const;
int uploadPayloadRate() const;
int downloadPayloadRate() const;
@@ -341,6 +348,7 @@ namespace BitTorrent
void prioritizeFiles(const QVector<int> &priorities);
void setFilePriority(int index, int priority);
void setRatioLimit(qreal limit);
void setSeedingTimeLimit(int limit);
void setUploadLimit(int limit);
void setDownloadLimit(int limit);
void setSuperSeeding(bool enable);
@@ -439,6 +447,7 @@ namespace BitTorrent
QString m_category;
bool m_hasSeedStatus;
qreal m_ratioLimit;
int m_seedingTimeLimit;
bool m_tempPathDisabled;
bool m_hasMissingFiles;
bool m_hasRootFolder;