mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-19 04:49:47 -07:00
- Support per-peer rate limiting
This commit is contained in:
parent
bf6d7534d5
commit
47fc4679d4
6 changed files with 88 additions and 3 deletions
|
@ -23,6 +23,7 @@
|
||||||
- FEATURE: Seeds and Peers columns are now sortable
|
- FEATURE: Seeds and Peers columns are now sortable
|
||||||
- FEATURE: Torrents can be rechecked from Web UI (Stephanos Antaris)
|
- FEATURE: Torrents can be rechecked from Web UI (Stephanos Antaris)
|
||||||
- FEATURE: New peers can manually be added to the torrents
|
- FEATURE: New peers can manually be added to the torrents
|
||||||
|
- FEATURE: Support per-peer rate limiting
|
||||||
- COSMETIC: Merged download / upload lists
|
- COSMETIC: Merged download / upload lists
|
||||||
- COSMETIC: Torrents can be filtered based on their status
|
- COSMETIC: Torrents can be filtered based on their status
|
||||||
- COSMETIC: Torrent properties are now displayed in main window
|
- COSMETIC: Torrent properties are now displayed in main window
|
||||||
|
|
|
@ -709,9 +709,9 @@ void TransferListWidget::displayListMenu(const QPoint&) {
|
||||||
connect(&actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedTorrents()));
|
connect(&actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedTorrents()));
|
||||||
QAction actionPreview_file(QIcon(QString::fromUtf8(":/Icons/skin/preview.png")), tr("Preview file"), 0);
|
QAction actionPreview_file(QIcon(QString::fromUtf8(":/Icons/skin/preview.png")), tr("Preview file"), 0);
|
||||||
connect(&actionPreview_file, SIGNAL(triggered()), this, SLOT(previewSelectedTorrents()));
|
connect(&actionPreview_file, SIGNAL(triggered()), this, SLOT(previewSelectedTorrents()));
|
||||||
QAction actionSet_upload_limit(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png")), tr("Set upload limit"), 0);
|
QAction actionSet_upload_limit(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png")), tr("Limit upload rate"), 0);
|
||||||
connect(&actionSet_upload_limit, SIGNAL(triggered()), this, SLOT(setUpLimitSelectedTorrents()));
|
connect(&actionSet_upload_limit, SIGNAL(triggered()), this, SLOT(setUpLimitSelectedTorrents()));
|
||||||
QAction actionSet_download_limit(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")), tr("Set download limit"), 0);
|
QAction actionSet_download_limit(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")), tr("Limit download rate"), 0);
|
||||||
connect(&actionSet_download_limit, SIGNAL(triggered()), this, SLOT(setDlLimitSelectedTorrents()));
|
connect(&actionSet_download_limit, SIGNAL(triggered()), this, SLOT(setDlLimitSelectedTorrents()));
|
||||||
QAction actionDelete_Permanently(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")), tr("Delete Permanently"), 0);
|
QAction actionDelete_Permanently(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")), tr("Delete Permanently"), 0);
|
||||||
connect(&actionDelete_Permanently, SIGNAL(triggered()), this, SLOT(deletePermSelectedTorrents()));
|
connect(&actionDelete_Permanently, SIGNAL(triggered()), this, SLOT(deletePermSelectedTorrents()));
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "propertieswidget.h"
|
#include "propertieswidget.h"
|
||||||
#include "geoip.h"
|
#include "geoip.h"
|
||||||
#include "peeraddition.h"
|
#include "peeraddition.h"
|
||||||
|
#include "speedlimitdlg.h"
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
@ -113,9 +114,23 @@ void PeerListWidget::showPeerListMenu(QPoint) {
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
QTorrentHandle h = properties->getCurrentTorrent();
|
QTorrentHandle h = properties->getCurrentTorrent();
|
||||||
if(!h.is_valid()) return;
|
if(!h.is_valid()) return;
|
||||||
|
QModelIndexList selectedIndexes = selectionModel()->selectedRows();
|
||||||
|
QStringList selectedPeerIPs;
|
||||||
|
foreach(const QModelIndex &index, selectedIndexes) {
|
||||||
|
QString IP = proxyModel->data(index).toString();
|
||||||
|
selectedPeerIPs << IP;
|
||||||
|
}
|
||||||
|
// Add Peer Action
|
||||||
QAction *addPeerAct = 0;
|
QAction *addPeerAct = 0;
|
||||||
if(!h.is_queued() && !h.is_checking()) {
|
if(!h.is_queued() && !h.is_checking()) {
|
||||||
addPeerAct = menu.addAction(QIcon(":/Icons/oxygen/add_peer.png"), "Add a new peer");
|
addPeerAct = menu.addAction(QIcon(":/Icons/oxygen/add_peer.png"), tr("Add a new peer"));
|
||||||
|
}
|
||||||
|
// Per Peer Speed limiting actions
|
||||||
|
QAction *upLimitAct = 0;
|
||||||
|
QAction *dlLimitAct = 0;
|
||||||
|
if(!selectedPeerIPs.isEmpty()) {
|
||||||
|
upLimitAct = menu.addAction(QIcon(":/Icons/skin/seeding.png"), tr("Limit upload rate"));
|
||||||
|
dlLimitAct = menu.addAction(QIcon(":/Icons/skin/downloading.png"), tr("Limit download rate"));
|
||||||
}
|
}
|
||||||
QAction *act = menu.exec(QCursor::pos());
|
QAction *act = menu.exec(QCursor::pos());
|
||||||
if(act == addPeerAct) {
|
if(act == addPeerAct) {
|
||||||
|
@ -132,11 +147,63 @@ void PeerListWidget::showPeerListMenu(QPoint) {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(act == upLimitAct) {
|
||||||
|
limitUpRateSelectedPeers(selectedPeerIPs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(act == dlLimitAct) {
|
||||||
|
limitDlRateSelectedPeers(selectedPeerIPs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerListWidget::limitUpRateSelectedPeers(QStringList peer_ips) {
|
||||||
|
QTorrentHandle h = properties->getCurrentTorrent();
|
||||||
|
if(!h.is_valid()) return;
|
||||||
|
bool ok=false;
|
||||||
|
long limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Upload rate limiting"), -1);
|
||||||
|
if(!ok) return;
|
||||||
|
foreach(const QString &ip, peer_ips) {
|
||||||
|
boost::asio::ip::tcp::endpoint ep = peerEndpoints.value(ip, boost::asio::ip::tcp::endpoint());
|
||||||
|
if(ep != boost::asio::ip::tcp::endpoint()) {
|
||||||
|
qDebug("Settings Upload limit of %.1f Kb/s to peer %s", limit/1024., ip.toLocal8Bit().data());
|
||||||
|
try {
|
||||||
|
h.set_peer_upload_limit(ep, limit);
|
||||||
|
}catch(std::exception) {
|
||||||
|
std::cerr << "Impossible to apply upload limit to peer" << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug("The selected peer no longer exists...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerListWidget::limitDlRateSelectedPeers(QStringList peer_ips) {
|
||||||
|
QTorrentHandle h = properties->getCurrentTorrent();
|
||||||
|
if(!h.is_valid()) return;
|
||||||
|
bool ok=false;
|
||||||
|
long limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Download rate limiting"), -1);
|
||||||
|
if(!ok) return;
|
||||||
|
foreach(const QString &ip, peer_ips) {
|
||||||
|
boost::asio::ip::tcp::endpoint ep = peerEndpoints.value(ip, boost::asio::ip::tcp::endpoint());
|
||||||
|
if(ep != boost::asio::ip::tcp::endpoint()) {
|
||||||
|
qDebug("Settings Download limit of %.1f Kb/s to peer %s", limit/1024., ip.toLocal8Bit().data());
|
||||||
|
try {
|
||||||
|
h.set_peer_download_limit(ep, limit);
|
||||||
|
}catch(std::exception) {
|
||||||
|
std::cerr << "Impossible to apply download limit to peer" << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug("The selected peer no longer exists...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PeerListWidget::clear() {
|
void PeerListWidget::clear() {
|
||||||
qDebug("clearing peer list");
|
qDebug("clearing peer list");
|
||||||
peerItems.clear();
|
peerItems.clear();
|
||||||
|
peerEndpoints.clear();
|
||||||
missingFlags.clear();
|
missingFlags.clear();
|
||||||
int nbrows = listModel->rowCount();
|
int nbrows = listModel->rowCount();
|
||||||
if(nbrows > 0) {
|
if(nbrows > 0) {
|
||||||
|
@ -184,6 +251,7 @@ void PeerListWidget::loadPeers(const QTorrentHandle &h, bool force_hostname_reso
|
||||||
} else {
|
} else {
|
||||||
// Add new peer
|
// Add new peer
|
||||||
peerItems[peer_ip] = addPeer(peer_ip, peer);
|
peerItems[peer_ip] = addPeer(peer_ip, peer);
|
||||||
|
peerEndpoints[peer_ip] = peer.ip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Delete peers that are gone
|
// Delete peers that are gone
|
||||||
|
@ -191,6 +259,7 @@ void PeerListWidget::loadPeers(const QTorrentHandle &h, bool force_hostname_reso
|
||||||
while(it.hasNext()) {
|
while(it.hasNext()) {
|
||||||
QString ip = it.next();
|
QString ip = it.next();
|
||||||
missingFlags.remove(ip);
|
missingFlags.remove(ip);
|
||||||
|
peerEndpoints.remove(ip);
|
||||||
QStandardItem *item = peerItems.take(ip);
|
QStandardItem *item = peerItems.take(ip);
|
||||||
listModel->removeRow(item->row());
|
listModel->removeRow(item->row());
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ private:
|
||||||
PeerListDelegate *listDelegate;
|
PeerListDelegate *listDelegate;
|
||||||
QSortFilterProxyModel * proxyModel;
|
QSortFilterProxyModel * proxyModel;
|
||||||
QHash<QString, QStandardItem*> peerItems;
|
QHash<QString, QStandardItem*> peerItems;
|
||||||
|
QHash<QString, boost::asio::ip::tcp::endpoint> peerEndpoints;
|
||||||
QSet<QString> missingFlags;
|
QSet<QString> missingFlags;
|
||||||
QPointer<ReverseResolution> resolver;
|
QPointer<ReverseResolution> resolver;
|
||||||
PropertiesWidget* properties;
|
PropertiesWidget* properties;
|
||||||
|
@ -75,6 +76,8 @@ protected slots:
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void saveSettings() const;
|
void saveSettings() const;
|
||||||
void showPeerListMenu(QPoint);
|
void showPeerListMenu(QPoint);
|
||||||
|
void limitUpRateSelectedPeers(QStringList peer_ips);
|
||||||
|
void limitDlRateSelectedPeers(QStringList peer_ips);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PEERLISTWIDGET_H
|
#endif // PEERLISTWIDGET_H
|
||||||
|
|
|
@ -508,6 +508,16 @@ void QTorrentHandle::connect_peer(asio::ip::tcp::endpoint const& adr, int source
|
||||||
h.connect_peer(adr, source);
|
h.connect_peer(adr, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QTorrentHandle::set_peer_upload_limit(asio::ip::tcp::endpoint ip, int limit) const {
|
||||||
|
Q_ASSERT(h.is_valid());
|
||||||
|
h.set_peer_upload_limit(ip, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTorrentHandle::set_peer_download_limit(asio::ip::tcp::endpoint ip, int limit) const {
|
||||||
|
Q_ASSERT(h.is_valid());
|
||||||
|
h.set_peer_download_limit(ip, limit);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Operators
|
// Operators
|
||||||
//
|
//
|
||||||
|
|
|
@ -147,6 +147,8 @@ class QTorrentHandle {
|
||||||
void super_seeding(bool on) const;
|
void super_seeding(bool on) const;
|
||||||
void resolve_countries(bool r);
|
void resolve_countries(bool r);
|
||||||
void connect_peer(asio::ip::tcp::endpoint const& adr, int source = 0) const;
|
void connect_peer(asio::ip::tcp::endpoint const& adr, int source = 0) const;
|
||||||
|
void set_peer_upload_limit(asio::ip::tcp::endpoint ip, int limit) const;
|
||||||
|
void set_peer_download_limit(asio::ip::tcp::endpoint ip, int limit) const;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Operators
|
// Operators
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue