mirror of
https://github.com/transmission/transmission.git
synced 2025-12-12 20:35:49 +01:00
refactor: replace Settings class with Serializable (#7877)
* refactor: replace Settings class with Serializable * Fields can now be declared as const static, so we only have to build this list once per class instead of once per iteration. * Add typesafe single-property getters & setters. * Split the converter registry into a generic standalone class. * refactor: make Serializable::Field::getter private refactor: make Serializable::Field::const_getter private * docs: tweak code comments * refactor: make Serializable::Field::Getter private refactor: make Serializable::Field::ConstGetter private refactor: make Serializable::Field::MemberStorage private * chore: fix readability-identifier-naming clang-tidy warnings * Update libtransmission/serializable.h Co-authored-by: Yat Ho <lagoho7@gmail.com> * Update libtransmission/serializable.h Co-authored-by: Yat Ho <lagoho7@gmail.com> * Update libtransmission/serializable.h Co-authored-by: Yat Ho <lagoho7@gmail.com> * fixup! Update libtransmission/serializable.h --------- Co-authored-by: Yat Ho <lagoho7@gmail.com>
This commit is contained in:
@@ -452,8 +452,8 @@
|
||||
ED5E0EA22CD314FE0071433B /* style.css in Resources */ = {isa = PBXBuildFile; fileRef = ED5E0EA12CD314FE0071433B /* style.css */; };
|
||||
ED5E0EFA2CD315720071433B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = ED5E0EF72CD315720071433B /* Localizable.strings */; };
|
||||
ED5E0F0F2CD31BC20071433B /* NSStringAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4DE5CC9C0980656F00BE280E /* NSStringAdditions.mm */; };
|
||||
ED67FB422B70FCE400D8A037 /* settings.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED67FB402B70FCE400D8A037 /* settings.cc */; };
|
||||
ED67FB432B70FCE400D8A037 /* settings.h in Headers */ = {isa = PBXBuildFile; fileRef = ED67FB412B70FCE400D8A037 /* settings.h */; };
|
||||
ED67FB422B70FCE400D8A037 /* serializable.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED67FB402B70FCE400D8A037 /* serializable.cc */; };
|
||||
ED67FB432B70FCE400D8A037 /* serializable.h in Headers */ = {isa = PBXBuildFile; fileRef = ED67FB412B70FCE400D8A037 /* serializable.h */; };
|
||||
ED6F16B52EB8F1EB007CD864 /* FileNameCellView.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED6F16B22EB8F1EB007CD864 /* FileNameCellView.mm */; };
|
||||
ED6F16B62EB8F1EB007CD864 /* FilePriorityCellView.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED6F16B42EB8F1EB007CD864 /* FilePriorityCellView.mm */; };
|
||||
ED6F16B72EB8F1EB007CD864 /* FileCheckCellView.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED6F16B02EB8F1EB007CD864 /* FileCheckCellView.mm */; };
|
||||
@@ -1439,8 +1439,8 @@
|
||||
ED5E0F0C2CD3163B0071433B /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
ED5E0F0D2CD316450071433B /* zh-CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-CN"; path = "zh-CN.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
ED5E0F0E2CD3164D0071433B /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-TW"; path = "zh-TW.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
ED67FB402B70FCE400D8A037 /* settings.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = settings.cc; sourceTree = "<group>"; };
|
||||
ED67FB412B70FCE400D8A037 /* settings.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = settings.h; sourceTree = "<group>"; };
|
||||
ED67FB402B70FCE400D8A037 /* serializable.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = serializable.cc; sourceTree = "<group>"; };
|
||||
ED67FB412B70FCE400D8A037 /* serializable.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = serializable.h; sourceTree = "<group>"; };
|
||||
ED6F16AF2EB8F1EB007CD864 /* FileCheckCellView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FileCheckCellView.h; sourceTree = "<group>"; };
|
||||
ED6F16B02EB8F1EB007CD864 /* FileCheckCellView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FileCheckCellView.mm; sourceTree = "<group>"; };
|
||||
ED6F16B12EB8F1EB007CD864 /* FileNameCellView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FileNameCellView.h; sourceTree = "<group>"; };
|
||||
@@ -2005,8 +2005,8 @@
|
||||
BEFC1E140C07861A00B0BB3C /* session.h */,
|
||||
CCEBA596277340F6DF9F4481 /* session-alt-speeds.cc */,
|
||||
CCEBA596277340F6DF9F4483 /* session-alt-speeds.h */,
|
||||
ED67FB402B70FCE400D8A037 /* settings.cc */,
|
||||
ED67FB412B70FCE400D8A037 /* settings.h */,
|
||||
ED67FB402B70FCE400D8A037 /* serializable.cc */,
|
||||
ED67FB412B70FCE400D8A037 /* serializable.h */,
|
||||
A25D2CBB0CF4C7190096A262 /* stats.cc */,
|
||||
A25D2CBA0CF4C7190096A262 /* stats.h */,
|
||||
C11DEA141FCD31C0009E22B9 /* subprocess-posix.cc */,
|
||||
@@ -2600,7 +2600,7 @@
|
||||
A29DF8BE0DB2545F00D04E5A /* verify.h in Headers */,
|
||||
C1FEE57B1C3223CC00D62832 /* watchdir.h in Headers */,
|
||||
A2AAB6650DE0D08B00E04DDA /* blocklist.h in Headers */,
|
||||
ED67FB432B70FCE400D8A037 /* settings.h in Headers */,
|
||||
ED67FB432B70FCE400D8A037 /* serializable.h in Headers */,
|
||||
A2A4E9210DE0F7E9000CE197 /* web.h in Headers */,
|
||||
A25E03E20E4015380086C225 /* tr-getopt.h in Headers */,
|
||||
A21FBBAB0EDA78C300BC3C51 /* bandwidth.h in Headers */,
|
||||
@@ -3478,7 +3478,7 @@
|
||||
C1033E081A3279B800EF44D8 /* crypto-utils-ccrypto.cc in Sources */,
|
||||
A22CFCA80FC24ED80009BD3E /* tr-dht.cc in Sources */,
|
||||
0A6169A70FE5C9A200C66CE6 /* bitfield.cc in Sources */,
|
||||
ED67FB422B70FCE400D8A037 /* settings.cc in Sources */,
|
||||
ED67FB422B70FCE400D8A037 /* serializable.cc in Sources */,
|
||||
1BB44E07B1B52E28291B4E32 /* file-piece-map.cc in Sources */,
|
||||
A25964A6106D73A800453B31 /* announcer.cc in Sources */,
|
||||
66F977825E65AD498C028BB0 /* announce-list.cc in Sources */,
|
||||
|
||||
@@ -110,6 +110,8 @@ target_sources(${TR_NAME}
|
||||
rpc-server.h
|
||||
rpcimpl.cc
|
||||
rpcimpl.h
|
||||
serializable.cc
|
||||
serializable.h
|
||||
session-alt-speeds.cc
|
||||
session-alt-speeds.h
|
||||
session-id.cc
|
||||
@@ -118,8 +120,6 @@ target_sources(${TR_NAME}
|
||||
session-thread.h
|
||||
session.cc
|
||||
session.h
|
||||
settings.cc
|
||||
settings.h
|
||||
stats.cc
|
||||
stats.h
|
||||
subprocess-posix.cc
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#error only libtransmission should #include this header.
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <cstddef> // size_t
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -19,7 +20,7 @@
|
||||
|
||||
#include "libtransmission/net.h"
|
||||
#include "libtransmission/quark.h"
|
||||
#include "libtransmission/settings.h"
|
||||
#include "libtransmission/serializable.h"
|
||||
#include "libtransmission/utils-ev.h"
|
||||
|
||||
class tr_rpc_address;
|
||||
@@ -35,7 +36,7 @@ class Timer;
|
||||
class tr_rpc_server
|
||||
{
|
||||
public:
|
||||
class Settings final : public libtransmission::Settings
|
||||
class Settings final : public libtransmission::Serializable<Settings>
|
||||
{
|
||||
public:
|
||||
Settings() = default;
|
||||
@@ -63,25 +64,24 @@ public:
|
||||
tr_port port = tr_port::from_host(TrDefaultRpcPort);
|
||||
|
||||
private:
|
||||
[[nodiscard]] Fields fields() override
|
||||
{
|
||||
return {
|
||||
{ TR_KEY_anti_brute_force_enabled, &is_anti_brute_force_enabled },
|
||||
{ TR_KEY_anti_brute_force_threshold, &anti_brute_force_limit },
|
||||
{ TR_KEY_rpc_authentication_required, &authentication_required },
|
||||
{ TR_KEY_rpc_bind_address, &bind_address_str },
|
||||
{ TR_KEY_rpc_enabled, &is_enabled },
|
||||
{ TR_KEY_rpc_host_whitelist, &host_whitelist_str },
|
||||
{ TR_KEY_rpc_host_whitelist_enabled, &is_host_whitelist_enabled },
|
||||
{ TR_KEY_rpc_port, &port },
|
||||
{ TR_KEY_rpc_password, &salted_password },
|
||||
{ TR_KEY_rpc_socket_mode, &socket_mode },
|
||||
{ TR_KEY_rpc_url, &url },
|
||||
{ TR_KEY_rpc_username, &username },
|
||||
{ TR_KEY_rpc_whitelist, &whitelist_str },
|
||||
{ TR_KEY_rpc_whitelist_enabled, &is_whitelist_enabled },
|
||||
};
|
||||
}
|
||||
friend libtransmission::Serializable<Settings>;
|
||||
|
||||
static inline auto const fields = std::array<Field, 14U>{ {
|
||||
{ TR_KEY_anti_brute_force_enabled, &Settings::is_anti_brute_force_enabled },
|
||||
{ TR_KEY_anti_brute_force_threshold, &Settings::anti_brute_force_limit },
|
||||
{ TR_KEY_rpc_authentication_required, &Settings::authentication_required },
|
||||
{ TR_KEY_rpc_bind_address, &Settings::bind_address_str },
|
||||
{ TR_KEY_rpc_enabled, &Settings::is_enabled },
|
||||
{ TR_KEY_rpc_host_whitelist, &Settings::host_whitelist_str },
|
||||
{ TR_KEY_rpc_host_whitelist_enabled, &Settings::is_host_whitelist_enabled },
|
||||
{ TR_KEY_rpc_port, &Settings::port },
|
||||
{ TR_KEY_rpc_password, &Settings::salted_password },
|
||||
{ TR_KEY_rpc_socket_mode, &Settings::socket_mode },
|
||||
{ TR_KEY_rpc_url, &Settings::url },
|
||||
{ TR_KEY_rpc_username, &Settings::username },
|
||||
{ TR_KEY_rpc_whitelist, &Settings::whitelist_str },
|
||||
{ TR_KEY_rpc_whitelist_enabled, &Settings::is_whitelist_enabled },
|
||||
} };
|
||||
};
|
||||
|
||||
tr_rpc_server(tr_session* session, Settings&& settings);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "libtransmission/net.h" // for tr_port
|
||||
#include "libtransmission/open-files.h" // for tr_open_files::Preallocation
|
||||
#include "libtransmission/peer-io.h" // tr_preferred_transport
|
||||
#include "libtransmission/settings.h"
|
||||
#include "libtransmission/serializable.h"
|
||||
#include "libtransmission/utils.h" // for tr_strv_strip(), tr_strlower()
|
||||
#include "libtransmission/variant.h"
|
||||
#include "libtransmission/tr-assert.h"
|
||||
@@ -40,7 +40,7 @@ using Lookup = std::array<std::pair<std::string_view, T>, N>;
|
||||
|
||||
// ---
|
||||
|
||||
bool load_bool(tr_variant const& src, bool* tgt)
|
||||
bool to_bool(tr_variant const& src, bool* tgt)
|
||||
{
|
||||
if (auto val = src.value_if<bool>())
|
||||
{
|
||||
@@ -51,14 +51,14 @@ bool load_bool(tr_variant const& src, bool* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_bool(bool const& val)
|
||||
tr_variant from_bool(bool const& val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
bool load_double(tr_variant const& src, double* tgt)
|
||||
bool to_double(tr_variant const& src, double* tgt)
|
||||
{
|
||||
if (auto val = src.value_if<double>())
|
||||
{
|
||||
@@ -69,7 +69,7 @@ bool load_double(tr_variant const& src, double* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_double(double const& val)
|
||||
tr_variant from_double(double const& val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
@@ -82,7 +82,7 @@ auto constexpr EncryptionKeys = Lookup<tr_encryption_mode, 3U>{ {
|
||||
{ "allowed", TR_CLEAR_PREFERRED },
|
||||
} };
|
||||
|
||||
bool load_encryption_mode(tr_variant const& src, tr_encryption_mode* tgt)
|
||||
bool to_encryption_mode(tr_variant const& src, tr_encryption_mode* tgt)
|
||||
{
|
||||
static constexpr auto& Keys = EncryptionKeys;
|
||||
|
||||
@@ -115,7 +115,7 @@ bool load_encryption_mode(tr_variant const& src, tr_encryption_mode* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_encryption_mode(tr_encryption_mode const& val)
|
||||
tr_variant from_encryption_mode(tr_encryption_mode const& val)
|
||||
{
|
||||
return static_cast<int64_t>(val);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ auto constexpr LogKeys = Lookup<tr_log_level, 7U>{ {
|
||||
{ "warn", TR_LOG_WARN },
|
||||
} };
|
||||
|
||||
bool load_log_level(tr_variant const& src, tr_log_level* tgt)
|
||||
bool to_log_level(tr_variant const& src, tr_log_level* tgt)
|
||||
{
|
||||
static constexpr auto& Keys = LogKeys;
|
||||
|
||||
@@ -165,14 +165,14 @@ bool load_log_level(tr_variant const& src, tr_log_level* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_log_level(tr_log_level const& val)
|
||||
tr_variant from_log_level(tr_log_level const& val)
|
||||
{
|
||||
return static_cast<int64_t>(val);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
bool load_mode_t(tr_variant const& src, tr_mode_t* tgt)
|
||||
bool to_mode_t(tr_variant const& src, tr_mode_t* tgt)
|
||||
{
|
||||
if (auto const val = src.value_if<std::string_view>())
|
||||
{
|
||||
@@ -192,14 +192,14 @@ bool load_mode_t(tr_variant const& src, tr_mode_t* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_mode_t(tr_mode_t const& val)
|
||||
tr_variant from_mode_t(tr_mode_t const& val)
|
||||
{
|
||||
return fmt::format("{:#03o}", val);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
bool load_msec(tr_variant const& src, std::chrono::milliseconds* tgt)
|
||||
bool to_msec(tr_variant const& src, std::chrono::milliseconds* tgt)
|
||||
{
|
||||
if (auto val = src.value_if<int64_t>())
|
||||
{
|
||||
@@ -210,14 +210,14 @@ bool load_msec(tr_variant const& src, std::chrono::milliseconds* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_msec(std::chrono::milliseconds const& src)
|
||||
tr_variant from_msec(std::chrono::milliseconds const& src)
|
||||
{
|
||||
return src.count();
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
bool load_port(tr_variant const& src, tr_port* tgt)
|
||||
bool to_port(tr_variant const& src, tr_port* tgt)
|
||||
{
|
||||
if (auto const val = src.value_if<int64_t>())
|
||||
{
|
||||
@@ -228,7 +228,7 @@ bool load_port(tr_variant const& src, tr_port* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_port(tr_port const& val)
|
||||
tr_variant from_port(tr_port const& val)
|
||||
{
|
||||
return int64_t{ val.host() };
|
||||
}
|
||||
@@ -243,7 +243,7 @@ auto constexpr PreallocationKeys = Lookup<tr_open_files::Preallocation, 5U>{ {
|
||||
{ "full", tr_open_files::Preallocation::Full },
|
||||
} };
|
||||
|
||||
bool load_preallocation_mode(tr_variant const& src, tr_open_files::Preallocation* tgt)
|
||||
bool to_preallocation_mode(tr_variant const& src, tr_open_files::Preallocation* tgt)
|
||||
{
|
||||
static constexpr auto& Keys = PreallocationKeys;
|
||||
|
||||
@@ -276,7 +276,7 @@ bool load_preallocation_mode(tr_variant const& src, tr_open_files::Preallocation
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_preallocation_mode(tr_open_files::Preallocation const& val)
|
||||
tr_variant from_preallocation_mode(tr_open_files::Preallocation const& val)
|
||||
{
|
||||
return static_cast<int64_t>(val);
|
||||
}
|
||||
@@ -288,7 +288,7 @@ auto constexpr PreferredTransportKeys = Lookup<tr_preferred_transport, TR_NUM_PR
|
||||
{ "tcp", TR_PREFER_TCP },
|
||||
} };
|
||||
|
||||
bool load_preferred_transport(
|
||||
bool to_preferred_transport(
|
||||
tr_variant const& src,
|
||||
small::max_size_vector<tr_preferred_transport, TR_NUM_PREFERRED_TRANSPORT>* tgt)
|
||||
{
|
||||
@@ -350,7 +350,7 @@ bool load_preferred_transport(
|
||||
return true;
|
||||
}
|
||||
|
||||
tr_variant save_preferred_transport(small::max_size_vector<tr_preferred_transport, TR_NUM_PREFERRED_TRANSPORT> const& val)
|
||||
tr_variant from_preferred_transport(small::max_size_vector<tr_preferred_transport, TR_NUM_PREFERRED_TRANSPORT> const& val)
|
||||
{
|
||||
static auto constexpr SaveSingle = [](tr_preferred_transport const ele) -> tr_variant
|
||||
{
|
||||
@@ -377,7 +377,7 @@ tr_variant save_preferred_transport(small::max_size_vector<tr_preferred_transpor
|
||||
|
||||
// ---
|
||||
|
||||
bool load_size_t(tr_variant const& src, size_t* tgt)
|
||||
bool to_size_t(tr_variant const& src, size_t* tgt)
|
||||
{
|
||||
if (auto const val = src.value_if<int64_t>())
|
||||
{
|
||||
@@ -388,14 +388,14 @@ bool load_size_t(tr_variant const& src, size_t* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_size_t(size_t const& val)
|
||||
tr_variant from_size_t(size_t const& val)
|
||||
{
|
||||
return uint64_t{ val };
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
bool load_string(tr_variant const& src, std::string* tgt)
|
||||
bool to_string(tr_variant const& src, std::string* tgt)
|
||||
{
|
||||
if (auto const val = src.value_if<std::string_view>())
|
||||
{
|
||||
@@ -406,14 +406,14 @@ bool load_string(tr_variant const& src, std::string* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_string(std::string const& val)
|
||||
tr_variant from_string(std::string const& val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
bool load_nullable_string(tr_variant const& src, std::optional<std::string>* tgt)
|
||||
bool to_optional_string(tr_variant const& src, std::optional<std::string>* tgt)
|
||||
{
|
||||
if (src.holds_alternative<std::nullptr_t>())
|
||||
{
|
||||
@@ -430,14 +430,14 @@ bool load_nullable_string(tr_variant const& src, std::optional<std::string>* tgt
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_nullable_string(std::optional<std::string> const& val)
|
||||
tr_variant from_optional_string(std::optional<std::string> const& val)
|
||||
{
|
||||
return val ? tr_variant{ *val } : nullptr;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
bool load_tos_t(tr_variant const& src, tr_tos_t* tgt)
|
||||
bool to_tos_t(tr_variant const& src, tr_tos_t* tgt)
|
||||
{
|
||||
if (auto const val = src.value_if<std::string_view>())
|
||||
{
|
||||
@@ -459,7 +459,7 @@ bool load_tos_t(tr_variant const& src, tr_tos_t* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_tos_t(tr_tos_t const& val)
|
||||
tr_variant from_tos_t(tr_tos_t const& val)
|
||||
{
|
||||
return val.toString();
|
||||
}
|
||||
@@ -471,7 +471,7 @@ auto constexpr VerifyModeKeys = Lookup<tr_verify_added_mode, 2U>{ {
|
||||
{ "full", TR_VERIFY_ADDED_FULL },
|
||||
} };
|
||||
|
||||
bool load_verify_added_mode(tr_variant const& src, tr_verify_added_mode* tgt)
|
||||
bool to_verify_added_mode(tr_variant const& src, tr_verify_added_mode* tgt)
|
||||
{
|
||||
static constexpr auto& Keys = VerifyModeKeys;
|
||||
|
||||
@@ -504,7 +504,7 @@ bool load_verify_added_mode(tr_variant const& src, tr_verify_added_mode* tgt)
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_verify_added_mode(tr_verify_added_mode const& val)
|
||||
tr_variant from_verify_added_mode(tr_verify_added_mode const& val)
|
||||
{
|
||||
for (auto const& [key, value] : VerifyModeKeys)
|
||||
{
|
||||
@@ -518,111 +518,21 @@ tr_variant save_verify_added_mode(tr_verify_added_mode const& val)
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
||||
Settings::Settings()
|
||||
{
|
||||
add_type_handler(load_bool, save_bool);
|
||||
add_type_handler(load_double, save_double);
|
||||
add_type_handler(load_encryption_mode, save_encryption_mode);
|
||||
add_type_handler(load_log_level, save_log_level);
|
||||
add_type_handler(load_mode_t, save_mode_t);
|
||||
add_type_handler(load_msec, save_msec);
|
||||
add_type_handler(load_port, save_port);
|
||||
add_type_handler(load_preallocation_mode, save_preallocation_mode);
|
||||
add_type_handler(load_preferred_transport, save_preferred_transport);
|
||||
add_type_handler(load_size_t, save_size_t);
|
||||
add_type_handler(load_string, save_string);
|
||||
add_type_handler(load_nullable_string, save_nullable_string);
|
||||
add_type_handler(load_tos_t, save_tos_t);
|
||||
add_type_handler(load_verify_added_mode, save_verify_added_mode);
|
||||
}
|
||||
Serializers::ConvertersMap Serializers::converters = { {
|
||||
Serializers::build_converter_entry(to_bool, from_bool),
|
||||
Serializers::build_converter_entry(to_double, from_double),
|
||||
Serializers::build_converter_entry(to_encryption_mode, from_encryption_mode),
|
||||
Serializers::build_converter_entry(to_log_level, from_log_level),
|
||||
Serializers::build_converter_entry(to_mode_t, from_mode_t),
|
||||
Serializers::build_converter_entry(to_msec, from_msec),
|
||||
Serializers::build_converter_entry(to_optional_string, from_optional_string),
|
||||
Serializers::build_converter_entry(to_port, from_port),
|
||||
Serializers::build_converter_entry(to_preallocation_mode, from_preallocation_mode),
|
||||
Serializers::build_converter_entry(to_preferred_transport, from_preferred_transport),
|
||||
Serializers::build_converter_entry(to_size_t, from_size_t),
|
||||
Serializers::build_converter_entry(to_string, from_string),
|
||||
Serializers::build_converter_entry(to_tos_t, from_tos_t),
|
||||
Serializers::build_converter_entry(to_verify_added_mode, from_verify_added_mode),
|
||||
} };
|
||||
|
||||
void Settings::load(tr_variant const& src)
|
||||
{
|
||||
auto const* map = src.get_if<tr_variant::Map>();
|
||||
if (map == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& field : fields())
|
||||
{
|
||||
if (auto const iter = map->find(field.key); iter != std::end(*map))
|
||||
{
|
||||
auto const type_index = std::type_index{ field.type };
|
||||
TR_ASSERT(load_.count(type_index) == 1U);
|
||||
load_.at(type_index)(iter->second, field.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::load_single(tr_quark const key, tr_variant const& src)
|
||||
{
|
||||
auto const fields = this->fields();
|
||||
auto const field_it = std::lower_bound(
|
||||
std::begin(fields),
|
||||
std::end(fields),
|
||||
key,
|
||||
[](Field const& f, tr_quark k) { return f.key < k; });
|
||||
if (field_it == std::end(fields) || field_it->key != key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const type_index = std::type_index{ field_it->type };
|
||||
TR_ASSERT(load_.count(type_index) == 1U);
|
||||
return load_.at(type_index)(src, field_it->ptr);
|
||||
}
|
||||
|
||||
tr_variant::Map Settings::save_partial(std::vector<tr_quark> quarks) const
|
||||
{
|
||||
static constexpr struct
|
||||
{
|
||||
constexpr bool operator()(Field const& lhs, tr_quark const rhs) const noexcept
|
||||
{
|
||||
return lhs.key < rhs;
|
||||
}
|
||||
|
||||
constexpr bool operator()(tr_quark const lhs, Field const& rhs) const noexcept
|
||||
{
|
||||
return lhs < rhs.key;
|
||||
}
|
||||
} Compare;
|
||||
|
||||
auto const fields = const_cast<Settings*>(this)->fields();
|
||||
auto to_save = Fields{};
|
||||
to_save.reserve(std::min(std::size(quarks), std::size(fields)));
|
||||
|
||||
// N.B. `fields` is supposed to be unique and sorted, so we don't need to sort it,
|
||||
// and we don't need to worry about duplicates in `to_save`
|
||||
std::sort(std::begin(quarks), std::end(quarks));
|
||||
std::set_intersection(
|
||||
std::begin(fields),
|
||||
std::end(fields),
|
||||
std::begin(quarks),
|
||||
std::end(quarks),
|
||||
std::back_inserter(to_save),
|
||||
Compare);
|
||||
|
||||
return save_impl(to_save);
|
||||
}
|
||||
|
||||
tr_variant Settings::save_single(tr_quark quark) const
|
||||
{
|
||||
auto map = save_partial({ quark });
|
||||
return std::empty(map) ? tr_variant{} : std::move(std::begin(map)->second);
|
||||
}
|
||||
|
||||
tr_variant::Map Settings::save_impl(libtransmission::Settings::Fields const& fields) const
|
||||
{
|
||||
auto map = tr_variant::Map{ std::size(fields) };
|
||||
|
||||
for (auto const& field : fields)
|
||||
{
|
||||
auto const type_index = std::type_index{ field.type };
|
||||
TR_ASSERT(save_.count(type_index) == 1U);
|
||||
map.try_emplace(field.key, save_.at(type_index)(field.ptr));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
} // namespace libtransmission
|
||||
265
libtransmission/serializable.h
Normal file
265
libtransmission/serializable.h
Normal file
@@ -0,0 +1,265 @@
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <new>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include <small/map.hpp>
|
||||
|
||||
#include "libtransmission/quark.h"
|
||||
#include "libtransmission/variant.h"
|
||||
|
||||
namespace libtransmission
|
||||
{
|
||||
|
||||
/**
|
||||
* Registry for `tr_variant` <-> `T` converters.
|
||||
* Used by `Serializable` to serialize/deserialize fields in a class.
|
||||
*/
|
||||
class Serializers
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
using Deserialize = bool (*)(tr_variant const& src, T* ptgt);
|
||||
|
||||
template<typename T>
|
||||
using Serialize = tr_variant (*)(T const& src);
|
||||
|
||||
template<typename T>
|
||||
static tr_variant serialize(T const& src)
|
||||
{
|
||||
return converter_storage<T>.serialize(src);
|
||||
}
|
||||
static tr_variant serialize(void const* const psrc, std::type_index const idx)
|
||||
{
|
||||
return converters.at(idx).second(psrc);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool deserialize(tr_variant const& src, T* const ptgt)
|
||||
{
|
||||
return converter_storage<T>.deserialize(src, ptgt);
|
||||
}
|
||||
static bool deserialize(tr_variant const& src, void* const vptgt, std::type_index const idx)
|
||||
{
|
||||
return converters.at(idx).first(src, vptgt);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void add_converter(Deserialize<T> deserialize, Serialize<T> serialize)
|
||||
{
|
||||
auto [key, val] = build_converter_entry<T>(deserialize, serialize);
|
||||
converters.try_emplace(std::move(key), std::move(val));
|
||||
}
|
||||
|
||||
private:
|
||||
using DeserializeFunc = bool (*)(tr_variant const& src, void* tgt);
|
||||
using SerializeFunc = tr_variant (*)(void const* src);
|
||||
using Converters = std::pair<DeserializeFunc, SerializeFunc>;
|
||||
|
||||
template<typename T>
|
||||
struct ConverterStorage
|
||||
{
|
||||
Deserialize<T> deserialize = nullptr;
|
||||
Serialize<T> serialize = nullptr;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static inline ConverterStorage<T> converter_storage;
|
||||
|
||||
template<typename T>
|
||||
static std::pair<std::type_index, Converters> build_converter_entry(Deserialize<T> deserialize, Serialize<T> serialize)
|
||||
{
|
||||
converter_storage<T> = ConverterStorage<T>{ deserialize, serialize };
|
||||
return { std::type_index{ typeid(T*) }, Converters{ &deserialize_impl<T>, &serialize_impl<T> } };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool deserialize_impl(tr_variant const& src, void* const tgt)
|
||||
{
|
||||
return converter_storage<T>.deserialize(src, static_cast<T*>(tgt));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static tr_variant serialize_impl(void const* const src)
|
||||
{
|
||||
return converter_storage<T>.serialize(*static_cast<T const*>(src));
|
||||
}
|
||||
|
||||
using ConvertersMap = small::unordered_map<std::type_index, Converters>;
|
||||
static ConvertersMap converters;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for classes that are convertble to a `tr_variant`.
|
||||
* Settings classes use this to load and save state from `settings.json`.
|
||||
*
|
||||
* Subclasses must define a field named `fields` which is an iterable
|
||||
* collection of `Serializable::Field`. This is typically declared as a
|
||||
* `static const std::array<Field, N>`.
|
||||
*
|
||||
* If your subclass has a field with a bespoke type, it must use
|
||||
* `Serializers::add_converter()` to register how to serialize that type.
|
||||
*/
|
||||
template<typename Derived, typename Key = tr_quark>
|
||||
class Serializable
|
||||
{
|
||||
public:
|
||||
/** Update this object's state from a tr_variant. */
|
||||
void load(tr_variant const& src)
|
||||
{
|
||||
auto const* map = src.get_if<tr_variant::Map>();
|
||||
if (map == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto* const derived = static_cast<Derived*>(this);
|
||||
for (auto const& field : derived->fields)
|
||||
{
|
||||
if (auto const iter = map->find(field.key); iter != std::end(*map))
|
||||
{
|
||||
Serializers::deserialize(iter->second, field.get(derived), field.idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Alias for load() */
|
||||
void deserialize(tr_variant const& src)
|
||||
{
|
||||
load(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save this object's fields to a tr_variant.
|
||||
* @return a tr_variant::Map that holds the serialized form of this object.
|
||||
*/
|
||||
[[nodiscard]] auto save() const
|
||||
{
|
||||
auto const* const derived = static_cast<Derived const*>(this);
|
||||
auto map = tr_variant::Map{ std::size(derived->fields) };
|
||||
for (auto const& field : derived->fields)
|
||||
{
|
||||
map.try_emplace(field.key, Serializers::serialize(field.get(derived), field.idx));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/** Alias for save() */
|
||||
[[nodiscard]] tr_variant::Map serialize() const
|
||||
{
|
||||
return save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single property by key.
|
||||
* Example: `settings_.set(TR_KEY_filename, "foo.txt");`
|
||||
* @return true if the property was changed.
|
||||
*/
|
||||
template<typename T>
|
||||
bool set(Key const& key_in, T val_in)
|
||||
{
|
||||
auto const idx_in = std::type_index{ typeid(T*) };
|
||||
auto* const derived = static_cast<Derived*>(this);
|
||||
for (auto const& field : derived->fields)
|
||||
{
|
||||
if (key_in == field.key && idx_in == field.idx)
|
||||
{
|
||||
if (T& val = *static_cast<T*>(field.get(derived)); val != val_in)
|
||||
{
|
||||
val = val_in;
|
||||
return true; // changed
|
||||
}
|
||||
|
||||
return false; // found but unchanged
|
||||
}
|
||||
}
|
||||
return false; // not found
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single property by key.
|
||||
* Example: `bool enabled = settings_.get<bool>(TR_KEY_incomplete_dir_enabled);`
|
||||
* @return a std::optional<> which has the value if the key was found.
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] std::optional<T> get(Key const& key_in) const
|
||||
{
|
||||
auto const idx_in = std::type_index{ typeid(T*) };
|
||||
auto const* const derived = static_cast<Derived const*>(this);
|
||||
for (auto const& field : derived->fields)
|
||||
{
|
||||
if (key_in == field.key && idx_in == field.idx)
|
||||
{
|
||||
return *static_cast<T const*>(field.get(derived));
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
protected:
|
||||
struct Field
|
||||
{
|
||||
template<typename T>
|
||||
Field(Key key_in, T Derived::* ptr)
|
||||
: key{ std::move(key_in) }
|
||||
, idx{ typeid(T*) }
|
||||
, getter_{ &Field::template get_impl<T> }
|
||||
, const_getter_{ &Field::template get_const_impl<T> }
|
||||
{
|
||||
static_assert(sizeof(MemberStorage) >= sizeof(T Derived::*));
|
||||
static_assert(alignof(MemberStorage) >= alignof(T Derived::*));
|
||||
new (&storage_) T Derived::*(ptr);
|
||||
}
|
||||
|
||||
void* get(Derived* self) const noexcept
|
||||
{
|
||||
return getter_(self, &storage_);
|
||||
}
|
||||
|
||||
void const* get(Derived const* self) const noexcept
|
||||
{
|
||||
return const_getter_(self, &storage_);
|
||||
}
|
||||
|
||||
Key key;
|
||||
std::type_index idx;
|
||||
|
||||
private:
|
||||
using Getter = void* (*)(Derived*, void const*);
|
||||
using ConstGetter = void const* (*)(Derived const*, void const*);
|
||||
using MemberStorage = std::aligned_storage_t<sizeof(char Derived::*), alignof(char Derived::*)>;
|
||||
|
||||
template<typename T>
|
||||
static void* get_impl(Derived* self, void const* opaque) noexcept
|
||||
{
|
||||
auto const member = *static_cast<T Derived::* const*>(opaque);
|
||||
return &(self->*member);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void const* get_const_impl(Derived const* self, void const* opaque) noexcept
|
||||
{
|
||||
auto const member = *static_cast<T Derived::* const*>(opaque);
|
||||
return &(self->*member);
|
||||
}
|
||||
|
||||
Getter getter_;
|
||||
ConstGetter const_getter_;
|
||||
MemberStorage storage_;
|
||||
};
|
||||
|
||||
private:
|
||||
friend Derived;
|
||||
|
||||
Serializable() = default;
|
||||
};
|
||||
} // namespace libtransmission
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cstddef> // size_t
|
||||
#include <ctime> // for time_t
|
||||
@@ -17,7 +18,7 @@
|
||||
#include "libtransmission/transmission.h" // for TR_SCHED_ALL
|
||||
|
||||
#include "libtransmission/quark.h"
|
||||
#include "libtransmission/settings.h"
|
||||
#include "libtransmission/serializable.h"
|
||||
#include "libtransmission/values.h"
|
||||
|
||||
struct tr_variant;
|
||||
@@ -28,7 +29,7 @@ class tr_session_alt_speeds
|
||||
using Speed = libtransmission::Values::Speed;
|
||||
|
||||
public:
|
||||
class Settings final : public libtransmission::Settings
|
||||
class Settings final : public libtransmission::Serializable<Settings>
|
||||
{
|
||||
public:
|
||||
Settings() = default;
|
||||
@@ -49,18 +50,17 @@ public:
|
||||
size_t use_on_these_weekdays = TR_SCHED_ALL;
|
||||
|
||||
private:
|
||||
[[nodiscard]] Fields fields() override
|
||||
{
|
||||
return {
|
||||
{ TR_KEY_alt_speed_enabled, &is_active },
|
||||
{ TR_KEY_alt_speed_up, &speed_up_kbyps },
|
||||
{ TR_KEY_alt_speed_down, &speed_down_kbyps },
|
||||
{ TR_KEY_alt_speed_time_enabled, &scheduler_enabled },
|
||||
{ TR_KEY_alt_speed_time_day, &use_on_these_weekdays },
|
||||
{ TR_KEY_alt_speed_time_begin, &minute_begin },
|
||||
{ TR_KEY_alt_speed_time_end, &minute_end },
|
||||
};
|
||||
}
|
||||
friend libtransmission::Serializable<Settings>;
|
||||
|
||||
static inline auto const fields = std::array<Field, 7U>{ {
|
||||
{ TR_KEY_alt_speed_enabled, &Settings::is_active },
|
||||
{ TR_KEY_alt_speed_up, &Settings::speed_up_kbyps },
|
||||
{ TR_KEY_alt_speed_down, &Settings::speed_down_kbyps },
|
||||
{ TR_KEY_alt_speed_time_enabled, &Settings::scheduler_enabled },
|
||||
{ TR_KEY_alt_speed_time_day, &Settings::use_on_these_weekdays },
|
||||
{ TR_KEY_alt_speed_time_begin, &Settings::minute_begin },
|
||||
{ TR_KEY_alt_speed_time_end, &Settings::minute_end },
|
||||
} };
|
||||
};
|
||||
|
||||
enum class ChangeReason : uint8_t
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
#include "libtransmission/session-alt-speeds.h"
|
||||
#include "libtransmission/session-id.h"
|
||||
#include "libtransmission/session-thread.h"
|
||||
#include "libtransmission/settings.h"
|
||||
#include "libtransmission/serializable.h"
|
||||
#include "libtransmission/stats.h"
|
||||
#include "libtransmission/timer.h"
|
||||
#include "libtransmission/torrent-queue.h"
|
||||
@@ -382,7 +382,7 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
struct Settings final : public libtransmission::Settings
|
||||
struct Settings final : public libtransmission::Serializable<Settings>
|
||||
{
|
||||
public:
|
||||
Settings() = default;
|
||||
@@ -460,72 +460,71 @@ public:
|
||||
tr_verify_added_mode torrent_added_verify_mode = TR_VERIFY_ADDED_FAST;
|
||||
|
||||
private:
|
||||
[[nodiscard]] Fields fields() override
|
||||
{
|
||||
return {
|
||||
{ TR_KEY_announce_ip, &announce_ip },
|
||||
{ TR_KEY_announce_ip_enabled, &announce_ip_enabled },
|
||||
{ TR_KEY_bind_address_ipv4, &bind_address_ipv4 },
|
||||
{ TR_KEY_bind_address_ipv6, &bind_address_ipv6 },
|
||||
{ TR_KEY_blocklist_enabled, &blocklist_enabled },
|
||||
{ TR_KEY_blocklist_url, &blocklist_url },
|
||||
{ TR_KEY_cache_size_mb, &cache_size_mbytes },
|
||||
{ TR_KEY_default_trackers, &default_trackers_str },
|
||||
{ TR_KEY_dht_enabled, &dht_enabled },
|
||||
{ TR_KEY_download_dir, &download_dir },
|
||||
{ TR_KEY_download_queue_enabled, &download_queue_enabled },
|
||||
{ TR_KEY_download_queue_size, &download_queue_size },
|
||||
{ TR_KEY_encryption, &encryption_mode },
|
||||
{ TR_KEY_idle_seeding_limit, &idle_seeding_limit_minutes },
|
||||
{ TR_KEY_idle_seeding_limit_enabled, &idle_seeding_limit_enabled },
|
||||
{ TR_KEY_incomplete_dir, &incomplete_dir },
|
||||
{ TR_KEY_incomplete_dir_enabled, &incomplete_dir_enabled },
|
||||
{ TR_KEY_lpd_enabled, &lpd_enabled },
|
||||
{ TR_KEY_message_level, &log_level },
|
||||
{ TR_KEY_peer_congestion_algorithm, &peer_congestion_algorithm },
|
||||
{ TR_KEY_peer_limit_global, &peer_limit_global },
|
||||
{ TR_KEY_peer_limit_per_torrent, &peer_limit_per_torrent },
|
||||
{ TR_KEY_peer_port, &peer_port },
|
||||
{ TR_KEY_peer_port_random_high, &peer_port_random_high },
|
||||
{ TR_KEY_peer_port_random_low, &peer_port_random_low },
|
||||
{ TR_KEY_peer_port_random_on_start, &peer_port_random_on_start },
|
||||
{ TR_KEY_peer_socket_tos, &peer_socket_tos },
|
||||
{ TR_KEY_pex_enabled, &pex_enabled },
|
||||
{ TR_KEY_port_forwarding_enabled, &port_forwarding_enabled },
|
||||
{ TR_KEY_preallocation, &preallocation_mode },
|
||||
{ TR_KEY_preferred_transports, &preferred_transports },
|
||||
{ TR_KEY_proxy_url, &proxy_url },
|
||||
{ TR_KEY_queue_stalled_enabled, &queue_stalled_enabled },
|
||||
{ TR_KEY_queue_stalled_minutes, &queue_stalled_minutes },
|
||||
{ TR_KEY_ratio_limit, &ratio_limit },
|
||||
{ TR_KEY_ratio_limit_enabled, &ratio_limit_enabled },
|
||||
{ TR_KEY_rename_partial_files, &is_incomplete_file_naming_enabled },
|
||||
{ TR_KEY_reqq, &reqq },
|
||||
{ TR_KEY_scrape_paused_torrents_enabled, &should_scrape_paused_torrents },
|
||||
{ TR_KEY_script_torrent_added_enabled, &script_torrent_added_enabled },
|
||||
{ TR_KEY_script_torrent_added_filename, &script_torrent_added_filename },
|
||||
{ TR_KEY_script_torrent_done_enabled, &script_torrent_done_enabled },
|
||||
{ TR_KEY_script_torrent_done_filename, &script_torrent_done_filename },
|
||||
{ TR_KEY_script_torrent_done_seeding_enabled, &script_torrent_done_seeding_enabled },
|
||||
{ TR_KEY_script_torrent_done_seeding_filename, &script_torrent_done_seeding_filename },
|
||||
{ TR_KEY_seed_queue_enabled, &seed_queue_enabled },
|
||||
{ TR_KEY_seed_queue_size, &seed_queue_size },
|
||||
{ TR_KEY_sequential_download, &sequential_download },
|
||||
{ TR_KEY_sleep_per_seconds_during_verify, &sleep_per_seconds_during_verify },
|
||||
{ TR_KEY_speed_limit_down, &speed_limit_down },
|
||||
{ TR_KEY_speed_limit_down_enabled, &speed_limit_down_enabled },
|
||||
{ TR_KEY_speed_limit_up, &speed_limit_up },
|
||||
{ TR_KEY_speed_limit_up_enabled, &speed_limit_up_enabled },
|
||||
{ TR_KEY_start_added_torrents, &should_start_added_torrents },
|
||||
{ TR_KEY_tcp_enabled, &tcp_enabled },
|
||||
{ TR_KEY_torrent_added_verify_mode, &torrent_added_verify_mode },
|
||||
{ TR_KEY_torrent_complete_verify_enabled, &torrent_complete_verify_enabled },
|
||||
{ TR_KEY_trash_original_torrent_files, &should_delete_source_torrents },
|
||||
{ TR_KEY_umask, &umask },
|
||||
{ TR_KEY_upload_slots_per_torrent, &upload_slots_per_torrent },
|
||||
{ TR_KEY_utp_enabled, &utp_enabled },
|
||||
};
|
||||
}
|
||||
friend class libtransmission::Serializable<Settings>;
|
||||
|
||||
static inline auto const fields = std::array<Field, 61U>{ {
|
||||
{ TR_KEY_announce_ip, &Settings::announce_ip },
|
||||
{ TR_KEY_announce_ip_enabled, &Settings::announce_ip_enabled },
|
||||
{ TR_KEY_bind_address_ipv4, &Settings::bind_address_ipv4 },
|
||||
{ TR_KEY_bind_address_ipv6, &Settings::bind_address_ipv6 },
|
||||
{ TR_KEY_blocklist_enabled, &Settings::blocklist_enabled },
|
||||
{ TR_KEY_blocklist_url, &Settings::blocklist_url },
|
||||
{ TR_KEY_cache_size_mb, &Settings::cache_size_mbytes },
|
||||
{ TR_KEY_default_trackers, &Settings::default_trackers_str },
|
||||
{ TR_KEY_dht_enabled, &Settings::dht_enabled },
|
||||
{ TR_KEY_download_dir, &Settings::download_dir },
|
||||
{ TR_KEY_download_queue_enabled, &Settings::download_queue_enabled },
|
||||
{ TR_KEY_download_queue_size, &Settings::download_queue_size },
|
||||
{ TR_KEY_encryption, &Settings::encryption_mode },
|
||||
{ TR_KEY_idle_seeding_limit, &Settings::idle_seeding_limit_minutes },
|
||||
{ TR_KEY_idle_seeding_limit_enabled, &Settings::idle_seeding_limit_enabled },
|
||||
{ TR_KEY_incomplete_dir, &Settings::incomplete_dir },
|
||||
{ TR_KEY_incomplete_dir_enabled, &Settings::incomplete_dir_enabled },
|
||||
{ TR_KEY_lpd_enabled, &Settings::lpd_enabled },
|
||||
{ TR_KEY_message_level, &Settings::log_level },
|
||||
{ TR_KEY_peer_congestion_algorithm, &Settings::peer_congestion_algorithm },
|
||||
{ TR_KEY_peer_limit_global, &Settings::peer_limit_global },
|
||||
{ TR_KEY_peer_limit_per_torrent, &Settings::peer_limit_per_torrent },
|
||||
{ TR_KEY_peer_port, &Settings::peer_port },
|
||||
{ TR_KEY_peer_port_random_high, &Settings::peer_port_random_high },
|
||||
{ TR_KEY_peer_port_random_low, &Settings::peer_port_random_low },
|
||||
{ TR_KEY_peer_port_random_on_start, &Settings::peer_port_random_on_start },
|
||||
{ TR_KEY_peer_socket_tos, &Settings::peer_socket_tos },
|
||||
{ TR_KEY_pex_enabled, &Settings::pex_enabled },
|
||||
{ TR_KEY_port_forwarding_enabled, &Settings::port_forwarding_enabled },
|
||||
{ TR_KEY_preallocation, &Settings::preallocation_mode },
|
||||
{ TR_KEY_preferred_transports, &Settings::preferred_transports },
|
||||
{ TR_KEY_proxy_url, &Settings::proxy_url },
|
||||
{ TR_KEY_queue_stalled_enabled, &Settings::queue_stalled_enabled },
|
||||
{ TR_KEY_queue_stalled_minutes, &Settings::queue_stalled_minutes },
|
||||
{ TR_KEY_ratio_limit, &Settings::ratio_limit },
|
||||
{ TR_KEY_ratio_limit_enabled, &Settings::ratio_limit_enabled },
|
||||
{ TR_KEY_rename_partial_files, &Settings::is_incomplete_file_naming_enabled },
|
||||
{ TR_KEY_reqq, &Settings::reqq },
|
||||
{ TR_KEY_scrape_paused_torrents_enabled, &Settings::should_scrape_paused_torrents },
|
||||
{ TR_KEY_script_torrent_added_enabled, &Settings::script_torrent_added_enabled },
|
||||
{ TR_KEY_script_torrent_added_filename, &Settings::script_torrent_added_filename },
|
||||
{ TR_KEY_script_torrent_done_enabled, &Settings::script_torrent_done_enabled },
|
||||
{ TR_KEY_script_torrent_done_filename, &Settings::script_torrent_done_filename },
|
||||
{ TR_KEY_script_torrent_done_seeding_enabled, &Settings::script_torrent_done_seeding_enabled },
|
||||
{ TR_KEY_script_torrent_done_seeding_filename, &Settings::script_torrent_done_seeding_filename },
|
||||
{ TR_KEY_seed_queue_enabled, &Settings::seed_queue_enabled },
|
||||
{ TR_KEY_seed_queue_size, &Settings::seed_queue_size },
|
||||
{ TR_KEY_sequential_download, &Settings::sequential_download },
|
||||
{ TR_KEY_sleep_per_seconds_during_verify, &Settings::sleep_per_seconds_during_verify },
|
||||
{ TR_KEY_speed_limit_down, &Settings::speed_limit_down },
|
||||
{ TR_KEY_speed_limit_down_enabled, &Settings::speed_limit_down_enabled },
|
||||
{ TR_KEY_speed_limit_up, &Settings::speed_limit_up },
|
||||
{ TR_KEY_speed_limit_up_enabled, &Settings::speed_limit_up_enabled },
|
||||
{ TR_KEY_start_added_torrents, &Settings::should_start_added_torrents },
|
||||
{ TR_KEY_tcp_enabled, &Settings::tcp_enabled },
|
||||
{ TR_KEY_torrent_added_verify_mode, &Settings::torrent_added_verify_mode },
|
||||
{ TR_KEY_torrent_complete_verify_enabled, &Settings::torrent_complete_verify_enabled },
|
||||
{ TR_KEY_trash_original_torrent_files, &Settings::should_delete_source_torrents },
|
||||
{ TR_KEY_umask, &Settings::umask },
|
||||
{ TR_KEY_upload_slots_per_torrent, &Settings::upload_slots_per_torrent },
|
||||
{ TR_KEY_utp_enabled, &Settings::utp_enabled },
|
||||
} };
|
||||
};
|
||||
|
||||
explicit tr_session(std::string_view config_dir, tr_variant const& settings_dict);
|
||||
@@ -1009,14 +1008,14 @@ public:
|
||||
|
||||
[[nodiscard]] auto save_preferred_transports() const
|
||||
{
|
||||
auto var = settings().save_single(TR_KEY_preferred_transports);
|
||||
auto var = libtransmission::Serializers::serialize(settings_.preferred_transports);
|
||||
TR_ASSERT(var.has_value());
|
||||
return var;
|
||||
}
|
||||
|
||||
bool load_preferred_transports(tr_variant const& var) noexcept
|
||||
{
|
||||
return settings_.load_single(TR_KEY_preferred_transports, var);
|
||||
return libtransmission::Serializers::deserialize(var, &settings_.preferred_transports);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto isIdleLimited() const noexcept
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "libtransmission/quark.h"
|
||||
#include "libtransmission/variant.h"
|
||||
|
||||
namespace libtransmission
|
||||
{
|
||||
|
||||
class Settings
|
||||
{
|
||||
public:
|
||||
virtual ~Settings() = default;
|
||||
Settings(Settings const& settings) = default;
|
||||
Settings& operator=(Settings const& other) = default;
|
||||
Settings(Settings&& settings) noexcept = default;
|
||||
Settings& operator=(Settings&& other) noexcept = default;
|
||||
|
||||
void load(tr_variant const& src);
|
||||
bool load_single(tr_quark key, tr_variant const& src);
|
||||
|
||||
[[nodiscard]] tr_variant::Map save() const
|
||||
{
|
||||
return save_impl(const_cast<Settings*>(this)->fields());
|
||||
}
|
||||
[[nodiscard]] tr_variant::Map save_partial(std::vector<tr_quark> quarks) const;
|
||||
[[nodiscard]] tr_variant save_single(tr_quark quark) const;
|
||||
|
||||
protected:
|
||||
Settings();
|
||||
|
||||
// convert from tr_variant to T
|
||||
template<typename T>
|
||||
using Load = bool (*)(tr_variant const& src, T* tgt);
|
||||
|
||||
// convert from T to tr_variant
|
||||
template<typename T>
|
||||
using Save = tr_variant (*)(T const& src);
|
||||
|
||||
template<typename T>
|
||||
void add_type_handler(Load<T> load_handler, Save<T> save_handler)
|
||||
{
|
||||
auto const key = std::type_index(typeid(T*));
|
||||
|
||||
// wrap load_handler + save_handler with void* wrappers so that
|
||||
// they can be stored in the save_ and load_ maps
|
||||
load_.insert_or_assign(
|
||||
key,
|
||||
[load_handler](tr_variant const& src, void* tgt) { return load_handler(src, static_cast<T*>(tgt)); });
|
||||
save_.insert_or_assign(key, [save_handler](void const* src) { return save_handler(*static_cast<T const*>(src)); });
|
||||
}
|
||||
|
||||
struct Field
|
||||
{
|
||||
template<typename T>
|
||||
Field(tr_quark key_in, T* ptr_in)
|
||||
: key{ key_in }
|
||||
, type{ typeid(T*) }
|
||||
, ptr{ ptr_in }
|
||||
{
|
||||
}
|
||||
|
||||
tr_quark key;
|
||||
std::type_info const& type;
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
using Fields = std::vector<Field>;
|
||||
|
||||
[[nodiscard]] virtual Fields fields() = 0;
|
||||
|
||||
private:
|
||||
[[nodiscard]] tr_variant::Map save_impl(Fields const& fields) const;
|
||||
|
||||
std::unordered_map<std::type_index, std::function<tr_variant(void const* src)>> save_;
|
||||
std::unordered_map<std::type_index, std::function<bool(tr_variant const& src, void* tgt)>> load_;
|
||||
};
|
||||
} // namespace libtransmission
|
||||
Reference in New Issue
Block a user