mirror of
https://github.com/transmission/transmission
synced 2025-02-21 21:57:01 +00:00
Limit bandwidth used by a group of torrents (#2761)
* Add support for bandwidth groups. i.e. Bandwidth limit for a (user specified) group of torrents,
This commit is contained in:
parent
6cb0498486
commit
c07bac4e19
13 changed files with 372 additions and 3 deletions
|
@ -144,6 +144,7 @@ Request arguments:
|
|||
| `downloadLimited` | boolean | true if `downloadLimit` is honored
|
||||
| `files-unwanted` | array | indices of file(s) to not download
|
||||
| `files-wanted` | array | indices of file(s) to download
|
||||
| `group` | string | The name of this torrent's bandwidth group
|
||||
| `honorsSessionLimits` | boolean | true if session upload limits are honored
|
||||
| `ids` | array | torrent list, as described in 3.1
|
||||
| `labels` | array | array of string labels
|
||||
|
@ -228,6 +229,7 @@ The 'source' column here corresponds to the data structure there.
|
|||
| `file-count` | number | tr_info
|
||||
| `files`| array (see below)| n/a
|
||||
| `fileStats`| array (see below)| n/a
|
||||
| `group`| string| n/a
|
||||
| `hashString`| string| tr_torrent_view
|
||||
| `haveUnchecked`| number| tr_stat
|
||||
| `haveValid`| number| tr_stat
|
||||
|
@ -709,6 +711,50 @@ Response arguments:
|
|||
| `size-bytes` | number | the size, in bytes, of the free space in that directory
|
||||
| `total_size` | number | the total capacity, in bytes, of that directory
|
||||
|
||||
### 4.8 Bandwidth groups
|
||||
|
||||
#### 4.8.1 Bandwidth group Mutator: `group-set`
|
||||
|
||||
Method name: `group-set`
|
||||
|
||||
Request parameters:
|
||||
|
||||
| Key | Value type | Description
|
||||
|:--|:--|:--
|
||||
| `honorsSessionLimits` | boolean | true if session upload limits are honored
|
||||
| `name` | string | Bandwidth group name
|
||||
| `speed-limit-down-enabled` | boolean | true means enabled
|
||||
| `speed-limit-down` | number | max global download speed (KBps)
|
||||
| `speed-limit-up-enabled` | boolean | true means enabled
|
||||
| `speed-limit-up` | number | max global upload speed (KBps)
|
||||
|
||||
Response arguments: none
|
||||
|
||||
#### 4.8.2 Bandwidth group Accessor: `group-get`
|
||||
|
||||
Method name: `group-get`
|
||||
|
||||
Request arguments: An optional argument `group`.
|
||||
`group` is either a string naming the bandwidth group,
|
||||
or a list of such strings.
|
||||
If `group` is omitted, all bandwidth groups are used.
|
||||
|
||||
Response arguments:
|
||||
|
||||
| Key | Value type | Description
|
||||
|:--|:--|:--
|
||||
|`group`| array | A list of bandwidth group description objects
|
||||
|
||||
A bandwidth group description object has:
|
||||
|
||||
| Key | Value type | Description
|
||||
|:--|:--|:--
|
||||
| `honorsSessionLimits` | boolean | true if session upload limits are honored
|
||||
| `name` | string | Bandwidth group name
|
||||
| `speed-limit-down-enabled` | boolean | true means enabled
|
||||
| `speed-limit-down` | number | max global download speed (KBps)
|
||||
| `speed-limit-up-enabled` | boolean | true means enabled
|
||||
| `speed-limit-up` | number | max global upload speed (KBps)
|
||||
|
||||
## 5. Protocol Versions
|
||||
|
||||
|
@ -949,13 +995,17 @@ Transmission 4.0.0 (`rpc-version-semver` 5.3.0, `rpc-version`: 17)
|
|||
| `session-get` | new arg `script-torrent-done-seeding-filename`
|
||||
| `torrent-add` | new arg `labels`
|
||||
| `torrent-get` | new arg `file-count`
|
||||
| `torrent-get` | new arg `group`
|
||||
| `torrent-get` | new arg `percentComplete`
|
||||
| `torrent-get` | new arg `primary-mime-type`
|
||||
| `torrent-get` | new arg `tracker.sitename`
|
||||
| `torrent-get` | new arg `trackerStats.sitename`
|
||||
| `torrent-get` | new arg `trackerList`
|
||||
| `torrent-set` | new arg `group`
|
||||
| `torrent-set` | new arg `trackerList`
|
||||
| `torrent-set` | **DEPRECATED** `trackerAdd`. Use `trackerList` instead.
|
||||
| `torrent-set` | **DEPRECATED** `trackerRemove`. Use `trackerList` instead.
|
||||
| `torrent-set` | **DEPRECATED** `trackerReplace`. Use `trackerList` instead.
|
||||
| `group-set` | new method
|
||||
| `group-get` | new method
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
|
@ -12,10 +13,15 @@
|
|||
|
||||
#include "bandwidth.h"
|
||||
#include "crypto-utils.h" /* tr_rand_int_weak() */
|
||||
#include "error.h"
|
||||
#include "log.h"
|
||||
#include "peer-io.h"
|
||||
#include "platform.h"
|
||||
#include "quark.h"
|
||||
#include "session.h"
|
||||
#include "tr-assert.h"
|
||||
#include "utils.h"
|
||||
#include "variant.h"
|
||||
|
||||
/***
|
||||
****
|
||||
|
@ -336,3 +342,25 @@ void Bandwidth::notifyBandwidthConsumed(tr_direction dir, size_t byte_count, boo
|
|||
this->parent_->notifyBandwidthConsumed(dir, byte_count, is_piece_data, now);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
tr_bandwidth_limits Bandwidth::getLimits() const
|
||||
{
|
||||
tr_bandwidth_limits limits;
|
||||
limits.up_limit_KBps = tr_toSpeedKBps(this->getDesiredSpeedBytesPerSecond(TR_UP));
|
||||
limits.down_limit_KBps = tr_toSpeedKBps(this->getDesiredSpeedBytesPerSecond(TR_DOWN));
|
||||
limits.up_limited = this->isLimited(TR_UP);
|
||||
limits.down_limited = this->isLimited(TR_DOWN);
|
||||
return limits;
|
||||
}
|
||||
|
||||
void Bandwidth::setLimits(tr_bandwidth_limits const* limits)
|
||||
{
|
||||
this->setDesiredSpeedBytesPerSecond(TR_UP, tr_toSpeedBytes(limits->up_limit_KBps));
|
||||
this->setDesiredSpeedBytesPerSecond(TR_DOWN, tr_toSpeedBytes(limits->down_limit_KBps));
|
||||
this->setLimited(TR_UP, limits->up_limited);
|
||||
this->setLimited(TR_DOWN, limits->down_limited);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <array>
|
||||
#include <cstddef> // size_t
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
|
@ -24,6 +25,14 @@ class tr_peerIo;
|
|||
* @{
|
||||
*/
|
||||
|
||||
struct tr_bandwidth_limits
|
||||
{
|
||||
bool up_limited;
|
||||
unsigned int up_limit_KBps;
|
||||
bool down_limited;
|
||||
unsigned int down_limit_KBps;
|
||||
};
|
||||
|
||||
/**
|
||||
* Bandwidth is an object for measuring and constraining bandwidth speeds.
|
||||
*
|
||||
|
@ -228,6 +237,9 @@ public:
|
|||
bool honor_parent_limits_;
|
||||
};
|
||||
|
||||
tr_bandwidth_limits getLimits() const;
|
||||
void setLimits(tr_bandwidth_limits const* limits);
|
||||
|
||||
private:
|
||||
static unsigned int getSpeedBytesPerSecond(RateControl& r, unsigned int interval_msec, uint64_t now);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ using namespace std::literals;
|
|||
namespace
|
||||
{
|
||||
|
||||
auto constexpr my_static = std::array<std::string_view, 390>{ ""sv,
|
||||
auto constexpr my_static = std::array<std::string_view, 391>{ ""sv,
|
||||
"activeTorrentCount"sv,
|
||||
"activity-date"sv,
|
||||
"activityDate"sv,
|
||||
|
@ -131,6 +131,7 @@ auto constexpr my_static = std::array<std::string_view, 390>{ ""sv,
|
|||
"fromLtep"sv,
|
||||
"fromPex"sv,
|
||||
"fromTracker"sv,
|
||||
"group"sv,
|
||||
"hasAnnounced"sv,
|
||||
"hasScraped"sv,
|
||||
"hashString"sv,
|
||||
|
|
|
@ -134,6 +134,7 @@ enum
|
|||
TR_KEY_fromLtep,
|
||||
TR_KEY_fromPex,
|
||||
TR_KEY_fromTracker,
|
||||
TR_KEY_group,
|
||||
TR_KEY_hasAnnounced,
|
||||
TR_KEY_hasScraped,
|
||||
TR_KEY_hashString,
|
||||
|
|
|
@ -133,6 +133,27 @@ static auto loadLabels(tr_variant* dict, tr_torrent* tor)
|
|||
****
|
||||
***/
|
||||
|
||||
static void saveGroup(tr_variant* dict, tr_torrent const* tor)
|
||||
{
|
||||
tr_variantDictAddStrView(dict, TR_KEY_group, tor->group);
|
||||
}
|
||||
|
||||
static auto loadGroup(tr_variant* dict, tr_torrent* tor)
|
||||
{
|
||||
std::string_view groupName;
|
||||
|
||||
if (tr_variantDictFindStrView(dict, TR_KEY_group, &groupName) && !groupName.empty())
|
||||
{
|
||||
tor->setGroup(groupName);
|
||||
return tr_resume::Group;
|
||||
}
|
||||
return tr_resume::fields_t{};
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static void saveDND(tr_variant* dict, tr_torrent const* tor)
|
||||
{
|
||||
auto const n = tor->fileCount();
|
||||
|
@ -819,6 +840,11 @@ static auto loadFromFile(tr_torrent* tor, tr_resume::fields_t fieldsToLoad, bool
|
|||
fields_loaded |= loadLabels(&top, tor);
|
||||
}
|
||||
|
||||
if ((fieldsToLoad & tr_resume::Group) != 0)
|
||||
{
|
||||
fields_loaded |= loadGroup(&top, tor);
|
||||
}
|
||||
|
||||
/* loading the resume file triggers of a lot of changes,
|
||||
* but none of them needs to trigger a re-saving of the
|
||||
* same resume information... */
|
||||
|
@ -930,6 +956,7 @@ void save(tr_torrent* tor)
|
|||
saveFilenames(&top, tor);
|
||||
saveName(&top, tor);
|
||||
saveLabels(&top, tor);
|
||||
saveGroup(&top, tor);
|
||||
|
||||
if (auto const err = tr_variantToFile(&top, TR_VARIANT_FMT_BENC, tor->resumeFile()); err != 0)
|
||||
{
|
||||
|
|
|
@ -42,6 +42,7 @@ auto inline constexpr TimeDownloading = fields_t{ 1 << 19 };
|
|||
auto inline constexpr Filenames = fields_t{ 1 << 20 };
|
||||
auto inline constexpr Name = fields_t{ 1 << 21 };
|
||||
auto inline constexpr Labels = fields_t{ 1 << 22 };
|
||||
auto inline constexpr Group = fields_t{ 1 << 23 };
|
||||
|
||||
auto inline constexpr All = ~fields_t{ 0 };
|
||||
|
||||
|
|
|
@ -562,6 +562,10 @@ static void initField(tr_torrent const* const tor, tr_stat const* const st, tr_v
|
|||
addFileStats(tor, initme);
|
||||
break;
|
||||
|
||||
case TR_KEY_group:
|
||||
tr_variantInitStrView(initme, tor->group);
|
||||
break;
|
||||
|
||||
case TR_KEY_hashString:
|
||||
tr_variantInitStrView(initme, tor->infoHashString());
|
||||
break;
|
||||
|
@ -1157,6 +1161,11 @@ static char const* torrentSet(
|
|||
}
|
||||
}
|
||||
|
||||
if (std::string_view group; tr_variantDictFindStrView(args_in, TR_KEY_group, &group))
|
||||
{
|
||||
tor->setGroup(group);
|
||||
}
|
||||
|
||||
if (errmsg == nullptr && tr_variantDictFindList(args_in, TR_KEY_labels, &tmp_variant))
|
||||
{
|
||||
errmsg = setLabels(tor, tmp_variant);
|
||||
|
@ -1695,6 +1704,96 @@ static char const* torrentAdd(tr_session* session, tr_variant* args_in, tr_varia
|
|||
****
|
||||
***/
|
||||
|
||||
static char const* groupGet(tr_session* s, tr_variant* args_in, tr_variant* args_out, struct tr_rpc_idle_data* /*idle_data*/)
|
||||
{
|
||||
std::set<std::string_view> names;
|
||||
|
||||
if (std::string_view one_name; tr_variantDictFindStrView(args_in, TR_KEY_name, &one_name))
|
||||
{
|
||||
names.insert(one_name);
|
||||
}
|
||||
else if (tr_variant* namesList = nullptr; tr_variantDictFindList(args_in, TR_KEY_name, &namesList))
|
||||
{
|
||||
int names_count = tr_variantListSize(namesList);
|
||||
for (int i = 0; i < names_count; i++)
|
||||
{
|
||||
tr_variant* v = tr_variantListChild(namesList, i);
|
||||
if (std::string_view l; tr_variantIsString(v) && tr_variantGetStrView(v, &l))
|
||||
{
|
||||
names.insert(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tr_variant* list = tr_variantDictAddList(args_out, TR_KEY_group, 1);
|
||||
for (auto const& [name, group] : s->bandwidth_groups)
|
||||
{
|
||||
if (names.empty() || names.count(name) > 0)
|
||||
{
|
||||
tr_variant* dict = tr_variantListAddDict(list, 5);
|
||||
auto limits = group->getLimits();
|
||||
tr_variantDictAddStrView(dict, TR_KEY_name, name);
|
||||
tr_variantDictAddBool(dict, TR_KEY_uploadLimited, limits.up_limited);
|
||||
tr_variantDictAddInt(dict, TR_KEY_uploadLimit, limits.up_limit_KBps);
|
||||
tr_variantDictAddBool(dict, TR_KEY_downloadLimited, limits.down_limited);
|
||||
tr_variantDictAddInt(dict, TR_KEY_downloadLimit, limits.down_limit_KBps);
|
||||
tr_variantDictAddBool(dict, TR_KEY_honorsSessionLimits, group->areParentLimitsHonored(TR_UP));
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static char const* groupSet(
|
||||
tr_session* session,
|
||||
tr_variant* args_in,
|
||||
tr_variant* /*args_out*/,
|
||||
struct tr_rpc_idle_data* /*idle_data*/)
|
||||
{
|
||||
std::string_view name;
|
||||
|
||||
if (!tr_variantDictFindStrView(args_in, TR_KEY_name, &name))
|
||||
{
|
||||
return "No group name given";
|
||||
}
|
||||
|
||||
Bandwidth* group = session->bandwidthGroupFind(name);
|
||||
if (group == nullptr)
|
||||
{
|
||||
return "No such group";
|
||||
}
|
||||
|
||||
auto limits = group->getLimits();
|
||||
|
||||
tr_variantDictFindBool(args_in, TR_KEY_speed_limit_down_enabled, &limits.down_limited);
|
||||
int64_t intVal = 0;
|
||||
if (tr_variantDictFindInt(args_in, TR_KEY_speed_limit_down, &intVal))
|
||||
{
|
||||
limits.down_limit_KBps = intVal;
|
||||
}
|
||||
|
||||
tr_variantDictFindBool(args_in, TR_KEY_speed_limit_up_enabled, &limits.up_limited);
|
||||
if (tr_variantDictFindInt(args_in, TR_KEY_speed_limit_up, &intVal))
|
||||
{
|
||||
limits.up_limit_KBps = intVal;
|
||||
}
|
||||
|
||||
group->setLimits(&limits);
|
||||
|
||||
bool honors = false;
|
||||
if (tr_variantDictFindBool(args_in, TR_KEY_honorsSessionLimits, &honors))
|
||||
{
|
||||
group->honorParentLimits(TR_UP, honors);
|
||||
group->honorParentLimits(TR_DOWN, honors);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static char const* sessionSet(
|
||||
tr_session* session,
|
||||
tr_variant* args_in,
|
||||
|
@ -2346,9 +2445,11 @@ struct rpc_method
|
|||
handler func;
|
||||
};
|
||||
|
||||
static auto constexpr Methods = std::array<rpc_method, 22>{ {
|
||||
static auto constexpr Methods = std::array<rpc_method, 24>{ {
|
||||
{ "blocklist-update"sv, false, blocklistUpdate },
|
||||
{ "free-space"sv, true, freeSpace },
|
||||
{ "group-get"sv, true, groupGet },
|
||||
{ "group-set"sv, true, groupSet },
|
||||
{ "port-test"sv, false, portTest },
|
||||
{ "queue-move-bottom"sv, true, queueMoveBottom },
|
||||
{ "queue-move-down"sv, true, queueMoveDown },
|
||||
|
|
|
@ -78,6 +78,9 @@ static auto constexpr DefaultPrefetchEnabled = bool{ true };
|
|||
#endif
|
||||
static auto constexpr SaveIntervalSecs = int{ 360 };
|
||||
|
||||
static void bandwidthGroupRead(tr_session* session, char const* configDir);
|
||||
static int bandwidthGroupWrite(tr_session* session, char const* configDir);
|
||||
|
||||
static tr_port getRandomPort(tr_session const* s)
|
||||
{
|
||||
return tr_port(tr_rand_int_weak(s->randomPortHigh - s->randomPortLow + 1) + s->randomPortLow);
|
||||
|
@ -536,6 +539,9 @@ void tr_sessionSaveSettings(tr_session* session, char const* config_dir, tr_vari
|
|||
|
||||
/* cleanup */
|
||||
tr_variantFree(&settings);
|
||||
|
||||
/* Write bandwidth groups limits to file */
|
||||
bandwidthGroupWrite(session, config_dir);
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -596,6 +602,7 @@ tr_session* tr_sessionInit(char const* config_dir, bool messageQueuingEnabled, t
|
|||
session->session_id = tr_session_id_new();
|
||||
session->bandwidth = new Bandwidth(nullptr);
|
||||
session->removed_torrents.clear();
|
||||
bandwidthGroupRead(session, config_dir);
|
||||
|
||||
/* nice to start logging at the very beginning */
|
||||
if (auto i = int64_t{}; tr_variantDictFindInt(clientSettings, TR_KEY_message_level, &i))
|
||||
|
@ -2267,6 +2274,26 @@ void tr_sessionSetDefaultTrackers(tr_session* session, char const* trackers)
|
|||
****
|
||||
***/
|
||||
|
||||
Bandwidth* tr_session::bandwidthGroupFind(std::string_view name)
|
||||
{
|
||||
std::string str_name{ name };
|
||||
if (name.empty())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (bandwidth_groups[str_name] == nullptr)
|
||||
{
|
||||
Bandwidth* bw = new Bandwidth(bandwidth);
|
||||
bandwidth_groups[str_name] = bw;
|
||||
}
|
||||
return bandwidth_groups[str_name];
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
struct port_forwarding_data
|
||||
{
|
||||
bool enabled;
|
||||
|
@ -2845,3 +2872,78 @@ int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction dir)
|
|||
|
||||
return max - active_count;
|
||||
}
|
||||
|
||||
static void bandwidthGroupRead(tr_session* session, char const* configDir)
|
||||
{
|
||||
tr_variant group_list;
|
||||
auto const filename = tr_strvPath(configDir, "bandwidthGroups");
|
||||
if (!tr_variantFromFile(&group_list, TR_VARIANT_PARSE_JSON, filename, nullptr) || !tr_variantIsList(&group_list))
|
||||
{
|
||||
return;
|
||||
}
|
||||
int n = tr_variantListSize(&group_list);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
tr_variant* dict = tr_variantListChild(&group_list, i);
|
||||
std::string_view name;
|
||||
if (!tr_variantDictFindStrView(dict, TR_KEY_name, &name) || name.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Bandwidth* group = session->bandwidthGroupFind(name);
|
||||
if (group == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int64_t val = 0;
|
||||
tr_bandwidth_limits limits;
|
||||
tr_variantDictFindBool(dict, TR_KEY_uploadLimited, &limits.up_limited);
|
||||
if (tr_variantDictFindInt(dict, TR_KEY_uploadLimit, &val))
|
||||
{
|
||||
limits.up_limit_KBps = val;
|
||||
}
|
||||
|
||||
tr_variantDictFindBool(dict, TR_KEY_downloadLimited, &limits.down_limited);
|
||||
if (tr_variantDictFindInt(dict, TR_KEY_downloadLimit, &val))
|
||||
{
|
||||
limits.down_limit_KBps = val;
|
||||
}
|
||||
|
||||
group->setLimits(&limits);
|
||||
|
||||
bool honors = false;
|
||||
if (tr_variantDictFindBool(dict, TR_KEY_honorsSessionLimits, &honors))
|
||||
{
|
||||
group->honorParentLimits(TR_UP, honors);
|
||||
group->honorParentLimits(TR_DOWN, honors);
|
||||
}
|
||||
}
|
||||
tr_variantFree(&group_list);
|
||||
}
|
||||
|
||||
static int bandwidthGroupWrite(tr_session* session, char const* configDir)
|
||||
{
|
||||
tr_variant group_list;
|
||||
int n = session->bandwidth_groups.size();
|
||||
tr_variantInitList(&group_list, n);
|
||||
for (auto const& [name, group] : session->bandwidth_groups)
|
||||
{
|
||||
tr_variant* dict = tr_variantListAddDict(&group_list, 5);
|
||||
auto limits = group->getLimits();
|
||||
|
||||
tr_variantDictAddStr(dict, TR_KEY_name, name);
|
||||
tr_variantDictAddBool(dict, TR_KEY_uploadLimited, limits.up_limited);
|
||||
tr_variantDictAddInt(dict, TR_KEY_uploadLimit, limits.up_limit_KBps);
|
||||
tr_variantDictAddBool(dict, TR_KEY_downloadLimited, limits.down_limited);
|
||||
tr_variantDictAddInt(dict, TR_KEY_downloadLimit, limits.down_limit_KBps);
|
||||
tr_variantDictAddBool(dict, TR_KEY_honorsSessionLimits, group->areParentLimitsHonored(TR_UP));
|
||||
}
|
||||
|
||||
auto const filename = tr_strvPath(configDir, "bandwidthGroups");
|
||||
auto const ret = tr_variantToFile(&group_list, TR_VARIANT_FMT_JSON, filename);
|
||||
tr_variantFree(&group_list);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "transmission.h"
|
||||
|
||||
#include "announce-list.h"
|
||||
#include "bandwidth.h"
|
||||
#include "net.h" // tr_socket_t
|
||||
#include "quark.h"
|
||||
#include "torrents.h"
|
||||
|
@ -404,6 +405,9 @@ public:
|
|||
// Only session.cc should use this.
|
||||
int peer_socket_tos_ = *tr_netTosFromName(TR_DEFAULT_PEER_SOCKET_TOS_STR);
|
||||
|
||||
Bandwidth* bandwidthGroupFind(std::string_view name);
|
||||
std::map<std::string, Bandwidth*> bandwidth_groups;
|
||||
|
||||
private:
|
||||
static std::recursive_mutex session_mutex_;
|
||||
|
||||
|
|
|
@ -1902,6 +1902,21 @@ void tr_torrentSetLabels(tr_torrent* tor, tr_labels_t&& labels)
|
|||
****
|
||||
***/
|
||||
|
||||
void tr_torrent::setGroup(std::string_view groupName)
|
||||
{
|
||||
auto const lock = this->unique_lock();
|
||||
|
||||
this->group.assign(groupName);
|
||||
Bandwidth* bw = this->session->bandwidthGroupFind(group);
|
||||
this->bandwidth->setParent(bw != nullptr ? bw : this->session->bandwidth);
|
||||
|
||||
this->setDirty();
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
tr_priority_t tr_torrentGetPriority(tr_torrent const* tor)
|
||||
{
|
||||
TR_ASSERT(tr_isTorrent(tor));
|
||||
|
|
|
@ -717,6 +717,10 @@ public:
|
|||
|
||||
tr_labels_t labels;
|
||||
|
||||
std::string group;
|
||||
/* Set the bandwidth group the torrent belongs to */
|
||||
void setGroup(std::string_view groupName);
|
||||
|
||||
static auto constexpr MagicNumber = int{ 95549 };
|
||||
|
||||
tr_file_piece_map fpm_ = tr_file_piece_map{ metainfo_ };
|
||||
|
|
|
@ -243,7 +243,7 @@ enum
|
|||
****
|
||||
***/
|
||||
|
||||
static auto constexpr Options = std::array<tr_option, 89>{
|
||||
static auto constexpr Options = std::array<tr_option, 91>{
|
||||
{ { 'a', "add", "Add torrent files by filename or URL", "a", false, nullptr },
|
||||
{ 970, "alt-speed", "Use the alternate Limits", "as", false, nullptr },
|
||||
{ 971, "no-alt-speed", "Don't use the alternate Limits", "AS", false, nullptr },
|
||||
|
@ -258,6 +258,8 @@ static auto constexpr Options = std::array<tr_option, 89>{
|
|||
{ 'c', "incomplete-dir", "Where to store new torrents until they're complete", "c", true, "<dir>" },
|
||||
{ 'C', "no-incomplete-dir", "Don't store incomplete torrents in a different location", "C", false, nullptr },
|
||||
{ 'b', "debug", "Print debugging information", "b", false, nullptr },
|
||||
{ 730, "bandwidth-group", "Set the current torrents' bandwidth group", "bwg", true, "<group>" },
|
||||
{ 731, "no-bandwidth-group", "Reset the current torrents' bandwidth group", "nwg", false, nullptr },
|
||||
{ 'd',
|
||||
"downlimit",
|
||||
"Set the max download speed in " SPEED_K_STR " for the current torrent(s) or globally",
|
||||
|
@ -481,6 +483,8 @@ static int getOptMode(int val)
|
|||
case 900: /* file priority-high */
|
||||
case 901: /* file priority-normal */
|
||||
case 902: /* file priority-low */
|
||||
case 730: /* set bandwidth group */
|
||||
case 731: /* reset bandwidth group */
|
||||
return MODE_TORRENT_SET | MODE_TORRENT_ADD;
|
||||
|
||||
case 961: /* find */
|
||||
|
@ -673,6 +677,11 @@ static void addLabels(tr_variant* args, std::string_view comma_delimited_labels)
|
|||
}
|
||||
}
|
||||
|
||||
static void setGroup(tr_variant* args, std::string_view group)
|
||||
{
|
||||
tr_variantDictAddStrView(args, TR_KEY_group, group);
|
||||
}
|
||||
|
||||
static void addFiles(tr_variant* args, tr_quark const key, char const* arg)
|
||||
{
|
||||
tr_variant* files = tr_variantDictAddList(args, key, 100);
|
||||
|
@ -716,6 +725,7 @@ static tr_quark const details_keys[] = {
|
|||
TR_KEY_error,
|
||||
TR_KEY_errorString,
|
||||
TR_KEY_eta,
|
||||
TR_KEY_group,
|
||||
TR_KEY_hashString,
|
||||
TR_KEY_haveUnchecked,
|
||||
TR_KEY_haveValid,
|
||||
|
@ -979,6 +989,11 @@ static void printDetails(tr_variant* top)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
if (tr_variantDictFindStrView(t, TR_KEY_group, &sv) && !sv.empty())
|
||||
{
|
||||
printf(" Bandwidth group: %" TR_PRIsv "\n", TR_PRIsv_ARG(sv));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("TRANSFER\n");
|
||||
|
@ -2785,6 +2800,14 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
addLabels(args, optarg ? optarg : "");
|
||||
break;
|
||||
|
||||
case 730:
|
||||
setGroup(args, optarg ? optarg : "");
|
||||
break;
|
||||
|
||||
case 731:
|
||||
setGroup(args, "");
|
||||
break;
|
||||
|
||||
case 900:
|
||||
addFiles(args, TR_KEY_priority_high, optarg);
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue