refactor: make variant_headers reusable to qt app. (#1369)

* refactor: make variant_headers reusable to qt app.

Torrent.cc's `change()` template methods are generically useful to deal
with tr_variant wrangling, but previously were only used in Torrent.cc.
This PR moves them into a new API `VariantHelpers.h` for use by Prefs,
Session, TorrentModel, etc.
This commit is contained in:
Charles Kerr 2020-07-26 23:30:58 -05:00 committed by GitHub
parent 7e1da2d8fe
commit 00be8d00d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 675 additions and 527 deletions

View File

@ -373,7 +373,7 @@ void tr_sessionGetDefaultSettings(tr_variant* d)
tr_variantDictAddBool(d, TR_KEY_rpc_whitelist_enabled, true);
tr_variantDictAddStr(d, TR_KEY_rpc_host_whitelist, TR_DEFAULT_RPC_HOST_WHITELIST);
tr_variantDictAddBool(d, TR_KEY_rpc_host_whitelist_enabled, true);
tr_variantDictAddInt(d, TR_KEY_rpc_port, atoi(TR_DEFAULT_RPC_PORT_STR));
tr_variantDictAddInt(d, TR_KEY_rpc_port, TR_DEFAULT_RPC_PORT);
tr_variantDictAddStr(d, TR_KEY_rpc_url, TR_DEFAULT_RPC_URL_STR);
tr_variantDictAddBool(d, TR_KEY_scrape_paused_torrents_enabled, true);
tr_variantDictAddStr(d, TR_KEY_script_torrent_done_filename, "");

View File

@ -113,6 +113,7 @@ char const* tr_getDefaultDownloadDir(void);
#define TR_DEFAULT_RPC_WHITELIST "127.0.0.1,::1"
#define TR_DEFAULT_RPC_HOST_WHITELIST ""
#define TR_DEFAULT_RPC_PORT_STR "9091"
#define TR_DEFAULT_RPC_PORT 9091
#define TR_DEFAULT_RPC_URL_STR "/transmission/"
#define TR_DEFAULT_PEER_PORT_STR "51413"
#define TR_DEFAULT_PEER_SOCKET_TOS_STR "default"

View File

@ -47,6 +47,7 @@ set(${PROJECT_NAME}_SOURCES
TrackerModel.cc
TrackerModelFilter.cc
Utils.cc
VariantHelpers.cc
WatchDir.cc
)
@ -108,6 +109,7 @@ set(${PROJECT_NAME}_HEADERS
TrackerModelFilter.h
Typedefs.h
Utils.h
VariantHelpers.h
WatchDir.h
)

View File

@ -15,6 +15,10 @@
#include "FreeSpaceLabel.h"
#include "RpcQueue.h"
#include "Session.h"
#include "VariantHelpers.h"
using ::trqt::variant_helpers::dictAdd;
using ::trqt::variant_helpers::dictFind;
namespace
{
@ -65,7 +69,7 @@ void FreeSpaceLabel::onTimer()
tr_variant args;
tr_variantInitDict(&args, 1);
tr_variantDictAddStr(&args, TR_KEY_path, path_.toUtf8().constData());
dictAdd(&args, TR_KEY_path, path_);
auto* q = new RpcQueue();
@ -76,14 +80,11 @@ void FreeSpaceLabel::onTimer()
q->add([this](RpcResponse const& r)
{
QString str;
// update the label
int64_t bytes = -1;
if (tr_variantDictFindInt(r.args.get(), TR_KEY_size_bytes, &bytes) && bytes >= 0)
auto const bytes = dictFind<int64_t>(r.args.get(), TR_KEY_size_bytes);
if (bytes && *bytes > 1)
{
setText(tr("%1 free").arg(Formatter::sizeToString(bytes)));
setText(tr("%1 free").arg(Formatter::sizeToString(*bytes)));
}
else
{
@ -91,11 +92,8 @@ void FreeSpaceLabel::onTimer()
}
// update the tooltip
size_t len = 0;
char const* path = nullptr;
tr_variantDictFindStr(r.args.get(), TR_KEY_path, &path, &len);
str = QString::fromUtf8(path, len);
setToolTip(QDir::toNativeSeparators(str));
auto const path = dictFind<QString>(r.args.get(), TR_KEY_path);
setToolTip(QDir::toNativeSeparators(path ? *path : QString()));
timer_.start();
});

View File

@ -20,6 +20,10 @@
#include "Session.h"
#include "Torrent.h"
#include "Utils.h"
#include "VariantHelpers.h"
using ::trqt::variant_helpers::dictAdd;
using ::trqt::variant_helpers::listAdd;
/***
****
@ -260,15 +264,15 @@ void OptionsDialog::onAccepted()
download_dir = ui_.destinationEdit->text();
}
tr_variantDictAddStr(&args, TR_KEY_download_dir, download_dir.toUtf8().constData());
dictAdd(&args, TR_KEY_download_dir, download_dir);
// paused
tr_variantDictAddBool(&args, TR_KEY_paused, !ui_.startCheck->isChecked());
dictAdd(&args, TR_KEY_paused, !ui_.startCheck->isChecked());
// priority
int const index = ui_.priorityCombo->currentIndex();
int const priority = ui_.priorityCombo->itemData(index).toInt();
tr_variantDictAddInt(&args, TR_KEY_bandwidthPriority, priority);
dictAdd(&args, TR_KEY_bandwidthPriority, priority);
// files-unwanted
int count = wanted_.count(false);
@ -281,7 +285,7 @@ void OptionsDialog::onAccepted()
{
if (!wanted_.at(i))
{
tr_variantListAddInt(l, i);
listAdd(l, i);
}
}
}
@ -297,7 +301,7 @@ void OptionsDialog::onAccepted()
{
if (priorities_.at(i) == TR_PRI_LOW)
{
tr_variantListAddInt(l, i);
listAdd(l, i);
}
}
}
@ -313,7 +317,7 @@ void OptionsDialog::onAccepted()
{
if (priorities_.at(i) == TR_PRI_HIGH)
{
tr_variantListAddInt(l, i);
listAdd(l, i);
}
}
}

View File

@ -20,6 +20,10 @@
#include "CustomVariantType.h"
#include "Prefs.h"
#include "Utils.h"
#include "VariantHelpers.h"
using ::trqt::variant_helpers::dictAdd;
using ::trqt::variant_helpers::getValue;
/***
****
@ -150,69 +154,78 @@ Prefs::Prefs(QString config_dir) :
for (int i = 0; i < PREFS_COUNT; ++i)
{
double d;
bool bool_val;
int64_t int_val;
char const* str;
size_t str_len;
tr_variant* b(tr_variantDictFind(&top, Items[i].key));
switch (Items[i].type)
{
case QVariant::Int:
if (tr_variantGetInt(b, &int_val))
{
values_[i].setValue(static_cast<qlonglong>(int_val));
auto const value = getValue<int64_t>(b);
if (value)
{
values_[i].setValue(*value);
}
}
break;
case CustomVariantType::SortModeType:
if (tr_variantGetStr(b, &str, nullptr))
{
values_[i] = QVariant::fromValue(SortMode(QString::fromUtf8(str)));
auto const value = getValue<QString>(b);
if (value)
{
values_[i] = QVariant::fromValue(SortMode(*value));
}
}
break;
case CustomVariantType::FilterModeType:
if (tr_variantGetStr(b, &str, nullptr))
{
values_[i] = QVariant::fromValue(FilterMode(QString::fromUtf8(str)));
auto const value = getValue<QString>(b);
if (value)
{
values_[i] = QVariant::fromValue(FilterMode(*value));
}
}
break;
case QVariant::String:
if (tr_variantGetStr(b, &str, &str_len))
{
values_[i].setValue(QString::fromUtf8(str, str_len));
auto const value = getValue<QString>(b);
if (value)
{
values_[i].setValue(*value);
}
}
break;
case QVariant::Bool:
if (tr_variantGetBool(b, &bool_val))
{
values_[i].setValue(static_cast<bool>(bool_val));
auto const value = getValue<bool>(b);
if (value)
{
values_[i].setValue(*value);
}
}
break;
case QVariant::Double:
if (tr_variantGetReal(b, &d))
{
values_[i].setValue(d);
auto const value = getValue<double>(b);
if (value)
{
values_[i].setValue(*value);
}
}
break;
case QVariant::DateTime:
if (tr_variantGetInt(b, &int_val))
{
values_[i].setValue(QDateTime::fromTime_t(int_val));
auto const value = getValue<time_t>(b);
if (value)
{
values_[i].setValue(QDateTime::fromTime_t(*value));
}
}
break;
default:
@ -243,44 +256,31 @@ Prefs::~Prefs()
switch (Items[i].type)
{
case QVariant::Int:
tr_variantDictAddInt(&current_settings, key, val.toInt());
dictAdd(&current_settings, key, val.toInt());
break;
case CustomVariantType::SortModeType:
tr_variantDictAddStr(&current_settings, key, val.value<SortMode>().name().toUtf8().constData());
dictAdd(&current_settings, key, val.value<SortMode>().name());
break;
case CustomVariantType::FilterModeType:
tr_variantDictAddStr(&current_settings, key, val.value<FilterMode>().name().toUtf8().constData());
dictAdd(&current_settings, key, val.value<FilterMode>().name());
break;
case QVariant::String:
{
QByteArray const ba(val.toByteArray());
char const* s = ba.constData();
if (Utils::isValidUtf8(s))
{
tr_variantDictAddStr(&current_settings, key, s);
}
else
{
tr_variantDictAddStr(&current_settings, key, val.toString().toUtf8().constData());
}
break;
}
dictAdd(&current_settings, key, val.toString());
break;
case QVariant::Bool:
tr_variantDictAddBool(&current_settings, key, val.toBool());
dictAdd(&current_settings, key, val.toBool());
break;
case QVariant::Double:
tr_variantDictAddReal(&current_settings, key, val.toDouble());
dictAdd(&current_settings, key, val.toDouble());
break;
case QVariant::DateTime:
tr_variantDictAddInt(&current_settings, key, val.toDateTime().toTime_t());
dictAdd(&current_settings, key, val.toDateTime().toTime_t());
break;
default:
@ -313,45 +313,45 @@ Prefs::~Prefs()
void Prefs::initDefaults(tr_variant* d)
{
tr_variantDictReserve(d, 38);
tr_variantDictAddBool(d, TR_KEY_blocklist_updates_enabled, true);
tr_variantDictAddBool(d, TR_KEY_compact_view, false);
tr_variantDictAddBool(d, TR_KEY_inhibit_desktop_hibernation, false);
tr_variantDictAddBool(d, TR_KEY_prompt_before_exit, true);
tr_variantDictAddBool(d, TR_KEY_remote_session_enabled, false);
tr_variantDictAddBool(d, TR_KEY_remote_session_requres_authentication, false);
tr_variantDictAddBool(d, TR_KEY_show_backup_trackers, false);
tr_variantDictAddBool(d, TR_KEY_show_extra_peer_details, false);
tr_variantDictAddBool(d, TR_KEY_show_filterbar, true);
tr_variantDictAddBool(d, TR_KEY_show_notification_area_icon, false);
tr_variantDictAddBool(d, TR_KEY_start_minimized, false);
tr_variantDictAddBool(d, TR_KEY_show_options_window, true);
tr_variantDictAddBool(d, TR_KEY_show_statusbar, true);
tr_variantDictAddBool(d, TR_KEY_show_toolbar, true);
tr_variantDictAddBool(d, TR_KEY_show_tracker_scrapes, false);
tr_variantDictAddBool(d, TR_KEY_sort_reversed, false);
tr_variantDictAddBool(d, TR_KEY_torrent_added_notification_enabled, true);
tr_variantDictAddBool(d, TR_KEY_torrent_complete_notification_enabled, true);
tr_variantDictAddStr(d, TR_KEY_torrent_complete_sound_command,
dictAdd(d, TR_KEY_blocklist_updates_enabled, true);
dictAdd(d, TR_KEY_compact_view, false);
dictAdd(d, TR_KEY_inhibit_desktop_hibernation, false);
dictAdd(d, TR_KEY_prompt_before_exit, true);
dictAdd(d, TR_KEY_remote_session_enabled, false);
dictAdd(d, TR_KEY_remote_session_requres_authentication, false);
dictAdd(d, TR_KEY_show_backup_trackers, false);
dictAdd(d, TR_KEY_show_extra_peer_details, false);
dictAdd(d, TR_KEY_show_filterbar, true);
dictAdd(d, TR_KEY_show_notification_area_icon, false);
dictAdd(d, TR_KEY_start_minimized, false);
dictAdd(d, TR_KEY_show_options_window, true);
dictAdd(d, TR_KEY_show_statusbar, true);
dictAdd(d, TR_KEY_show_toolbar, true);
dictAdd(d, TR_KEY_show_tracker_scrapes, false);
dictAdd(d, TR_KEY_sort_reversed, false);
dictAdd(d, TR_KEY_torrent_added_notification_enabled, true);
dictAdd(d, TR_KEY_torrent_complete_notification_enabled, true);
dictAdd(d, TR_KEY_torrent_complete_sound_command,
"canberra-gtk-play -i complete-download -d 'transmission torrent downloaded'");
tr_variantDictAddBool(d, TR_KEY_torrent_complete_sound_enabled, true);
tr_variantDictAddBool(d, TR_KEY_user_has_given_informed_consent, false);
tr_variantDictAddBool(d, TR_KEY_watch_dir_enabled, false);
tr_variantDictAddInt(d, TR_KEY_blocklist_date, 0);
tr_variantDictAddInt(d, TR_KEY_main_window_height, 500);
tr_variantDictAddInt(d, TR_KEY_main_window_width, 300);
tr_variantDictAddInt(d, TR_KEY_main_window_x, 50);
tr_variantDictAddInt(d, TR_KEY_main_window_y, 50);
tr_variantDictAddInt(d, TR_KEY_remote_session_port, strtol(TR_DEFAULT_RPC_PORT_STR, nullptr, 0));
tr_variantDictAddStr(d, TR_KEY_download_dir, tr_getDefaultDownloadDir());
tr_variantDictAddStr(d, TR_KEY_filter_mode, "all");
tr_variantDictAddStr(d, TR_KEY_main_window_layout_order, "menu,toolbar,filter,list,statusbar");
tr_variantDictAddStr(d, TR_KEY_open_dialog_dir, QDir::home().absolutePath().toUtf8());
tr_variantDictAddStr(d, TR_KEY_remote_session_host, "localhost");
tr_variantDictAddStr(d, TR_KEY_remote_session_password, "");
tr_variantDictAddStr(d, TR_KEY_remote_session_username, "");
tr_variantDictAddStr(d, TR_KEY_sort_mode, "sort-by-name");
tr_variantDictAddStr(d, TR_KEY_statusbar_stats, "total-ratio");
tr_variantDictAddStr(d, TR_KEY_watch_dir, tr_getDefaultDownloadDir());
dictAdd(d, TR_KEY_torrent_complete_sound_enabled, true);
dictAdd(d, TR_KEY_user_has_given_informed_consent, false);
dictAdd(d, TR_KEY_watch_dir_enabled, false);
dictAdd(d, TR_KEY_blocklist_date, 0);
dictAdd(d, TR_KEY_main_window_height, 500);
dictAdd(d, TR_KEY_main_window_width, 300);
dictAdd(d, TR_KEY_main_window_x, 50);
dictAdd(d, TR_KEY_main_window_y, 50);
dictAdd(d, TR_KEY_remote_session_port, TR_DEFAULT_RPC_PORT);
dictAdd(d, TR_KEY_download_dir, tr_getDefaultDownloadDir());
dictAdd(d, TR_KEY_filter_mode, "all");
dictAdd(d, TR_KEY_main_window_layout_order, "menu,toolbar,filter,list,statusbar");
dictAdd(d, TR_KEY_open_dialog_dir, QDir::home().absolutePath().toUtf8());
dictAdd(d, TR_KEY_remote_session_host, "localhost");
dictAdd(d, TR_KEY_remote_session_password, "");
dictAdd(d, TR_KEY_remote_session_username, "");
dictAdd(d, TR_KEY_sort_mode, "sort-by-name");
dictAdd(d, TR_KEY_statusbar_stats, "total-ratio");
dictAdd(d, TR_KEY_watch_dir, tr_getDefaultDownloadDir());
}
/***

View File

@ -144,11 +144,6 @@ public:
return !isCore(key);
}
char const* keyStr(int i) const
{
return tr_quark_get_string(Items[i].key, nullptr);
}
tr_quark getKey(int i) const
{
return Items[i].key;
@ -204,8 +199,7 @@ private:
void initDefaults(tr_variant*);
// Intentionally not implemented
void set(int key, char const* value);
void set(int key, char const* value) = delete;
QString const config_dir_;

View File

@ -21,12 +21,17 @@
#include <libtransmission/version.h> // LONG_VERSION_STRING
#include "RpcClient.h"
#include "VariantHelpers.h"
// #define DEBUG_HTTP
#define REQUEST_DATA_PROPERTY_KEY "requestData"
#define REQUEST_FUTUREINTERFACE_PROPERTY_KEY "requestReplyFutureInterface"
using ::trqt::variant_helpers::dictAdd;
using ::trqt::variant_helpers::dictFind;
using ::trqt::variant_helpers::variantInit;
namespace
{
@ -94,14 +99,16 @@ QUrl const& RpcClient::url() const
RpcResponseFuture RpcClient::exec(tr_quark method, tr_variant* args)
{
return exec(tr_quark_get_string(method, nullptr), args);
auto len = size_t{};
auto const* str = tr_quark_get_string(method, &len);
return exec(std::string_view(str, len), args);
}
RpcResponseFuture RpcClient::exec(char const* method, tr_variant* args)
RpcResponseFuture RpcClient::exec(std::string_view method, tr_variant* args)
{
TrVariantPtr json = createVariant();
tr_variantInitDict(json.get(), 3);
tr_variantDictAddStr(json.get(), TR_KEY_method, method);
dictAdd(json.get(), TR_KEY_method, method);
if (args != nullptr)
{
@ -162,7 +169,7 @@ void RpcClient::sendLocalRequest(TrVariantPtr json, QFutureInterface<RpcResponse
RpcResponseFuture RpcClient::sendRequest(TrVariantPtr json)
{
int64_t tag = getNextTag();
tr_variantDictAddInt(json.get(), TR_KEY_tag, tag);
dictAdd(json.get(), TR_KEY_tag, tag);
QFutureInterface<RpcResponse> promise;
promise.setExpectedResultCount(1);
@ -205,7 +212,7 @@ void RpcClient::localSessionCallback(tr_session* s, tr_variant* response, void*
TrVariantPtr json = createVariant();
*json = *response;
tr_variantInitBool(response, false);
variantInit(response, false);
// this callback is invoked in the libtransmission thread, so we don't want
// to process the response here... let's push it over to the Qt thread.
@ -281,26 +288,19 @@ void RpcClient::localRequestFinished(TrVariantPtr response)
int64_t RpcClient::parseResponseTag(tr_variant& json)
{
int64_t tag;
if (!tr_variantDictFindInt(&json, TR_KEY_tag, &tag))
{
tag = -1;
}
return tag;
auto const tag = dictFind<int>(&json, TR_KEY_tag);
return tag ? *tag : -1;
}
RpcResponse RpcClient::parseResponseData(tr_variant& json)
{
RpcResponse ret;
char const* result;
if (tr_variantDictFindStr(&json, TR_KEY_result, &result, nullptr))
auto const result = dictFind<QString>(&json, TR_KEY_result);
if (result)
{
ret.result = QString::fromUtf8(result);
ret.success = std::strcmp(result, "success") == 0;
ret.result = *result;
ret.success = *result == QStringLiteral("success");
}
tr_variant* args;
@ -309,7 +309,7 @@ RpcResponse RpcClient::parseResponseData(tr_variant& json)
{
ret.args = createVariant();
*ret.args = *args;
tr_variantInitBool(args, false);
variantInit(args, false);
}
return ret;

View File

@ -9,6 +9,7 @@
#pragma once
#include <memory>
#include <string_view>
#include <QFuture>
#include <QFutureInterface>
@ -62,7 +63,7 @@ public:
QUrl const& url() const;
RpcResponseFuture exec(tr_quark method, tr_variant* args);
RpcResponseFuture exec(char const* method, tr_variant* args);
RpcResponseFuture exec(std::string_view method, tr_variant* args);
signals:
void httpAuthenticationRequired();

View File

@ -34,6 +34,12 @@
#include "SessionDialog.h"
#include "Torrent.h"
#include "Utils.h"
#include "VariantHelpers.h"
using ::trqt::variant_helpers::dictAdd;
using ::trqt::variant_helpers::dictFind;
using ::trqt::variant_helpers::getValue;
using ::trqt::variant_helpers::listAdd;
/***
****
@ -44,16 +50,6 @@ namespace
using KeyList = Torrent::KeyList;
void addList(tr_variant* list, KeyList const& keys)
{
tr_variantListReserve(list, keys.size());
for (tr_quark const key : keys)
{
tr_variantListAddQuark(list, key);
}
}
// If this object is passed as "ids" (compared by address), then recently active torrents are queried.
auto const RecentlyActiveIDs = torrent_ids_t{ -1 };
@ -70,19 +66,19 @@ void Session::sessionSet(tr_quark const key, QVariant const& value)
switch (value.type())
{
case QVariant::Bool:
tr_variantDictAddBool(&args, key, value.toBool());
dictAdd(&args, key, value.toBool());
break;
case QVariant::Int:
tr_variantDictAddInt(&args, key, value.toInt());
dictAdd(&args, key, value.toInt());
break;
case QVariant::Double:
tr_variantDictAddReal(&args, key, value.toDouble());
dictAdd(&args, key, value.toDouble());
break;
case QVariant::String:
tr_variantDictAddStr(&args, key, value.toString().toUtf8().constData());
dictAdd(&args, key, value.toString());
break;
default:
@ -107,7 +103,11 @@ void Session::portTest()
if (r.success)
{
(void)tr_variantDictFindBool(r.args.get(), TR_KEY_port_is_open, &is_open);
auto const value = dictFind<bool>(r.args.get(), TR_KEY_port_is_open);
if (value)
{
is_open = *value;
}
}
emit portTested(is_open);
@ -120,8 +120,8 @@ void Session::copyMagnetLinkToClipboard(int torrent_id)
{
tr_variant args;
tr_variantInitDict(&args, 2);
tr_variantListAddInt(tr_variantDictAddList(&args, TR_KEY_ids, 1), torrent_id);
tr_variantListAddStr(tr_variantDictAddList(&args, TR_KEY_fields, 1), "magnetLink");
dictAdd(&args, TR_KEY_ids, std::array<int, 1>{ torrent_id });
dictAdd(&args, TR_KEY_fields, std::array<std::string_view, 1>{ "magnetLink" });
auto* q = new RpcQueue();
@ -140,11 +140,13 @@ void Session::copyMagnetLinkToClipboard(int torrent_id)
}
tr_variant* const child = tr_variantListChild(torrents, 0);
char const* str;
if (child != nullptr && tr_variantDictFindStr(child, TR_KEY_magnetLink, &str, nullptr))
if (child != nullptr)
{
qApp->clipboard()->setText(QString::fromUtf8(str));
auto const link = dictFind<QString>(child, TR_KEY_magnetLink);
if (link)
{
qApp->clipboard()->setText(*link);
}
}
});
@ -407,16 +409,11 @@ void addOptionalIds(tr_variant* args, torrent_ids_t const& ids)
{
if (&ids == &RecentlyActiveIDs)
{
tr_variantDictAddStr(args, TR_KEY_ids, "recently-active");
dictAdd(args, TR_KEY_ids, "recently-active");
}
else if (!ids.empty())
{
tr_variant* id_list(tr_variantDictAddList(args, TR_KEY_ids, ids.size()));
for (int const i : ids)
{
tr_variantListAddInt(id_list, i);
}
dictAdd(args, TR_KEY_ids, ids);
}
}
@ -426,8 +423,8 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, double va
{
tr_variant args;
tr_variantInitDict(&args, 2);
tr_variantDictAddReal(&args, key, value);
addOptionalIds(&args, ids);
dictAdd(&args, key, value);
exec(TR_KEY_torrent_set, &args);
}
@ -436,8 +433,8 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, int value
{
tr_variant args;
tr_variantInitDict(&args, 2);
tr_variantDictAddInt(&args, key, value);
addOptionalIds(&args, ids);
dictAdd(&args, key, value);
exec(TR_KEY_torrent_set, &args);
}
@ -446,8 +443,8 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, bool valu
{
tr_variant args;
tr_variantInitDict(&args, 2);
tr_variantDictAddBool(&args, key, value);
addOptionalIds(&args, ids);
dictAdd(&args, key, value);
exec(TR_KEY_torrent_set, &args);
}
@ -457,12 +454,7 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, QStringLi
tr_variant args;
tr_variantInitDict(&args, 2);
addOptionalIds(&args, ids);
tr_variant* list(tr_variantDictAddList(&args, key, value.size()));
for (QString const& str : value)
{
tr_variantListAddStr(list, str.toUtf8().constData());
}
dictAdd(&args, key, value);
exec(TR_KEY_torrent_set, &args);
}
@ -472,12 +464,7 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, QList<int
tr_variant args;
tr_variantInitDict(&args, 2);
addOptionalIds(&args, ids);
tr_variant* list(tr_variantDictAddList(&args, key, value.size()));
for (int const i : value)
{
tr_variantListAddInt(list, i);
}
dictAdd(&args, key, value);
exec(TR_KEY_torrent_set, &args);
}
@ -488,8 +475,8 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, QPair<int
tr_variantInitDict(&args, 2);
addOptionalIds(&args, ids);
tr_variant* list(tr_variantDictAddList(&args, key, 2));
tr_variantListAddInt(list, value.first);
tr_variantListAddStr(list, value.second.toUtf8().constData());
listAdd(list, value.first);
listAdd(list, value.second);
exec(TR_KEY_torrent_set, &args);
}
@ -499,8 +486,8 @@ void Session::torrentSetLocation(torrent_ids_t const& ids, QString const& locati
tr_variant args;
tr_variantInitDict(&args, 3);
addOptionalIds(&args, ids);
tr_variantDictAddStr(&args, TR_KEY_location, location.toUtf8().constData());
tr_variantDictAddBool(&args, TR_KEY_move, do_move);
dictAdd(&args, TR_KEY_location, location);
dictAdd(&args, TR_KEY_move, do_move);
exec(TR_KEY_torrent_set_location, &args);
}
@ -510,8 +497,8 @@ void Session::torrentRenamePath(torrent_ids_t const& ids, QString const& oldpath
tr_variant args;
tr_variantInitDict(&args, 2);
addOptionalIds(&args, ids);
tr_variantDictAddStr(&args, TR_KEY_path, oldpath.toUtf8().constData());
tr_variantDictAddStr(&args, TR_KEY_name, newname.toUtf8().constData());
dictAdd(&args, TR_KEY_path, oldpath);
dictAdd(&args, TR_KEY_name, newname);
auto* q = new RpcQueue();
@ -521,14 +508,14 @@ void Session::torrentRenamePath(torrent_ids_t const& ids, QString const& oldpath
},
[](RpcResponse const& r)
{
char const* path = "(unknown)";
char const* name = "(unknown)";
tr_variantDictFindStr(r.args.get(), TR_KEY_path, &path, nullptr);
tr_variantDictFindStr(r.args.get(), TR_KEY_name, &name, nullptr);
auto str = dictFind<QString>(r.args.get(), TR_KEY_path);
auto const path = str ? *str : QStringLiteral("(unknown)");
str = dictFind<QString>(r.args.get(), TR_KEY_name);
auto const name = str ? *str : QStringLiteral("(unknown)");
auto* d = new QMessageBox(QMessageBox::Information, tr("Error Renaming Path"),
tr(R"(<p><b>Unable to rename "%1" as "%2": %3.</b></p><p>Please correct the errors and try again.</p>)").
arg(QString::fromUtf8(path)).arg(QString::fromUtf8(name)).arg(r.result), QMessageBox::Close,
arg(path).arg(name).arg(r.result), QMessageBox::Close,
qApp->activeWindow());
QObject::connect(d, &QMessageBox::rejected, d, &QMessageBox::deleteLater);
d->show();
@ -546,8 +533,18 @@ void Session::refreshTorrents(torrent_ids_t const& ids, KeyList const& keys)
{
tr_variant args;
tr_variantInitDict(&args, 3);
tr_variantDictAddStr(&args, TR_KEY_format, "table");
addList(tr_variantDictAddList(&args, TR_KEY_fields, 0), keys);
dictAdd(&args, TR_KEY_format, "table");
std::vector<std::string_view> keystrs;
keystrs.reserve(keys.size());
for (auto const& key : keys)
{
auto len = size_t{};
auto const* str = tr_quark_get_string(key, &len);
keystrs.emplace_back(str, len);
}
dictAdd(&args, TR_KEY_fields, keystrs);
addOptionalIds(&args, ids);
auto* q = new RpcQueue();
@ -587,7 +584,7 @@ void Session::refreshExtraStats(torrent_ids_t const& ids)
refreshTorrents(ids, Torrent::MainStatKeys + Torrent::DetailStatKeys);
}
void Session::sendTorrentRequest(char const* request, torrent_ids_t const& ids)
void Session::sendTorrentRequest(std::string_view request, torrent_ids_t const& ids)
{
tr_variant args;
tr_variantInitDict(&args, 1);
@ -703,11 +700,10 @@ void Session::updateBlocklist()
q->add([this](RpcResponse const& r)
{
int64_t blocklist_size;
if (tr_variantDictFindInt(r.args.get(), TR_KEY_blocklist_size, &blocklist_size))
auto const size = dictFind<int>(r.args.get(), TR_KEY_blocklist_size);
if (size)
{
setBlocklistSize(blocklist_size);
setBlocklistSize(*size);
}
});
@ -723,38 +719,37 @@ RpcResponseFuture Session::exec(tr_quark method, tr_variant* args)
return rpc_.exec(method, args);
}
RpcResponseFuture Session::exec(char const* method, tr_variant* args)
RpcResponseFuture Session::exec(std::string_view method, tr_variant* args)
{
return rpc_.exec(method, args);
}
void Session::updateStats(tr_variant* d, tr_session_stats* stats)
{
int64_t i;
if (tr_variantDictFindInt(d, TR_KEY_uploadedBytes, &i))
auto value = dictFind<int>(d, TR_KEY_uploadedBytes);
if (value)
{
stats->uploadedBytes = i;
stats->uploadedBytes = *value;
}
if (tr_variantDictFindInt(d, TR_KEY_downloadedBytes, &i))
if ((value = dictFind<int>(d, TR_KEY_downloadedBytes)))
{
stats->downloadedBytes = i;
stats->downloadedBytes = *value;
}
if (tr_variantDictFindInt(d, TR_KEY_filesAdded, &i))
if ((value = dictFind<int>(d, TR_KEY_filesAdded)))
{
stats->filesAdded = i;
stats->filesAdded = *value;
}
if (tr_variantDictFindInt(d, TR_KEY_sessionCount, &i))
if ((value = dictFind<int>(d, TR_KEY_sessionCount)))
{
stats->sessionCount = i;
stats->sessionCount = *value;
}
if (tr_variantDictFindInt(d, TR_KEY_secondsActive, &i))
if ((value = dictFind<int>(d, TR_KEY_secondsActive)))
{
stats->secondsActive = i;
stats->secondsActive = *value;
}
stats->ratio = tr_getRatio(stats->uploadedBytes, stats->downloadedBytes);
@ -779,9 +774,6 @@ void Session::updateStats(tr_variant* d)
void Session::updateInfo(tr_variant* d)
{
int64_t i;
char const* str;
disconnect(&prefs_, SIGNAL(changed(int)), this, SLOT(updatePref(int)));
for (int i = Prefs::FIRST_CORE_PREF; i <= Prefs::LAST_CORE_PREF; ++i)
@ -795,19 +787,19 @@ void Session::updateInfo(tr_variant* d)
if (i == Prefs::ENCRYPTION)
{
char const* val;
auto const str = getValue<QString>(b);
if (tr_variantGetStr(b, &val, nullptr))
if (str)
{
if (qstrcmp(val, "required") == 0)
if (*str == QStringLiteral("required"))
{
prefs_.set(i, 2);
}
else if (qstrcmp(val, "preferred") == 0)
else if (*str == QStringLiteral("preferred"))
{
prefs_.set(i, 1);
}
else if (qstrcmp(val, "tolerated") == 0)
else if (*str == QStringLiteral("tolerated"))
{
prefs_.set(i, 0);
}
@ -820,11 +812,11 @@ void Session::updateInfo(tr_variant* d)
{
case QVariant::Int:
{
int64_t val;
auto const value = getValue<int>(b);
if (tr_variantGetInt(b, &val))
if (value)
{
prefs_.set(i, static_cast<int>(val));
prefs_.set(i, *value);
}
break;
@ -832,11 +824,11 @@ void Session::updateInfo(tr_variant* d)
case QVariant::Double:
{
double val;
auto const value = getValue<double>(b);
if (tr_variantGetReal(b, &val))
if (value)
{
prefs_.set(i, val);
prefs_.set(i, *value);
}
break;
@ -844,11 +836,11 @@ void Session::updateInfo(tr_variant* d)
case QVariant::Bool:
{
bool val;
auto const value = getValue<bool>(b);
if (tr_variantGetBool(b, &val))
if (value)
{
prefs_.set(i, val);
prefs_.set(i, *value);
}
break;
@ -858,11 +850,11 @@ void Session::updateInfo(tr_variant* d)
case CustomVariantType::SortModeType:
case QVariant::String:
{
char const* val;
auto const value = getValue<QString>(b);
if (tr_variantGetStr(b, &val, nullptr))
if (value)
{
prefs_.set(i, QString::fromUtf8(val));
prefs_.set(i, *value);
}
break;
@ -873,17 +865,16 @@ void Session::updateInfo(tr_variant* d)
}
}
bool b;
double x;
if (tr_variantDictFindBool(d, TR_KEY_seedRatioLimited, &b))
auto const b = dictFind<bool>(d, TR_KEY_seedRatioLimited);
if (b)
{
prefs_.set(Prefs::RATIO_ENABLED, b);
prefs_.set(Prefs::RATIO_ENABLED, *b);
}
if (tr_variantDictFindReal(d, TR_KEY_seedRatioLimit, &x))
auto const x = dictFind<double>(d, TR_KEY_seedRatioLimit);
if (x)
{
prefs_.set(Prefs::RATIO, x);
prefs_.set(Prefs::RATIO, *x);
}
/* Use the C API to get settings that, for security reasons, aren't supported by RPC */
@ -898,25 +889,23 @@ void Session::updateInfo(tr_variant* d)
prefs_.set(Prefs::RPC_WHITELIST, QString::fromUtf8(tr_sessionGetRPCWhitelist(session_)));
}
if (tr_variantDictFindInt(d, TR_KEY_blocklist_size, &i) && i != blocklistSize())
auto const size = dictFind<int>(d, TR_KEY_blocklist_size);
if (size && *size != blocklistSize())
{
setBlocklistSize(i);
setBlocklistSize(*size);
}
if (tr_variantDictFindStr(d, TR_KEY_version, &str, nullptr) && session_version_ != QString::fromUtf8(str))
auto str = dictFind<QString>(d, TR_KEY_version);
if (str)
{
session_version_ = QString::fromUtf8(str);
session_version_ = *str;
}
if (tr_variantDictFindStr(d, TR_KEY_session_id, &str, nullptr))
str = dictFind<QString>(d, TR_KEY_session_id);
if (str)
{
QString const session_id = QString::fromUtf8(str);
if (session_id_ != session_id)
{
session_id_ = session_id;
is_definitely_local_session_ = tr_session_id_is_local(str);
}
session_id_ = *str;
is_definitely_local_session_ = tr_session_id_is_local(session_id_.toUtf8().constData());
}
else
{
@ -943,26 +932,23 @@ void Session::addTorrent(AddData const& add_me, tr_variant* args, bool trash_ori
if (tr_variantDictFind(args, TR_KEY_paused) == nullptr)
{
tr_variantDictAddBool(args, TR_KEY_paused, !prefs_.getBool(Prefs::START));
dictAdd(args, TR_KEY_paused, !prefs_.getBool(Prefs::START));
}
switch (add_me.type)
{
case AddData::MAGNET:
tr_variantDictAddStr(args, TR_KEY_filename, add_me.magnet.toUtf8().constData());
dictAdd(args, TR_KEY_filename, add_me.magnet);
break;
case AddData::URL:
tr_variantDictAddStr(args, TR_KEY_filename, add_me.url.toString().toUtf8().constData());
dictAdd(args, TR_KEY_filename, add_me.url.toString());
break;
case AddData::FILENAME: /* fall-through */
case AddData::METAINFO:
{
QByteArray const b64 = add_me.toBase64();
tr_variantDictAddRaw(args, TR_KEY_metainfo, b64.constData(), b64.size());
break;
}
dictAdd(args, TR_KEY_metainfo, add_me.toBase64());
break;
default:
qWarning() << "Unhandled AddData type: " << add_me.type;
@ -993,14 +979,12 @@ void Session::addTorrent(AddData const& add_me, tr_variant* args, bool trash_ori
return;
}
char const* str;
if (tr_variantDictFindStr(dup, TR_KEY_name, &str, nullptr))
auto const name = dictFind<QString>(dup, TR_KEY_name);
if (name)
{
QString const name = QString::fromUtf8(str);
auto* d = new QMessageBox(QMessageBox::Warning, tr("Add Torrent"),
tr(R"(<p><b>Unable to add "%1".</b></p><p>It is a duplicate of "%2" which is already added.</p>)").
arg(add_me.readableShortName()).arg(name), QMessageBox::Close, qApp->activeWindow());
arg(add_me.readableShortName()).arg(*name), QMessageBox::Close, qApp->activeWindow());
QObject::connect(d, &QMessageBox::rejected, d, &QMessageBox::deleteLater);
d->show();
}
@ -1033,9 +1017,9 @@ void Session::addNewlyCreatedTorrent(QString const& filename, QString const& loc
tr_variant args;
tr_variantInitDict(&args, 3);
tr_variantDictAddStr(&args, TR_KEY_download_dir, local_path.toUtf8().constData());
tr_variantDictAddBool(&args, TR_KEY_paused, !prefs_.getBool(Prefs::START));
tr_variantDictAddRaw(&args, TR_KEY_metainfo, b64.constData(), b64.size());
dictAdd(&args, TR_KEY_download_dir, local_path);
dictAdd(&args, TR_KEY_paused, !prefs_.getBool(Prefs::START));
dictAdd(&args, TR_KEY_metainfo, b64);
exec("torrent-add", &args);
}
@ -1047,7 +1031,7 @@ void Session::removeTorrents(torrent_ids_t const& ids, bool delete_files)
tr_variant args;
tr_variantInitDict(&args, 2);
addOptionalIds(&args, ids);
tr_variantDictAddInt(&args, TR_KEY_delete_local_data, delete_files);
dictAdd(&args, TR_KEY_delete_local_data, delete_files);
exec("torrent-remove", &args);
}

View File

@ -8,6 +8,8 @@
#pragma once
#include <string_view>
#include <QObject>
#include <QString>
#include <QStringList>
@ -75,7 +77,7 @@ public:
bool isLocal() const;
RpcResponseFuture exec(tr_quark method, tr_variant* args);
RpcResponseFuture exec(char const* method, tr_variant* args);
RpcResponseFuture exec(std::string_view method, tr_variant* args);
void torrentSet(torrent_ids_t const& ids, tr_quark const key, bool val);
void torrentSet(torrent_ids_t const& ids, tr_quark const key, int val);
@ -131,7 +133,7 @@ private:
void sessionSet(tr_quark const key, QVariant const& variant);
void pumpRequests();
void sendTorrentRequest(char const* request, torrent_ids_t const& torrent_ids);
void sendTorrentRequest(std::string_view request, torrent_ids_t const& torrent_ids);
void refreshTorrents(torrent_ids_t const& torrent_ids, Torrent::KeyList const& keys);
static void updateStats(tr_variant* d, tr_session_stats* stats);

View File

@ -22,6 +22,9 @@
#include "Prefs.h"
#include "Torrent.h"
#include "Utils.h"
#include "VariantHelpers.h"
using ::trqt::variant_helpers::change;
/***
****
@ -120,248 +123,6 @@ Torrent::Torrent(Prefs const& prefs, int id) :
****
***/
namespace
{
template<typename T>
bool change(T& setme, T const& value)
{
bool const changed = setme != value;
if (changed)
{
setme = value;
}
return changed;
}
bool change(double& setme, double const& value)
{
bool const changed = !qFuzzyCompare(setme + 1, value + 1);
if (changed)
{
setme = value;
}
return changed;
}
bool change(double& setme, tr_variant const* value)
{
double d;
return tr_variantGetReal(value, &d) && change(setme, d);
}
bool change(int& setme, tr_variant const* value)
{
int64_t i;
return tr_variantGetInt(value, &i) && change(setme, static_cast<int>(i));
}
bool change(uint64_t& setme, tr_variant const* value)
{
int64_t i;
return tr_variantGetInt(value, &i) && change(setme, static_cast<uint64_t>(i));
}
bool change(time_t& setme, tr_variant const* value)
{
int64_t i;
return tr_variantGetInt(value, &i) && change(setme, static_cast<time_t>(i));
}
bool change(Speed& setme, tr_variant const* value)
{
int64_t i;
return tr_variantGetInt(value, &i) && change(setme, Speed::fromBps(i));
}
bool change(bool& setme, tr_variant const* value)
{
bool b;
return tr_variantGetBool(value, &b) && change(setme, b);
}
bool change(QString& setme, tr_variant const* value)
{
bool changed = false;
char const* str;
size_t len;
if (!tr_variantGetStr(value, &str, &len))
{
return changed;
}
if (len == 0)
{
changed = !setme.isEmpty();
setme.clear();
return changed;
}
return change(setme, QString::fromUtf8(str, len));
}
bool change(Peer& setme, tr_variant const* value)
{
bool changed = false;
size_t pos = 0;
tr_quark key;
tr_variant* child;
while (tr_variantDictChild(const_cast<tr_variant*>(value), pos++, &key, &child))
{
switch (key)
{
#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \
changed = change(setme.field, child) || changed; break;
HANDLE_KEY(address, address)
HANDLE_KEY(clientIsChoked, client_is_choked)
HANDLE_KEY(clientIsInterested, client_is_interested)
HANDLE_KEY(clientName, client_name)
HANDLE_KEY(flagStr, flags)
HANDLE_KEY(isDownloadingFrom, is_downloading_from)
HANDLE_KEY(isEncrypted, is_encrypted)
HANDLE_KEY(isIncoming, is_incoming)
HANDLE_KEY(isUploadingTo, is_uploading_to)
HANDLE_KEY(peerIsChoked, peer_is_choked)
HANDLE_KEY(peerIsInterested, peer_is_interested)
HANDLE_KEY(port, port)
HANDLE_KEY(progress, progress)
HANDLE_KEY(rateToClient, rate_to_client)
HANDLE_KEY(rateToPeer, rate_to_peer)
#undef HANDLE_KEY
default:
break;
}
}
return changed;
}
bool change(TorrentFile& setme, tr_variant const* value)
{
bool changed = false;
size_t pos = 0;
tr_quark key;
tr_variant* child;
while (tr_variantDictChild(const_cast<tr_variant*>(value), pos++, &key, &child))
{
switch (key)
{
#define HANDLE_KEY(key) case TR_KEY_ ## key: \
changed = change(setme.key, child) || changed; break;
HANDLE_KEY(have)
HANDLE_KEY(priority)
HANDLE_KEY(wanted)
#undef HANDLE_KEY
#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \
changed = change(setme.field, child) || changed; break;
HANDLE_KEY(bytesCompleted, have)
HANDLE_KEY(length, size)
HANDLE_KEY(name, filename)
#undef HANDLE_KEY
default:
break;
}
}
return changed;
}
bool change(TrackerStat& setme, tr_variant const* value)
{
bool changed = false;
size_t pos = 0;
tr_quark key;
tr_variant* child;
while (tr_variantDictChild(const_cast<tr_variant*>(value), pos++, &key, &child))
{
bool field_changed = false;
switch (key)
{
#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \
field_changed = change(setme.field, child); break;
HANDLE_KEY(announce, announce)
HANDLE_KEY(announceState, announce_state)
HANDLE_KEY(downloadCount, download_count)
HANDLE_KEY(hasAnnounced, has_announced)
HANDLE_KEY(hasScraped, has_scraped)
HANDLE_KEY(host, host);
HANDLE_KEY(id, id);
HANDLE_KEY(isBackup, is_backup);
HANDLE_KEY(lastAnnouncePeerCount, last_announce_peer_count);
HANDLE_KEY(lastAnnounceResult, last_announce_result);
HANDLE_KEY(lastAnnounceStartTime, last_announce_start_time)
HANDLE_KEY(lastAnnounceSucceeded, last_announce_succeeded)
HANDLE_KEY(lastAnnounceTime, last_announce_time)
HANDLE_KEY(lastAnnounceTimedOut, last_announce_timed_out)
HANDLE_KEY(lastScrapeResult, last_scrape_result)
HANDLE_KEY(lastScrapeStartTime, last_scrape_start_time)
HANDLE_KEY(lastScrapeSucceeded, last_scrape_succeeded)
HANDLE_KEY(lastScrapeTime, last_scrape_time)
HANDLE_KEY(lastScrapeTimedOut, last_scrape_timed_out)
HANDLE_KEY(leecherCount, leecher_count)
HANDLE_KEY(nextAnnounceTime, next_announce_time)
HANDLE_KEY(nextScrapeTime, next_scrape_time)
HANDLE_KEY(scrapeState, scrape_state)
HANDLE_KEY(seederCount, seeder_count)
HANDLE_KEY(tier, tier)
#undef HANDLE_KEY
default:
break;
}
if (field_changed)
{
if (key == TR_KEY_announce)
{
setme.favicon_key = qApp->faviconCache().add(QUrl(setme.announce));
}
changed = true;
}
}
return changed;
}
template<typename T>
bool change(QVector<T>& setme, tr_variant const* value)
{
bool changed = false;
int const n = tr_variantListSize(value);
if (setme.size() != n)
{
setme.resize(n);
changed = true;
}
for (int i = 0; i < n; ++i)
{
changed = change(setme[i], tr_variantListChild(const_cast<tr_variant*>(value), i)) || changed;
}
return changed;
}
} // anonymous namespace
/***
****
***/
bool Torrent::getSeedRatio(double& setmeRatio) const
{
bool is_limited;

View File

@ -17,6 +17,9 @@
#include "Torrent.h"
#include "TorrentDelegate.h"
#include "TorrentModel.h"
#include "VariantHelpers.h"
using ::trqt::variant_helpers::getValue;
/***
****
@ -131,17 +134,14 @@ void TorrentModel::removeTorrents(tr_variant* list)
tr_variant* child;
while ((child = tr_variantListChild(list, i++)) != nullptr)
{
int64_t id;
Torrent* torrent = nullptr;
if (tr_variantGetInt(child, &id))
auto const id = getValue<int>(child);
if (id)
{
torrent = getTorrentFromId(id);
}
if (torrent != nullptr)
{
torrents.push_back(torrent);
auto* torrent = getTorrentFromId(*id);
if (torrent != nullptr)
{
torrents.push_back(torrent);
}
}
}
@ -242,18 +242,18 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool is_complete_list)
}
// Find the torrent id
int64_t id;
if (!tr_variantGetInt(values[id_pos], &id))
auto const id = getValue<int>(values[id_pos]);
if (!id)
{
continue;
}
Torrent* tor = getTorrentFromId(id);
Torrent* tor = getTorrentFromId(*id);
bool is_new = false;
if (tor == nullptr)
{
tor = new Torrent(prefs_, id);
tor = new Torrent(prefs_, *id);
instantiated.push_back(tor);
is_new = true;
}
@ -263,28 +263,28 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool is_complete_list)
if (fields.any())
{
changed_fields |= fields;
changed.insert(id);
changed.insert(*id);
}
if (fields.test(Torrent::EDIT_DATE))
{
edited.insert(id);
edited.insert(*id);
}
if (is_new && !tor->hasName())
{
needinfo.insert(id);
needinfo.insert(*id);
}
if (recently_added(tor) && tor->hasName() && !already_added_.count(id))
if (recently_added(tor) && tor->hasName() && !already_added_.count(*id))
{
added.insert(id);
already_added_.insert(id);
added.insert(*id);
already_added_.insert(*id);
}
if (fields.test(Torrent::LEFT_UNTIL_DONE) && (tor->leftUntilDone() == 0) && (tor->downloadedEver() > 0))
{
completed.insert(id);
completed.insert(*id);
}
processed.push_back(tor);

213
qt/VariantHelpers.cc Normal file
View File

@ -0,0 +1,213 @@
/*
* This file Copyright (C) 2020 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include "VariantHelpers.h"
#include <QtGlobal> // qFuzzyCompare
#include <QUrl>
#include "Application.h" // qApp
#include "Filters.h"
#include "Speed.h"
#include "Torrent.h"
namespace trqt::variant_helpers
{
bool change(double& setme, double const& value)
{
bool const changed = !qFuzzyCompare(setme + 1, value + 1);
if (changed)
{
setme = value;
}
return changed;
}
bool change(Speed& setme, tr_variant const* variant)
{
auto const value = getValue<int>(variant);
return value && change(setme, Speed::fromBps(*value));
}
bool change(Peer& setme, tr_variant const* value)
{
bool changed = false;
size_t pos = 0;
tr_quark key;
tr_variant* child;
while (tr_variantDictChild(const_cast<tr_variant*>(value), pos++, &key, &child))
{
switch (key)
{
#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \
changed = change(setme.field, child) || changed; break;
HANDLE_KEY(address, address)
HANDLE_KEY(clientIsChoked, client_is_choked)
HANDLE_KEY(clientIsInterested, client_is_interested)
HANDLE_KEY(clientName, client_name)
HANDLE_KEY(flagStr, flags)
HANDLE_KEY(isDownloadingFrom, is_downloading_from)
HANDLE_KEY(isEncrypted, is_encrypted)
HANDLE_KEY(isIncoming, is_incoming)
HANDLE_KEY(isUploadingTo, is_uploading_to)
HANDLE_KEY(peerIsChoked, peer_is_choked)
HANDLE_KEY(peerIsInterested, peer_is_interested)
HANDLE_KEY(port, port)
HANDLE_KEY(progress, progress)
HANDLE_KEY(rateToClient, rate_to_client)
HANDLE_KEY(rateToPeer, rate_to_peer)
#undef HANDLE_KEY
default:
break;
}
}
return changed;
}
bool change(TorrentFile& setme, tr_variant const* value)
{
bool changed = false;
size_t pos = 0;
tr_quark key;
tr_variant* child;
while (tr_variantDictChild(const_cast<tr_variant*>(value), pos++, &key, &child))
{
switch (key)
{
#define HANDLE_KEY(key) case TR_KEY_ ## key: \
changed = change(setme.key, child) || changed; break;
HANDLE_KEY(have)
HANDLE_KEY(priority)
HANDLE_KEY(wanted)
#undef HANDLE_KEY
#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \
changed = change(setme.field, child) || changed; break;
HANDLE_KEY(bytesCompleted, have)
HANDLE_KEY(length, size)
HANDLE_KEY(name, filename)
#undef HANDLE_KEY
default:
break;
}
}
return changed;
}
bool change(TrackerStat& setme, tr_variant const* value)
{
bool changed = false;
size_t pos = 0;
tr_quark key;
tr_variant* child;
while (tr_variantDictChild(const_cast<tr_variant*>(value), pos++, &key, &child))
{
bool field_changed = false;
switch (key)
{
#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \
field_changed = change(setme.field, child); break;
HANDLE_KEY(announce, announce)
HANDLE_KEY(announceState, announce_state)
HANDLE_KEY(downloadCount, download_count)
HANDLE_KEY(hasAnnounced, has_announced)
HANDLE_KEY(hasScraped, has_scraped)
HANDLE_KEY(host, host);
HANDLE_KEY(id, id);
HANDLE_KEY(isBackup, is_backup);
HANDLE_KEY(lastAnnouncePeerCount, last_announce_peer_count);
HANDLE_KEY(lastAnnounceResult, last_announce_result);
HANDLE_KEY(lastAnnounceStartTime, last_announce_start_time)
HANDLE_KEY(lastAnnounceSucceeded, last_announce_succeeded)
HANDLE_KEY(lastAnnounceTime, last_announce_time)
HANDLE_KEY(lastAnnounceTimedOut, last_announce_timed_out)
HANDLE_KEY(lastScrapeResult, last_scrape_result)
HANDLE_KEY(lastScrapeStartTime, last_scrape_start_time)
HANDLE_KEY(lastScrapeSucceeded, last_scrape_succeeded)
HANDLE_KEY(lastScrapeTime, last_scrape_time)
HANDLE_KEY(lastScrapeTimedOut, last_scrape_timed_out)
HANDLE_KEY(leecherCount, leecher_count)
HANDLE_KEY(nextAnnounceTime, next_announce_time)
HANDLE_KEY(nextScrapeTime, next_scrape_time)
HANDLE_KEY(scrapeState, scrape_state)
HANDLE_KEY(seederCount, seeder_count)
HANDLE_KEY(tier, tier)
#undef HANDLE_KEY
default:
break;
}
if (field_changed)
{
if (key == TR_KEY_announce)
{
setme.favicon_key = qApp->faviconCache().add(QUrl(setme.announce));
}
changed = true;
}
}
return changed;
}
///
void variantInit(tr_variant* init_me, bool value)
{
tr_variantInitBool(init_me, value);
}
void variantInit(tr_variant* init_me, int64_t value)
{
tr_variantInitInt(init_me, value);
}
void variantInit(tr_variant* init_me, int value)
{
tr_variantInitInt(init_me, value);
}
void variantInit(tr_variant* init_me, unsigned int value)
{
tr_variantInitInt(init_me, value);
}
void variantInit(tr_variant* init_me, double value)
{
tr_variantInitReal(init_me, value);
}
void variantInit(tr_variant* init_me, QByteArray const& value)
{
tr_variantInitRaw(init_me, value.constData(), value.size());
}
void variantInit(tr_variant* init_me, QString const& value)
{
variantInit(init_me, value.toUtf8());
}
void variantInit(tr_variant* init_me, std::string_view value)
{
tr_variantInitStr(init_me, std::data(value), std::size(value));
}
} // namespace trqt::variant_helpers

187
qt/VariantHelpers.h Normal file
View File

@ -0,0 +1,187 @@
/*
* This file Copyright (C) 2020 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#pragma once
#include <string_view>
#include <optional>
#include <QString>
#include <QVector>
#include <libtransmission/variant.h>
class QByteArray;
class Speed;
struct Peer;
struct TorrentFile;
struct TrackerStat;
namespace trqt
{
namespace variant_helpers
{
template<typename T,
typename std::enable_if<std::is_same_v<T, bool>>::type* = nullptr>
auto getValue(tr_variant const* variant)
{
std::optional<T> ret;
auto value = T {};
if (tr_variantGetBool(variant, &value))
{
ret = value;
}
return ret;
}
template<typename T,
typename std::enable_if<std::is_same_v<T, int64_t>||
std::is_same_v<T, uint64_t>||
std::is_same_v<T, int>||
std::is_same_v<T, time_t>>::type* = nullptr>
auto getValue(tr_variant const* variant)
{
std::optional<T> ret;
auto value = int64_t {};
if (tr_variantGetInt(variant, &value))
{
ret = value;
}
return ret;
}
template<typename T,
typename std::enable_if<std::is_same_v<T, double>>::type* = nullptr>
auto getValue(tr_variant const* variant)
{
std::optional<T> ret;
auto value = T {};
if (tr_variantGetReal(variant, &value))
{
ret = value;
}
return ret;
}
template<typename T, typename std::enable_if<std::is_same_v<T, QString>>::type* = nullptr>
auto getValue(tr_variant const* variant)
{
std::optional<T> ret;
char const* str;
size_t len;
if (tr_variantGetStr(variant, &str, &len))
{
ret = QString::fromUtf8(str, len);
}
return ret;
}
template<typename T>
bool change(T& setme, T const& value)
{
bool const changed = setme != value;
if (changed)
{
setme = value;
}
return changed;
}
bool change(double& setme, double const& value);
bool change(Speed& setme, tr_variant const* value);
bool change(Peer& setme, tr_variant const* value);
bool change(TorrentFile& setme, tr_variant const* value);
bool change(TrackerStat& setme, tr_variant const* value);
template<typename T>
bool change(T& setme, tr_variant const* variant)
{
auto const value = getValue<T>(variant);
return value && change(setme, *value);
}
template<typename T>
bool change(QVector<T>& setme, tr_variant const* value)
{
bool changed = false;
int const n = tr_variantListSize(value);
if (setme.size() != n)
{
setme.resize(n);
changed = true;
}
for (int i = 0; i < n; ++i)
{
changed = change(setme[i], tr_variantListChild(const_cast<tr_variant*>(value), i)) || changed;
}
return changed;
}
///
template<typename T>
auto dictFind(tr_variant* dict, tr_quark key)
{
std::optional<T> ret;
auto const* child = tr_variantDictFind(dict, key);
if (child != nullptr)
{
ret = getValue<T>(child);
}
return ret;
}
///
void variantInit(tr_variant* init_me, bool value);
void variantInit(tr_variant* init_me, int64_t value);
void variantInit(tr_variant* init_me, int value);
void variantInit(tr_variant* init_me, unsigned int value);
void variantInit(tr_variant* init_me, double value);
void variantInit(tr_variant* init_me, QByteArray const& value);
void variantInit(tr_variant* init_me, QString const& value);
void variantInit(tr_variant* init_me, std::string_view value);
template<typename C, typename T = typename C::value_type>
void variantInit(tr_variant* init_me, C const& value)
{
tr_variantInitList(init_me, std::size(value));
for (auto const& item : value)
{
variantInit(tr_variantListAdd(init_me), item);
}
}
template<typename T>
void listAdd(tr_variant* list, T const& value)
{
variantInit(tr_variantListAdd(list), value);
}
template<typename T>
void dictAdd(tr_variant* dict, tr_quark key, T const& value)
{
variantInit(tr_variantDictAdd(dict, key), value);
}
} // namespace variant_helpers
} // trqt

View File

@ -119,6 +119,7 @@ SOURCES += AboutDialog.cc \
TrackerModel.cc \
TrackerModelFilter.cc \
Utils.cc \
VariantHelpers.cc \
WatchDir.cc
HEADERS += $$replace(SOURCES, .cc, .h)
HEADERS += BaseDialog.h CustomVariantType.h Speed.h Typedefs.h

View File

@ -32,7 +32,7 @@
#define MY_NAME "transmission-remote"
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT atoi(TR_DEFAULT_RPC_PORT_STR)
#define DEFAULT_PORT TR_DEFAULT_RPC_PORT
#define DEFAULT_URL TR_DEFAULT_RPC_URL_STR "rpc/"
#define ARGUMENTS TR_KEY_arguments