mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 02:18:42 +00:00
feat: add libtransmission::api_compat::convert() (#7917)
Add a module to convert between tr4 and tr5 RPC / settings / config file payloads. This will be used as a compatibility layer between Transmission 5's naming scheme and Transmission <= 4. Co-authored-by: Yat Ho <lagoho7@gmail.com> Co-authored-by: Dzmitry Neviadomski <nevack.d@gmail.com>
This commit is contained in:
@@ -480,6 +480,8 @@
|
||||
EDBAAC8C29E486BC00D9495F /* ip-cache.h in Headers */ = {isa = PBXBuildFile; fileRef = EDBAAC8B29E486BC00D9495F /* ip-cache.h */; };
|
||||
EDBAAC8E29E486C200D9495F /* ip-cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = EDBAAC8D29E486C200D9495F /* ip-cache.cc */; };
|
||||
EDBDFA9E25AFCCA60093D9C1 /* evutil_time.c in Sources */ = {isa = PBXBuildFile; fileRef = EDBDFA9D25AFCCA60093D9C1 /* evutil_time.c */; };
|
||||
EDC37BCD2EE9C2AD001E2612 /* api-compat.cc in Sources */ = {isa = PBXBuildFile; fileRef = EDC37BCC2EE9C2AD001E2612 /* api-compat.cc */; };
|
||||
EDC37BCE2EE9C2AD001E2612 /* api-compat.h in Headers */ = {isa = PBXBuildFile; fileRef = EDC37BCB2EE9C2AD001E2612 /* api-compat.h */; };
|
||||
EDC749F92D98AE3000A12D0F /* PowerManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = EDC749F82D98AE2900A12D0F /* PowerManager.mm */; };
|
||||
F11545ACA7C4D7A464F703AB /* block-info.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A044CBD8C049AFCBD4DB411 /* block-info.h */; settings = {ATTRIBUTES = (Project, ); }; };
|
||||
F63480631E1D7274005B9E09 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F63480621E1D7274005B9E09 /* Images.xcassets */; };
|
||||
@@ -1472,6 +1474,8 @@
|
||||
EDBAAC8B29E486BC00D9495F /* ip-cache.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = "ip-cache.h"; sourceTree = "<group>"; };
|
||||
EDBAAC8D29E486C200D9495F /* ip-cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "ip-cache.cc"; sourceTree = "<group>"; };
|
||||
EDBDFA9D25AFCCA60093D9C1 /* evutil_time.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = evutil_time.c; sourceTree = "<group>"; };
|
||||
EDC37BCB2EE9C2AD001E2612 /* api-compat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "api-compat.h"; sourceTree = "<group>"; };
|
||||
EDC37BCC2EE9C2AD001E2612 /* api-compat.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "api-compat.cc"; sourceTree = "<group>"; };
|
||||
EDC749F72D98ADE200A12D0F /* PowerManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerManager.h; sourceTree = "<group>"; };
|
||||
EDC749F82D98AE2900A12D0F /* PowerManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PowerManager.mm; sourceTree = "<group>"; };
|
||||
F63480621E1D7274005B9E09 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Images/Images.xcassets; sourceTree = "<group>"; };
|
||||
@@ -1919,6 +1923,8 @@
|
||||
4D1838DC09DEC04A0047D688 /* libtransmission */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EDC37BCB2EE9C2AD001E2612 /* api-compat.h */,
|
||||
EDC37BCC2EE9C2AD001E2612 /* api-compat.cc */,
|
||||
66F977825E65AD498C028BB1 /* announce-list.cc */,
|
||||
66F977825E65AD498C028BB3 /* announce-list.h */,
|
||||
A23F299F132A447400E9A83B /* announcer-common.h */,
|
||||
@@ -2561,6 +2567,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C1077A51183EB29600634C22 /* file.h in Headers */,
|
||||
EDC37BCE2EE9C2AD001E2612 /* api-compat.h in Headers */,
|
||||
BEFC1E290C07861A00B0BB3C /* version.h in Headers */,
|
||||
BEFC1E2A0C07861A00B0BB3C /* utils.h in Headers */,
|
||||
BE7AA337F6752914B0C416B0 /* utils-ev.h in Headers */,
|
||||
@@ -3489,6 +3496,7 @@
|
||||
C1FEE57A1C3223CC00D62832 /* watchdir.cc in Sources */,
|
||||
A23547E211CD0B090046EAE6 /* cache.cc in Sources */,
|
||||
C843FC8429C51B9400491854 /* utils.mm in Sources */,
|
||||
EDC37BCD2EE9C2AD001E2612 /* api-compat.cc in Sources */,
|
||||
A284214412DA663E00FBDDBB /* tr-udp.cc in Sources */,
|
||||
C17740D5273A002C00E455D2 /* web-utils.cc in Sources */,
|
||||
A2679294130E00A000CB7464 /* tr-utp.cc in Sources */,
|
||||
|
||||
@@ -6,6 +6,7 @@ Users can set environmental variables to override Transmission's default behavio
|
||||
* If `TR_CURL_SSL_NO_VERIFY` is set, Transmission will not validate SSL certificate for HTTPS connections when talking to trackers. See CURL's documentation ([CURLOPT_SSL_VERIFYHOST](https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html) and [CURLOPT_SSL_VERIFYPEER](https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html)) for more details.
|
||||
* If `TR_CURL_VERBOSE` is set, debugging information for libcurl will be enabled. More information about libcurl's debugging mode [is available here](https://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTVERBOSE).
|
||||
* If `TR_DHT_VERBOSE` is set, Transmission will log all of the DHT's activities in excruciating detail to standard error.
|
||||
* If `TR_SAVE_VERSION_FORMAT` is set to `4` or `5`, it will save settings.json, stats.json, etc. files to either Transmission 4 or Transmission 5 format.
|
||||
|
||||
## Standard Variables Used by Transmission
|
||||
* If `TRANSMISSION_WEB_HOME` is _not_ set, non-Mac platforms will look for the [Web Interface](Web-Interface.md) files in `XDG_DATA_HOME` and in `XDG_DATA_DIRS` as described in [the XDG Base Directory Specification](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables). `XDG_DATA_HOME` has a default value of `$HOME/.local/share/`.
|
||||
|
||||
@@ -28,6 +28,8 @@ target_sources(${TR_NAME}
|
||||
announcer-udp.cc
|
||||
announcer.cc
|
||||
announcer.h
|
||||
api-compat.cc
|
||||
api-compat.h
|
||||
bandwidth.cc
|
||||
bandwidth.h
|
||||
benc.h
|
||||
|
||||
800
libtransmission/api-compat.cc
Normal file
800
libtransmission/api-compat.cc
Normal file
@@ -0,0 +1,800 @@
|
||||
// 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.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "libtransmission/api-compat.h"
|
||||
#include "libtransmission/quark.h"
|
||||
#include "libtransmission/rpcimpl.h"
|
||||
#include "libtransmission/utils.h"
|
||||
#include "libtransmission/variant.h"
|
||||
|
||||
namespace libtransmission::api_compat
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct ApiKey
|
||||
{
|
||||
// snake-case quark
|
||||
tr_quark current;
|
||||
|
||||
// legacy mixed-case RPC quark (pre-05aef3e7)
|
||||
tr_quark legacy;
|
||||
};
|
||||
|
||||
auto constexpr RpcKeys = std::array<ApiKey, 212U>{ {
|
||||
{ TR_KEY_active_torrent_count, TR_KEY_active_torrent_count_camel },
|
||||
{ TR_KEY_activity_date, TR_KEY_activity_date_camel }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_added_date, TR_KEY_added_date_camel }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_alt_speed_down, TR_KEY_alt_speed_down_kebab },
|
||||
{ TR_KEY_alt_speed_enabled, TR_KEY_alt_speed_enabled_kebab },
|
||||
{ TR_KEY_alt_speed_time_begin, TR_KEY_alt_speed_time_begin_kebab },
|
||||
{ TR_KEY_alt_speed_time_day, TR_KEY_alt_speed_time_day_kebab },
|
||||
{ TR_KEY_alt_speed_time_enabled, TR_KEY_alt_speed_time_enabled_kebab },
|
||||
{ TR_KEY_alt_speed_time_end, TR_KEY_alt_speed_time_end_kebab },
|
||||
{ TR_KEY_alt_speed_up, TR_KEY_alt_speed_up_kebab },
|
||||
{ TR_KEY_announce_state, TR_KEY_announce_state_camel },
|
||||
{ TR_KEY_anti_brute_force_enabled, TR_KEY_anti_brute_force_enabled_kebab },
|
||||
{ TR_KEY_anti_brute_force_threshold, TR_KEY_anti_brute_force_threshold_kebab },
|
||||
{ TR_KEY_bandwidth_priority, TR_KEY_bandwidth_priority_camel }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_blocklist_enabled, TR_KEY_blocklist_enabled_kebab },
|
||||
{ TR_KEY_blocklist_size, TR_KEY_blocklist_size_kebab },
|
||||
{ TR_KEY_blocklist_url, TR_KEY_blocklist_url_kebab },
|
||||
{ TR_KEY_bytes_completed, TR_KEY_bytes_completed_camel },
|
||||
{ TR_KEY_cache_size_mb, TR_KEY_cache_size_mb_kebab },
|
||||
{ TR_KEY_client_is_choked, TR_KEY_client_is_choked_camel },
|
||||
{ TR_KEY_client_is_interested, TR_KEY_client_is_interested_camel },
|
||||
{ TR_KEY_client_name, TR_KEY_client_name_camel },
|
||||
{ TR_KEY_config_dir, TR_KEY_config_dir_kebab },
|
||||
{ TR_KEY_corrupt_ever, TR_KEY_corrupt_ever_camel },
|
||||
{ TR_KEY_cumulative_stats, TR_KEY_cumulative_stats_kebab },
|
||||
{ TR_KEY_current_stats, TR_KEY_current_stats_kebab },
|
||||
{ TR_KEY_date_created, TR_KEY_date_created_camel },
|
||||
{ TR_KEY_default_trackers, TR_KEY_default_trackers_kebab },
|
||||
{ TR_KEY_delete_local_data, TR_KEY_delete_local_data_kebab },
|
||||
{ TR_KEY_desired_available, TR_KEY_desired_available_camel },
|
||||
{ TR_KEY_dht_enabled, TR_KEY_dht_enabled_kebab },
|
||||
{ TR_KEY_done_date, TR_KEY_done_date_camel }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_download_count, TR_KEY_download_count_camel },
|
||||
{ TR_KEY_download_dir, TR_KEY_download_dir_kebab }, // crazy case 1: camel in torrent-get/set, kebab everywhere else
|
||||
{ TR_KEY_download_dir_free_space, TR_KEY_download_dir_free_space_kebab },
|
||||
{ TR_KEY_download_limit, TR_KEY_download_limit_camel },
|
||||
{ TR_KEY_download_limited, TR_KEY_download_limited_camel },
|
||||
{ TR_KEY_download_queue_enabled, TR_KEY_download_queue_enabled_kebab },
|
||||
{ TR_KEY_download_queue_size, TR_KEY_download_queue_size_kebab },
|
||||
{ TR_KEY_download_speed, TR_KEY_download_speed_camel },
|
||||
{ TR_KEY_downloaded_bytes, TR_KEY_downloaded_bytes_camel }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_downloaded_ever, TR_KEY_downloaded_ever_camel },
|
||||
{ TR_KEY_edit_date, TR_KEY_edit_date_camel },
|
||||
{ TR_KEY_error_string, TR_KEY_error_string_camel },
|
||||
{ TR_KEY_eta_idle, TR_KEY_eta_idle_camel },
|
||||
{ TR_KEY_file_count, TR_KEY_file_count_kebab },
|
||||
{ TR_KEY_file_stats, TR_KEY_file_stats_camel },
|
||||
{ TR_KEY_files_added, TR_KEY_files_added_camel }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_files_unwanted, TR_KEY_files_unwanted_kebab },
|
||||
{ TR_KEY_files_wanted, TR_KEY_files_wanted_kebab },
|
||||
{ TR_KEY_flag_str, TR_KEY_flag_str_camel },
|
||||
{ TR_KEY_from_cache, TR_KEY_from_cache_camel },
|
||||
{ TR_KEY_from_dht, TR_KEY_from_dht_camel },
|
||||
{ TR_KEY_from_incoming, TR_KEY_from_incoming_camel },
|
||||
{ TR_KEY_from_lpd, TR_KEY_from_lpd_camel },
|
||||
{ TR_KEY_from_ltep, TR_KEY_from_ltep_camel },
|
||||
{ TR_KEY_from_pex, TR_KEY_from_pex_camel },
|
||||
{ TR_KEY_from_tracker, TR_KEY_from_tracker_camel },
|
||||
{ TR_KEY_has_announced, TR_KEY_has_announced_camel },
|
||||
{ TR_KEY_has_scraped, TR_KEY_has_scraped_camel },
|
||||
{ TR_KEY_hash_string, TR_KEY_hash_string_camel },
|
||||
{ TR_KEY_have_unchecked, TR_KEY_have_unchecked_camel },
|
||||
{ TR_KEY_have_valid, TR_KEY_have_valid_camel },
|
||||
{ TR_KEY_honors_session_limits, TR_KEY_honors_session_limits_camel },
|
||||
{ TR_KEY_idle_seeding_limit, TR_KEY_idle_seeding_limit_kebab },
|
||||
{ TR_KEY_idle_seeding_limit_enabled, TR_KEY_idle_seeding_limit_enabled_kebab },
|
||||
{ TR_KEY_incomplete_dir, TR_KEY_incomplete_dir_kebab },
|
||||
{ TR_KEY_incomplete_dir_enabled, TR_KEY_incomplete_dir_enabled_kebab },
|
||||
{ TR_KEY_is_backup, TR_KEY_is_backup_camel },
|
||||
{ TR_KEY_is_downloading_from, TR_KEY_is_downloading_from_camel },
|
||||
{ TR_KEY_is_encrypted, TR_KEY_is_encrypted_camel },
|
||||
{ TR_KEY_is_finished, TR_KEY_is_finished_camel },
|
||||
{ TR_KEY_is_incoming, TR_KEY_is_incoming_camel },
|
||||
{ TR_KEY_is_private, TR_KEY_is_private_camel },
|
||||
{ TR_KEY_is_stalled, TR_KEY_is_stalled_camel },
|
||||
{ TR_KEY_is_uploading_to, TR_KEY_is_uploading_to_camel },
|
||||
{ TR_KEY_is_utp, TR_KEY_is_utp_camel },
|
||||
{ TR_KEY_last_announce_peer_count, TR_KEY_last_announce_peer_count_camel },
|
||||
{ TR_KEY_last_announce_result, TR_KEY_last_announce_result_camel },
|
||||
{ TR_KEY_last_announce_start_time, TR_KEY_last_announce_start_time_camel },
|
||||
{ TR_KEY_last_announce_succeeded, TR_KEY_last_announce_succeeded_camel },
|
||||
{ TR_KEY_last_announce_time, TR_KEY_last_announce_time_camel },
|
||||
{ TR_KEY_last_announce_timed_out, TR_KEY_last_announce_timed_out_camel },
|
||||
{ TR_KEY_last_scrape_result, TR_KEY_last_scrape_result_camel },
|
||||
{ TR_KEY_last_scrape_start_time, TR_KEY_last_scrape_start_time_camel },
|
||||
{ TR_KEY_last_scrape_succeeded, TR_KEY_last_scrape_succeeded_camel },
|
||||
{ TR_KEY_last_scrape_time, TR_KEY_last_scrape_time_camel },
|
||||
{ TR_KEY_last_scrape_timed_out, TR_KEY_last_scrape_timed_out_camel },
|
||||
{ TR_KEY_leecher_count, TR_KEY_leecher_count_camel },
|
||||
{ TR_KEY_left_until_done, TR_KEY_left_until_done_camel },
|
||||
{ TR_KEY_lpd_enabled, TR_KEY_lpd_enabled_kebab },
|
||||
{ TR_KEY_magnet_link, TR_KEY_magnet_link_camel },
|
||||
{ TR_KEY_manual_announce_time, TR_KEY_manual_announce_time_camel },
|
||||
{ TR_KEY_max_connected_peers, TR_KEY_max_connected_peers_camel },
|
||||
{ TR_KEY_memory_bytes, TR_KEY_memory_bytes_kebab },
|
||||
{ TR_KEY_memory_units, TR_KEY_memory_units_kebab },
|
||||
{ TR_KEY_metadata_percent_complete, TR_KEY_metadata_percent_complete_camel },
|
||||
{ TR_KEY_next_announce_time, TR_KEY_next_announce_time_camel },
|
||||
{ TR_KEY_next_scrape_time, TR_KEY_next_scrape_time_camel },
|
||||
{ TR_KEY_paused_torrent_count, TR_KEY_paused_torrent_count_camel },
|
||||
{ TR_KEY_peer_is_choked, TR_KEY_peer_is_choked_camel },
|
||||
{ TR_KEY_peer_is_interested, TR_KEY_peer_is_interested_camel },
|
||||
{ TR_KEY_peer_limit, TR_KEY_peer_limit_kebab },
|
||||
{ TR_KEY_peer_limit_global, TR_KEY_peer_limit_global_kebab },
|
||||
{ TR_KEY_peer_limit_per_torrent, TR_KEY_peer_limit_per_torrent_kebab },
|
||||
{ TR_KEY_peer_port, TR_KEY_peer_port_kebab },
|
||||
{ TR_KEY_peer_port_random_on_start, TR_KEY_peer_port_random_on_start_kebab },
|
||||
{ TR_KEY_peers_connected, TR_KEY_peers_connected_camel },
|
||||
{ TR_KEY_peers_from, TR_KEY_peers_from_camel },
|
||||
{ TR_KEY_peers_getting_from_us, TR_KEY_peers_getting_from_us_camel },
|
||||
{ TR_KEY_peers_sending_to_us, TR_KEY_peers_sending_to_us_camel },
|
||||
{ TR_KEY_percent_complete, TR_KEY_percent_complete_camel },
|
||||
{ TR_KEY_percent_done, TR_KEY_percent_done_camel },
|
||||
{ TR_KEY_pex_enabled, TR_KEY_pex_enabled_kebab },
|
||||
{ TR_KEY_piece_count, TR_KEY_piece_count_camel },
|
||||
{ TR_KEY_piece_size, TR_KEY_piece_size_camel },
|
||||
{ TR_KEY_port_forwarding_enabled, TR_KEY_port_forwarding_enabled_kebab },
|
||||
{ TR_KEY_port_is_open, TR_KEY_port_is_open_kebab },
|
||||
{ TR_KEY_primary_mime_type, TR_KEY_primary_mime_type_kebab },
|
||||
{ TR_KEY_priority_high, TR_KEY_priority_high_kebab },
|
||||
{ TR_KEY_priority_low, TR_KEY_priority_low_kebab },
|
||||
{ TR_KEY_priority_normal, TR_KEY_priority_normal_kebab },
|
||||
{ TR_KEY_queue_position, TR_KEY_queue_position_camel },
|
||||
{ TR_KEY_queue_stalled_enabled, TR_KEY_queue_stalled_enabled_kebab },
|
||||
{ TR_KEY_queue_stalled_minutes, TR_KEY_queue_stalled_minutes_kebab },
|
||||
{ TR_KEY_rate_download, TR_KEY_rate_download_camel },
|
||||
{ TR_KEY_rate_to_client, TR_KEY_rate_to_client_camel },
|
||||
{ TR_KEY_rate_to_peer, TR_KEY_rate_to_peer_camel },
|
||||
{ TR_KEY_rate_upload, TR_KEY_rate_upload_camel },
|
||||
{ TR_KEY_recently_active, TR_KEY_recently_active_kebab },
|
||||
{ TR_KEY_recheck_progress, TR_KEY_recheck_progress_camel },
|
||||
{ TR_KEY_rename_partial_files, TR_KEY_rename_partial_files_kebab },
|
||||
{ TR_KEY_rpc_host_whitelist, TR_KEY_rpc_host_whitelist_kebab },
|
||||
{ TR_KEY_rpc_host_whitelist_enabled, TR_KEY_rpc_host_whitelist_enabled_kebab },
|
||||
{ TR_KEY_rpc_version, TR_KEY_rpc_version_kebab },
|
||||
{ TR_KEY_rpc_version_minimum, TR_KEY_rpc_version_minimum_kebab },
|
||||
{ TR_KEY_rpc_version_semver, TR_KEY_rpc_version_semver_kebab },
|
||||
{ TR_KEY_scrape_state, TR_KEY_scrape_state_camel },
|
||||
{ TR_KEY_script_torrent_added_enabled, TR_KEY_script_torrent_added_enabled_kebab },
|
||||
{ TR_KEY_script_torrent_added_filename, TR_KEY_script_torrent_added_filename_kebab },
|
||||
{ TR_KEY_script_torrent_done_enabled, TR_KEY_script_torrent_done_enabled_kebab },
|
||||
{ TR_KEY_script_torrent_done_filename, TR_KEY_script_torrent_done_filename_kebab },
|
||||
{ TR_KEY_script_torrent_done_seeding_enabled, TR_KEY_script_torrent_done_seeding_enabled_kebab },
|
||||
{ TR_KEY_script_torrent_done_seeding_filename, TR_KEY_script_torrent_done_seeding_filename_kebab },
|
||||
{ TR_KEY_seconds_active, TR_KEY_seconds_active_camel }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_seconds_downloading, TR_KEY_seconds_downloading_camel },
|
||||
{ TR_KEY_seconds_seeding, TR_KEY_seconds_seeding_camel },
|
||||
{ TR_KEY_seed_idle_limit, TR_KEY_seed_idle_limit_camel },
|
||||
{ TR_KEY_seed_idle_mode, TR_KEY_seed_idle_mode_camel },
|
||||
{ TR_KEY_seed_queue_enabled, TR_KEY_seed_queue_enabled_kebab },
|
||||
{ TR_KEY_seed_queue_size, TR_KEY_seed_queue_size_kebab },
|
||||
{ TR_KEY_seed_ratio_limit, TR_KEY_seed_ratio_limit_camel },
|
||||
{ TR_KEY_seed_ratio_limited, TR_KEY_seed_ratio_limited_camel },
|
||||
{ TR_KEY_seed_ratio_mode, TR_KEY_seed_ratio_mode_camel },
|
||||
{ TR_KEY_seeder_count, TR_KEY_seeder_count_camel },
|
||||
{ TR_KEY_session_count, TR_KEY_session_count_camel }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_session_id, TR_KEY_session_id_kebab },
|
||||
{ TR_KEY_size_bytes, TR_KEY_size_bytes_kebab },
|
||||
{ TR_KEY_size_units, TR_KEY_size_units_kebab },
|
||||
{ TR_KEY_size_when_done, TR_KEY_size_when_done_camel },
|
||||
{ TR_KEY_speed_bytes, TR_KEY_speed_bytes_kebab },
|
||||
{ TR_KEY_speed_limit_down, TR_KEY_speed_limit_down_kebab },
|
||||
{ TR_KEY_speed_limit_down_enabled, TR_KEY_speed_limit_down_enabled_kebab },
|
||||
{ TR_KEY_speed_limit_up, TR_KEY_speed_limit_up_kebab },
|
||||
{ TR_KEY_speed_limit_up_enabled, TR_KEY_speed_limit_up_enabled_kebab },
|
||||
{ TR_KEY_speed_units, TR_KEY_speed_units_kebab },
|
||||
{ TR_KEY_start_added_torrents, TR_KEY_start_added_torrents_kebab },
|
||||
{ TR_KEY_start_date, TR_KEY_start_date_camel },
|
||||
{ TR_KEY_tcp_enabled, TR_KEY_tcp_enabled_kebab },
|
||||
{ TR_KEY_torrent_added, TR_KEY_torrent_added_kebab },
|
||||
{ TR_KEY_torrent_count, TR_KEY_torrent_count_camel },
|
||||
{ TR_KEY_torrent_duplicate, TR_KEY_torrent_duplicate_kebab },
|
||||
{ TR_KEY_torrent_file, TR_KEY_torrent_file_camel },
|
||||
{ TR_KEY_total_size, TR_KEY_total_size_camel },
|
||||
{ TR_KEY_tracker_add, TR_KEY_tracker_add_camel },
|
||||
{ TR_KEY_tracker_list, TR_KEY_tracker_list_camel },
|
||||
{ TR_KEY_tracker_remove, TR_KEY_tracker_remove_camel },
|
||||
{ TR_KEY_tracker_replace, TR_KEY_tracker_replace_camel },
|
||||
{ TR_KEY_tracker_stats, TR_KEY_tracker_stats_camel },
|
||||
{ TR_KEY_trash_original_torrent_files, TR_KEY_trash_original_torrent_files_kebab },
|
||||
{ TR_KEY_upload_limit, TR_KEY_upload_limit_camel },
|
||||
{ TR_KEY_upload_limited, TR_KEY_upload_limited_camel },
|
||||
{ TR_KEY_upload_ratio, TR_KEY_upload_ratio_camel },
|
||||
{ TR_KEY_upload_speed, TR_KEY_upload_speed_camel },
|
||||
{ TR_KEY_uploaded_bytes, TR_KEY_uploaded_bytes_camel }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_uploaded_ever, TR_KEY_uploaded_ever_camel },
|
||||
{ TR_KEY_utp_enabled, TR_KEY_utp_enabled_kebab },
|
||||
{ TR_KEY_webseeds_sending_to_us, TR_KEY_webseeds_sending_to_us_camel },
|
||||
{ TR_KEY_blocklist_update, TR_KEY_blocklist_update_kebab },
|
||||
{ TR_KEY_free_space, TR_KEY_free_space_kebab },
|
||||
{ TR_KEY_group_get, TR_KEY_group_get_kebab },
|
||||
{ TR_KEY_group_set, TR_KEY_group_set_kebab },
|
||||
{ TR_KEY_port_test, TR_KEY_port_test_kebab },
|
||||
{ TR_KEY_queue_move_bottom, TR_KEY_queue_move_bottom_kebab },
|
||||
{ TR_KEY_queue_move_down, TR_KEY_queue_move_down_kebab },
|
||||
{ TR_KEY_queue_move_top, TR_KEY_queue_move_top_kebab },
|
||||
{ TR_KEY_queue_move_up, TR_KEY_queue_move_up_kebab },
|
||||
{ TR_KEY_session_close, TR_KEY_session_close_kebab },
|
||||
{ TR_KEY_session_get, TR_KEY_session_get_kebab },
|
||||
{ TR_KEY_session_set, TR_KEY_session_set_kebab },
|
||||
{ TR_KEY_session_stats, TR_KEY_session_stats_kebab },
|
||||
{ TR_KEY_torrent_add, TR_KEY_torrent_add_kebab },
|
||||
{ TR_KEY_torrent_get, TR_KEY_torrent_get_kebab },
|
||||
{ TR_KEY_torrent_reannounce, TR_KEY_torrent_reannounce_kebab },
|
||||
{ TR_KEY_torrent_remove, TR_KEY_torrent_remove_kebab },
|
||||
{ TR_KEY_torrent_rename_path, TR_KEY_torrent_rename_path_kebab },
|
||||
{ TR_KEY_torrent_set, TR_KEY_torrent_set_kebab },
|
||||
{ TR_KEY_torrent_set_location, TR_KEY_torrent_set_location_kebab },
|
||||
{ TR_KEY_torrent_start, TR_KEY_torrent_start_kebab },
|
||||
{ TR_KEY_torrent_start_now, TR_KEY_torrent_start_now_kebab },
|
||||
{ TR_KEY_torrent_stop, TR_KEY_torrent_stop_kebab },
|
||||
{ TR_KEY_torrent_verify, TR_KEY_torrent_verify_kebab },
|
||||
} };
|
||||
|
||||
auto constexpr SessionKeys = std::array<ApiKey, 139U>{ {
|
||||
{ TR_KEY_activity_date, TR_KEY_activity_date_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_added_date, TR_KEY_added_date_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_alt_speed_down, TR_KEY_alt_speed_down_kebab },
|
||||
{ TR_KEY_alt_speed_enabled, TR_KEY_alt_speed_enabled_kebab },
|
||||
{ TR_KEY_alt_speed_time_begin, TR_KEY_alt_speed_time_begin_kebab },
|
||||
{ TR_KEY_alt_speed_time_day, TR_KEY_alt_speed_time_day_kebab },
|
||||
{ TR_KEY_alt_speed_time_enabled, TR_KEY_alt_speed_time_enabled_kebab },
|
||||
{ TR_KEY_alt_speed_time_end, TR_KEY_alt_speed_time_end_kebab },
|
||||
{ TR_KEY_alt_speed_up, TR_KEY_alt_speed_up_kebab },
|
||||
{ TR_KEY_announce_ip, TR_KEY_announce_ip_kebab },
|
||||
{ TR_KEY_announce_ip_enabled, TR_KEY_announce_ip_enabled_kebab },
|
||||
{ TR_KEY_anti_brute_force_enabled, TR_KEY_anti_brute_force_enabled_kebab },
|
||||
{ TR_KEY_anti_brute_force_threshold, TR_KEY_anti_brute_force_threshold_kebab },
|
||||
{ TR_KEY_bandwidth_priority, TR_KEY_bandwidth_priority_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_bind_address_ipv4, TR_KEY_bind_address_ipv4_kebab },
|
||||
{ TR_KEY_bind_address_ipv6, TR_KEY_bind_address_ipv6_kebab },
|
||||
{ TR_KEY_blocklist_date, TR_KEY_blocklist_date_kebab },
|
||||
{ TR_KEY_blocklist_enabled, TR_KEY_blocklist_enabled_kebab },
|
||||
{ TR_KEY_blocklist_updates_enabled, TR_KEY_blocklist_updates_enabled_kebab },
|
||||
{ TR_KEY_blocklist_url, TR_KEY_blocklist_url_kebab },
|
||||
{ TR_KEY_cache_size_mb, TR_KEY_cache_size_mb_kebab },
|
||||
{ TR_KEY_compact_view, TR_KEY_compact_view_kebab },
|
||||
{ TR_KEY_default_trackers, TR_KEY_default_trackers_kebab },
|
||||
{ TR_KEY_details_window_height, TR_KEY_details_window_height_kebab },
|
||||
{ TR_KEY_details_window_width, TR_KEY_details_window_width_kebab },
|
||||
{ TR_KEY_dht_enabled, TR_KEY_dht_enabled_kebab },
|
||||
{ TR_KEY_done_date, TR_KEY_done_date_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_download_dir, TR_KEY_download_dir_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_download_queue_enabled, TR_KEY_download_queue_enabled_kebab },
|
||||
{ TR_KEY_download_queue_size, TR_KEY_download_queue_size_kebab },
|
||||
{ TR_KEY_downloaded_bytes, TR_KEY_downloaded_bytes_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_downloading_time_seconds, TR_KEY_downloading_time_seconds_kebab },
|
||||
{ TR_KEY_files_added, TR_KEY_files_added_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_filter_mode, TR_KEY_filter_mode_kebab },
|
||||
{ TR_KEY_filter_text, TR_KEY_filter_text_kebab },
|
||||
{ TR_KEY_filter_trackers, TR_KEY_filter_trackers_kebab },
|
||||
{ TR_KEY_idle_limit, TR_KEY_idle_limit_kebab },
|
||||
{ TR_KEY_idle_mode, TR_KEY_idle_mode_kebab },
|
||||
{ TR_KEY_idle_seeding_limit, TR_KEY_idle_seeding_limit_kebab },
|
||||
{ TR_KEY_idle_seeding_limit_enabled, TR_KEY_idle_seeding_limit_enabled_kebab },
|
||||
{ TR_KEY_incomplete_dir, TR_KEY_incomplete_dir_kebab },
|
||||
{ TR_KEY_incomplete_dir_enabled, TR_KEY_incomplete_dir_enabled_kebab },
|
||||
{ TR_KEY_inhibit_desktop_hibernation, TR_KEY_inhibit_desktop_hibernation_kebab },
|
||||
{ TR_KEY_lpd_enabled, TR_KEY_lpd_enabled_kebab },
|
||||
{ TR_KEY_main_window_height, TR_KEY_main_window_height_kebab },
|
||||
{ TR_KEY_main_window_is_maximized, TR_KEY_main_window_is_maximized_kebab },
|
||||
{ TR_KEY_main_window_layout_order, TR_KEY_main_window_layout_order_kebab },
|
||||
{ TR_KEY_main_window_width, TR_KEY_main_window_width_kebab },
|
||||
{ TR_KEY_main_window_x, TR_KEY_main_window_x_kebab },
|
||||
{ TR_KEY_main_window_y, TR_KEY_main_window_y_kebab },
|
||||
{ TR_KEY_max_peers, TR_KEY_max_peers_kebab },
|
||||
{ TR_KEY_message_level, TR_KEY_message_level_kebab },
|
||||
{ TR_KEY_open_dialog_dir, TR_KEY_open_dialog_dir_kebab },
|
||||
{ TR_KEY_peer_congestion_algorithm, TR_KEY_peer_congestion_algorithm_kebab },
|
||||
{ TR_KEY_peer_limit_global, TR_KEY_peer_limit_global_kebab },
|
||||
{ TR_KEY_peer_limit_per_torrent, TR_KEY_peer_limit_per_torrent_kebab },
|
||||
{ TR_KEY_peer_port, TR_KEY_peer_port_kebab },
|
||||
{ TR_KEY_peer_port_random_high, TR_KEY_peer_port_random_high_kebab },
|
||||
{ TR_KEY_peer_port_random_low, TR_KEY_peer_port_random_low_kebab },
|
||||
{ TR_KEY_peer_port_random_on_start, TR_KEY_peer_port_random_on_start_kebab },
|
||||
{ TR_KEY_peer_socket_tos, TR_KEY_peer_socket_tos_kebab },
|
||||
{ TR_KEY_peers2_6, TR_KEY_peers2_6_kebab },
|
||||
{ TR_KEY_pex_enabled, TR_KEY_pex_enabled_kebab },
|
||||
{ TR_KEY_port_forwarding_enabled, TR_KEY_port_forwarding_enabled_kebab },
|
||||
{ TR_KEY_prompt_before_exit, TR_KEY_prompt_before_exit_kebab },
|
||||
{ TR_KEY_queue_stalled_enabled, TR_KEY_queue_stalled_enabled_kebab },
|
||||
{ TR_KEY_queue_stalled_minutes, TR_KEY_queue_stalled_minutes_kebab },
|
||||
{ TR_KEY_ratio_limit, TR_KEY_ratio_limit_kebab },
|
||||
{ TR_KEY_ratio_limit_enabled, TR_KEY_ratio_limit_enabled_kebab },
|
||||
{ TR_KEY_ratio_mode, TR_KEY_ratio_mode_kebab },
|
||||
{ TR_KEY_read_clipboard, TR_KEY_read_clipboard_kebab },
|
||||
{ TR_KEY_remote_session_enabled, TR_KEY_remote_session_enabled_kebab },
|
||||
{ TR_KEY_remote_session_host, TR_KEY_remote_session_host_kebab },
|
||||
{ TR_KEY_remote_session_https, TR_KEY_remote_session_https_kebab },
|
||||
{ TR_KEY_remote_session_password, TR_KEY_remote_session_password_kebab },
|
||||
{ TR_KEY_remote_session_port, TR_KEY_remote_session_port_kebab },
|
||||
{ TR_KEY_remote_session_requires_authentication, TR_KEY_remote_session_requres_authentication_kebab },
|
||||
{ TR_KEY_remote_session_username, TR_KEY_remote_session_username_kebab },
|
||||
{ TR_KEY_rename_partial_files, TR_KEY_rename_partial_files_kebab },
|
||||
{ TR_KEY_rpc_authentication_required, TR_KEY_rpc_authentication_required_kebab },
|
||||
{ TR_KEY_rpc_bind_address, TR_KEY_rpc_bind_address_kebab },
|
||||
{ TR_KEY_rpc_enabled, TR_KEY_rpc_enabled_kebab },
|
||||
{ TR_KEY_rpc_host_whitelist, TR_KEY_rpc_host_whitelist_kebab },
|
||||
{ TR_KEY_rpc_host_whitelist_enabled, TR_KEY_rpc_host_whitelist_enabled_kebab },
|
||||
{ TR_KEY_rpc_password, TR_KEY_rpc_password_kebab },
|
||||
{ TR_KEY_rpc_port, TR_KEY_rpc_port_kebab },
|
||||
{ TR_KEY_rpc_socket_mode, TR_KEY_rpc_socket_mode_kebab },
|
||||
{ TR_KEY_rpc_url, TR_KEY_rpc_url_kebab },
|
||||
{ TR_KEY_rpc_username, TR_KEY_rpc_username_kebab },
|
||||
{ TR_KEY_rpc_whitelist, TR_KEY_rpc_whitelist_kebab },
|
||||
{ TR_KEY_rpc_whitelist_enabled, TR_KEY_rpc_whitelist_enabled_kebab },
|
||||
{ TR_KEY_scrape_paused_torrents_enabled, TR_KEY_scrape_paused_torrents_enabled_kebab },
|
||||
{ TR_KEY_script_torrent_added_enabled, TR_KEY_script_torrent_added_enabled_kebab },
|
||||
{ TR_KEY_script_torrent_added_filename, TR_KEY_script_torrent_added_filename_kebab },
|
||||
{ TR_KEY_script_torrent_done_enabled, TR_KEY_script_torrent_done_enabled_kebab },
|
||||
{ TR_KEY_script_torrent_done_filename, TR_KEY_script_torrent_done_filename_kebab },
|
||||
{ TR_KEY_script_torrent_done_seeding_enabled, TR_KEY_script_torrent_done_seeding_enabled_kebab },
|
||||
{ TR_KEY_script_torrent_done_seeding_filename, TR_KEY_script_torrent_done_seeding_filename_kebab },
|
||||
{ TR_KEY_seconds_active, TR_KEY_seconds_active_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_seed_queue_enabled, TR_KEY_seed_queue_enabled_kebab },
|
||||
{ TR_KEY_seed_queue_size, TR_KEY_seed_queue_size_kebab },
|
||||
{ TR_KEY_seeding_time_seconds, TR_KEY_seeding_time_seconds_kebab },
|
||||
{ TR_KEY_session_count, TR_KEY_session_count_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_show_backup_trackers, TR_KEY_show_backup_trackers_kebab },
|
||||
{ TR_KEY_show_extra_peer_details, TR_KEY_show_extra_peer_details_kebab },
|
||||
{ TR_KEY_show_filterbar, TR_KEY_show_filterbar_kebab },
|
||||
{ TR_KEY_show_notification_area_icon, TR_KEY_show_notification_area_icon_kebab },
|
||||
{ TR_KEY_show_options_window, TR_KEY_show_options_window_kebab },
|
||||
{ TR_KEY_show_statusbar, TR_KEY_show_statusbar_kebab },
|
||||
{ TR_KEY_show_toolbar, TR_KEY_show_toolbar_kebab },
|
||||
{ TR_KEY_show_tracker_scrapes, TR_KEY_show_tracker_scrapes_kebab },
|
||||
{ TR_KEY_sleep_per_seconds_during_verify, TR_KEY_sleep_per_seconds_during_verify_kebab },
|
||||
{ TR_KEY_sort_mode, TR_KEY_sort_mode_kebab },
|
||||
{ TR_KEY_sort_reversed, TR_KEY_sort_reversed_kebab },
|
||||
{ TR_KEY_speed_Bps, TR_KEY_speed_Bps_kebab },
|
||||
{ TR_KEY_speed_limit_down, TR_KEY_speed_limit_down_kebab },
|
||||
{ TR_KEY_speed_limit_down_enabled, TR_KEY_speed_limit_down_enabled_kebab },
|
||||
{ TR_KEY_speed_limit_up, TR_KEY_speed_limit_up_kebab },
|
||||
{ TR_KEY_speed_limit_up_enabled, TR_KEY_speed_limit_up_enabled_kebab },
|
||||
{ TR_KEY_start_added_torrents, TR_KEY_start_added_torrents_kebab },
|
||||
{ TR_KEY_start_minimized, TR_KEY_start_minimized_kebab },
|
||||
{ TR_KEY_statusbar_stats, TR_KEY_statusbar_stats_kebab },
|
||||
{ TR_KEY_tcp_enabled, TR_KEY_tcp_enabled_kebab },
|
||||
{ TR_KEY_time_checked, TR_KEY_time_checked_kebab },
|
||||
{ TR_KEY_torrent_added_notification_enabled, TR_KEY_torrent_added_notification_enabled_kebab },
|
||||
{ TR_KEY_torrent_added_verify_mode, TR_KEY_torrent_added_verify_mode_kebab },
|
||||
{ TR_KEY_torrent_complete_notification_enabled, TR_KEY_torrent_complete_notification_enabled_kebab },
|
||||
{ TR_KEY_torrent_complete_sound_command, TR_KEY_torrent_complete_sound_command_kebab },
|
||||
{ TR_KEY_torrent_complete_sound_enabled, TR_KEY_torrent_complete_sound_enabled_kebab },
|
||||
{ TR_KEY_trash_can_enabled, TR_KEY_trash_can_enabled_kebab },
|
||||
{ TR_KEY_trash_original_torrent_files, TR_KEY_trash_original_torrent_files_kebab },
|
||||
{ TR_KEY_upload_slots_per_torrent, TR_KEY_upload_slots_per_torrent_kebab },
|
||||
{ TR_KEY_uploaded_bytes, TR_KEY_uploaded_bytes_kebab }, // TODO(ckerr) legacy duplicate
|
||||
{ TR_KEY_use_global_speed_limit, TR_KEY_use_global_speed_limit_kebab },
|
||||
{ TR_KEY_use_speed_limit, TR_KEY_use_speed_limit_kebab },
|
||||
{ TR_KEY_utp_enabled, TR_KEY_utp_enabled_kebab },
|
||||
{ TR_KEY_watch_dir, TR_KEY_watch_dir_kebab },
|
||||
{ TR_KEY_watch_dir_enabled, TR_KEY_watch_dir_enabled_kebab },
|
||||
{ TR_KEY_watch_dir_force_generic, TR_KEY_watch_dir_force_generic_kebab },
|
||||
} };
|
||||
|
||||
auto constexpr MethodNotFoundLegacyErrmsg = std::string_view{ "no method name" };
|
||||
|
||||
[[nodiscard]] constexpr tr_quark convert_key(tr_quark const src, Style const style, bool const is_rpc)
|
||||
{
|
||||
if (style == Style::Tr5)
|
||||
{
|
||||
for (auto const [current, legacy] : RpcKeys)
|
||||
{
|
||||
if (src == current || src == legacy)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
}
|
||||
for (auto const [current, legacy] : SessionKeys)
|
||||
{
|
||||
if (src == current || src == legacy)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_rpc) // legacy RPC
|
||||
{
|
||||
for (auto const [current, legacy] : RpcKeys)
|
||||
{
|
||||
if (src == current || src == legacy)
|
||||
{
|
||||
return legacy;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // legacy datafiles
|
||||
{
|
||||
for (auto const [current, legacy] : SessionKeys)
|
||||
{
|
||||
if (src == current || src == legacy)
|
||||
{
|
||||
return legacy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess the error code from a legacy RPC response message.
|
||||
*
|
||||
* Use case: a modern Transmission client that parses jsonrpc needs to
|
||||
* connect to a legacy Transmission RPC server.
|
||||
*
|
||||
* We're not going to always get this right: There are some edge cases
|
||||
* where legacy Transmission's error messages are unhelpful.
|
||||
*/
|
||||
[[nodiscard]] JsonRpc::Error::Code guess_error_code(std::string_view const result_in)
|
||||
{
|
||||
using namespace JsonRpc;
|
||||
|
||||
auto const result = tr_strlower(result_in);
|
||||
|
||||
if (result == "success")
|
||||
{
|
||||
return Error::SUCCESS;
|
||||
}
|
||||
|
||||
static auto constexpr Phrases = std::array<std::pair<std::string_view, Error::Code>, 14U>{ {
|
||||
{ "absolute", Error::PATH_NOT_ABSOLUTE },
|
||||
{ "couldn't fetch blocklist", Error::HTTP_ERROR },
|
||||
{ "couldn't save", Error::SYSTEM_ERROR },
|
||||
{ "couldn't test port", Error::HTTP_ERROR },
|
||||
{ "file index out of range", Error::FILE_IDX_OOR },
|
||||
{ "invalid ip protocol", Error::INVALID_PARAMS },
|
||||
{ "invalid or corrupt torrent", Error::CORRUPT_TORRENT },
|
||||
{ "invalid tracker list", Error::INVALID_TRACKER_LIST },
|
||||
{ "labels cannot", Error::INVALID_PARAMS },
|
||||
{ "no filename or metainfo specified", Error::INVALID_PARAMS },
|
||||
{ "no location", Error::INVALID_PARAMS },
|
||||
{ "torrent-rename-path requires 1 torrent", Error::INVALID_PARAMS },
|
||||
{ "unrecognized info", Error::UNRECOGNIZED_INFO },
|
||||
{ MethodNotFoundLegacyErrmsg, Error::METHOD_NOT_FOUND },
|
||||
} };
|
||||
|
||||
for (auto const& [substr, code] : Phrases)
|
||||
{
|
||||
if (tr_strv_contains(result, substr))
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
struct CloneState
|
||||
{
|
||||
api_compat::Style style = {};
|
||||
bool is_rpc = false;
|
||||
bool convert_strings = false;
|
||||
bool is_torrent = false;
|
||||
bool is_free_space_response = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] tr_variant convert_impl(tr_variant const& self, CloneState& state)
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
tr_variant operator()(std::monostate const& /*unused*/) const
|
||||
{
|
||||
return tr_variant{};
|
||||
}
|
||||
|
||||
tr_variant operator()(std::nullptr_t const& /*unused*/) const
|
||||
{
|
||||
return tr_variant{ nullptr };
|
||||
}
|
||||
|
||||
tr_variant operator()(bool const& val) const
|
||||
{
|
||||
return tr_variant{ val };
|
||||
}
|
||||
|
||||
tr_variant operator()(int64_t const& val) const
|
||||
{
|
||||
return tr_variant{ val };
|
||||
}
|
||||
|
||||
tr_variant operator()(double const& val) const
|
||||
{
|
||||
return tr_variant{ val };
|
||||
}
|
||||
|
||||
tr_variant operator()(std::string_view const& sv) const
|
||||
{
|
||||
if (!state_.convert_strings)
|
||||
{
|
||||
return sv;
|
||||
}
|
||||
|
||||
auto const lookup = tr_quark_lookup(sv);
|
||||
if (!lookup)
|
||||
{
|
||||
return sv;
|
||||
}
|
||||
|
||||
auto key = *lookup;
|
||||
|
||||
// crazy case 1: downloadDir in torrent-get, download-dir in session-get
|
||||
if (state_.is_rpc &&
|
||||
(key == TR_KEY_download_dir_camel || key == TR_KEY_download_dir_kebab || key == TR_KEY_download_dir))
|
||||
{
|
||||
if (state_.style == Style::Tr5)
|
||||
{
|
||||
key = TR_KEY_download_dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = state_.is_torrent ? TR_KEY_download_dir_camel : TR_KEY_download_dir_kebab;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
key = convert_key(key, state_.style, state_.is_rpc);
|
||||
}
|
||||
|
||||
return tr_variant::unmanaged_string(key);
|
||||
}
|
||||
|
||||
tr_variant operator()(tr_variant::Vector const& src)
|
||||
{
|
||||
auto tgt = tr_variant::Vector();
|
||||
tgt.reserve(std::size(src));
|
||||
for (auto const& val : src)
|
||||
{
|
||||
tgt.emplace_back(convert_impl(val, state_));
|
||||
}
|
||||
return tgt;
|
||||
}
|
||||
|
||||
tr_variant operator()(tr_variant::Map const& src)
|
||||
{
|
||||
auto tgt = tr_variant::Map{ std::size(src) };
|
||||
for (auto const& [key, val] : src)
|
||||
{
|
||||
auto const pop = state_.convert_strings;
|
||||
auto new_key = convert_key(key, state_.style, state_.is_rpc);
|
||||
auto const special =
|
||||
(state_.is_rpc &&
|
||||
(new_key == TR_KEY_method || new_key == TR_KEY_fields || new_key == TR_KEY_ids ||
|
||||
new_key == TR_KEY_torrents));
|
||||
// TODO(ckerr): replace `new_key == TR_KEY_TORRENTS` on previous line with logic to turn on convert
|
||||
// if it's an array inside an array val whose key was `torrents`.
|
||||
// This is for the edge case of table mode: `torrents : [ [ 'key1', 'key2' ], [ ... ] ]`
|
||||
state_.convert_strings |= special;
|
||||
|
||||
// Crazy case: total_size in free-space, totalSize in torrent-get
|
||||
if (state_.is_free_space_response && new_key == TR_KEY_total_size_camel)
|
||||
{
|
||||
new_key = TR_KEY_total_size;
|
||||
}
|
||||
|
||||
tgt.insert_or_assign(new_key, convert_impl(val, state_));
|
||||
state_.convert_strings = pop;
|
||||
}
|
||||
return tgt;
|
||||
}
|
||||
|
||||
CloneState& state_;
|
||||
};
|
||||
|
||||
return self.visit(Visitor{ state });
|
||||
}
|
||||
} // namespace
|
||||
|
||||
tr_variant convert(tr_variant const& src, Style const tgt_style)
|
||||
{
|
||||
// TODO: yes I know this method is ugly rn.
|
||||
// I've just been trying to get the tests passing.
|
||||
|
||||
auto const* const src_top = src.get_if<tr_variant::Map>();
|
||||
|
||||
// if it's not a Map, just clone it
|
||||
if (src_top == nullptr)
|
||||
{
|
||||
return src.clone();
|
||||
}
|
||||
|
||||
auto const is_request = src_top->contains(TR_KEY_method);
|
||||
|
||||
auto const was_jsonrpc = src_top->contains(TR_KEY_jsonrpc);
|
||||
auto const was_legacy = !was_jsonrpc;
|
||||
auto const was_jsonrpc_response = was_jsonrpc && (src_top->contains(TR_KEY_result) || src_top->contains(TR_KEY_error));
|
||||
auto const was_legacy_response = was_legacy && src_top->contains(TR_KEY_result);
|
||||
auto const is_response = was_jsonrpc_response || was_legacy_response;
|
||||
auto const is_rpc = is_request || is_response;
|
||||
|
||||
auto state = CloneState{};
|
||||
state.style = tgt_style;
|
||||
state.is_rpc = is_rpc;
|
||||
|
||||
auto const is_success = is_response &&
|
||||
(was_jsonrpc_response ? src_top->contains(TR_KEY_result) :
|
||||
src_top->value_if<std::string_view>(TR_KEY_result).value_or("") == "success");
|
||||
|
||||
if (auto const method = src_top->value_if<std::string_view>(TR_KEY_method))
|
||||
{
|
||||
auto const key = tr_quark_convert(tr_quark_new(*method));
|
||||
state.is_torrent = key == TR_KEY_torrent_get || key == TR_KEY_torrent_set;
|
||||
}
|
||||
|
||||
if (is_response)
|
||||
{
|
||||
if (auto const* const args = src_top->find_if<tr_variant::Map>(was_jsonrpc ? TR_KEY_result : TR_KEY_arguments))
|
||||
{
|
||||
state.is_free_space_response = args->contains(TR_KEY_path) &&
|
||||
args->contains(was_jsonrpc ? TR_KEY_size_bytes : TR_KEY_size_bytes_kebab);
|
||||
}
|
||||
}
|
||||
|
||||
auto ret = convert_impl(src, state);
|
||||
|
||||
auto* const tgt_top = ret.get_if<tr_variant::Map>();
|
||||
|
||||
// jsonrpc <-> legacy rpc conversion
|
||||
if (is_rpc)
|
||||
{
|
||||
auto const is_jsonrpc = tgt_style == Style::Tr5;
|
||||
auto const is_legacy = tgt_style != Style::Tr5;
|
||||
|
||||
// - use `jsonrpc` in jsonrpc, but not in legacy
|
||||
// - use `id` in jsonrpc; use `tag` in legacy
|
||||
if (is_jsonrpc)
|
||||
{
|
||||
tgt_top->try_emplace(TR_KEY_jsonrpc, tr_variant::unmanaged_string(JsonRpc::Version));
|
||||
tgt_top->replace_key(TR_KEY_tag, TR_KEY_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
tgt_top->erase(TR_KEY_jsonrpc);
|
||||
tgt_top->replace_key(TR_KEY_id, TR_KEY_tag);
|
||||
}
|
||||
|
||||
if (is_response && is_legacy && is_success && was_jsonrpc)
|
||||
{
|
||||
// in legacy messages:
|
||||
// - move `result` to `arguments`
|
||||
// - add `result: "success"`
|
||||
tgt_top->replace_key(TR_KEY_result, TR_KEY_arguments);
|
||||
tgt_top->try_emplace(TR_KEY_result, tr_variant::unmanaged_string("success"));
|
||||
}
|
||||
|
||||
if (is_response && is_legacy && !is_success)
|
||||
{
|
||||
// in legacy error responses:
|
||||
// - copy `error.data.error_string` to `result`
|
||||
// - remove `error` object
|
||||
// - add an empty `arguments` object
|
||||
if (auto* error_ptr = tgt_top->find_if<tr_variant::Map>(TR_KEY_error))
|
||||
{
|
||||
// move the `error` object before memory reallocations invalidate the pointer
|
||||
auto error = std::move(*error_ptr);
|
||||
tgt_top->erase(TR_KEY_error);
|
||||
|
||||
// crazy case: current and legacy METHOD_NOT_FOUND has different error messages
|
||||
if (auto const code = error.value_if<int64_t>(TR_KEY_code); code && *code == JsonRpc::Error::METHOD_NOT_FOUND)
|
||||
{
|
||||
tgt_top->try_emplace(TR_KEY_result, tr_variant::unmanaged_string(MethodNotFoundLegacyErrmsg));
|
||||
}
|
||||
|
||||
if (auto* data = error.find_if<tr_variant::Map>(TR_KEY_data))
|
||||
{
|
||||
if (auto const* errmsg = data->find_if<std::string_view>(TR_KEY_error_string_camel))
|
||||
{
|
||||
tgt_top->try_emplace(TR_KEY_result, *errmsg);
|
||||
}
|
||||
|
||||
if (auto const result = data->find(TR_KEY_result); result != std::end(*data))
|
||||
{
|
||||
tgt_top->try_emplace(TR_KEY_arguments, std::move(result->second));
|
||||
}
|
||||
}
|
||||
|
||||
if (auto const* errmsg = error.find_if<std::string_view>(TR_KEY_message))
|
||||
{
|
||||
tgt_top->try_emplace(TR_KEY_result, *errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
tgt_top->try_emplace(TR_KEY_arguments, tr_variant::make_map());
|
||||
}
|
||||
|
||||
if (is_response && is_jsonrpc && is_success && was_legacy)
|
||||
{
|
||||
tgt_top->erase(TR_KEY_result);
|
||||
tgt_top->replace_key(TR_KEY_arguments, TR_KEY_result);
|
||||
}
|
||||
|
||||
if (is_response && is_jsonrpc && !is_success && was_legacy)
|
||||
{
|
||||
// in jsonrpc error message:
|
||||
// - copy `result` to `error.data.error_string`
|
||||
// - ensure `error` object exists and is well-formatted
|
||||
// - remove `result`
|
||||
auto const errstr = tgt_top->value_if<std::string_view>(TR_KEY_result).value_or("unknown error");
|
||||
auto error = tr_variant::Map{ 3U };
|
||||
auto data = tr_variant::Map{ 2U };
|
||||
auto const code = guess_error_code(errstr);
|
||||
auto const errmsg = JsonRpc::Error::to_string(code);
|
||||
error.try_emplace(TR_KEY_code, code);
|
||||
error.try_emplace(TR_KEY_message, errmsg);
|
||||
// crazy case: current and legacy METHOD_NOT_FOUND has different error messages
|
||||
if (errstr != errmsg && errstr != MethodNotFoundLegacyErrmsg)
|
||||
{
|
||||
data.try_emplace(TR_KEY_error_string, errstr);
|
||||
}
|
||||
tgt_top->erase(TR_KEY_result);
|
||||
|
||||
if (auto const args_it = tgt_top->find(TR_KEY_arguments); args_it != std::end(*tgt_top))
|
||||
{
|
||||
auto args = std::move(args_it->second);
|
||||
tgt_top->erase(TR_KEY_arguments);
|
||||
|
||||
if (auto const* args_map = args.get_if<tr_variant::Map>(); args_map != nullptr && !std::empty(*args_map))
|
||||
{
|
||||
data.try_emplace(TR_KEY_result, std::move(args));
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::empty(data))
|
||||
{
|
||||
error.try_emplace(TR_KEY_data, std::move(data));
|
||||
}
|
||||
tgt_top->try_emplace(TR_KEY_error, std::move(error));
|
||||
}
|
||||
|
||||
if (is_request && is_jsonrpc)
|
||||
{
|
||||
tgt_top->replace_key(TR_KEY_arguments, TR_KEY_params);
|
||||
}
|
||||
|
||||
if (is_request && is_legacy)
|
||||
{
|
||||
tgt_top->replace_key(TR_KEY_params, TR_KEY_arguments);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
[[nodiscard]] Style get_export_settings_style()
|
||||
{
|
||||
// TODO: change default to Tr5 in transmission 5.0.0-beta.1
|
||||
static auto const style = tr_env_get_string("TR_SAVE_VERSION_FORMAT", "4") == "5" ? Style::Tr5 : Style::Tr4;
|
||||
return style;
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_variant convert_outgoing_data(tr_variant const& src)
|
||||
{
|
||||
return convert(src, get_export_settings_style());
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_variant convert_incoming_data(tr_variant const& src)
|
||||
{
|
||||
return convert(src, Style::Tr5);
|
||||
}
|
||||
} // namespace libtransmission::api_compat
|
||||
|
||||
tr_quark tr_quark_convert(tr_quark const quark)
|
||||
{
|
||||
using namespace libtransmission::api_compat;
|
||||
return convert_key(quark, Style::Tr5, false /*ignored for Style::Tr5*/);
|
||||
}
|
||||
36
libtransmission/api-compat.h
Normal file
36
libtransmission/api-compat.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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 <cstdint> // uint8_t
|
||||
|
||||
#include "libtransmission/quark.h"
|
||||
|
||||
struct tr_variant;
|
||||
|
||||
namespace libtransmission::api_compat
|
||||
{
|
||||
enum class Style : uint8_t
|
||||
{
|
||||
Tr4, // bespoke RPC, mixed-case keys,
|
||||
Tr5, // jsonrpc, all snake_case keys
|
||||
};
|
||||
|
||||
[[nodiscard]] tr_variant convert(tr_variant const& src, Style tgt_style);
|
||||
|
||||
[[nodiscard]] Style get_export_settings_style();
|
||||
|
||||
[[nodiscard]] tr_variant convert_incoming_data(tr_variant const& src);
|
||||
[[nodiscard]] tr_variant convert_outgoing_data(tr_variant const& src);
|
||||
|
||||
} // namespace libtransmission::api_compat
|
||||
|
||||
/**
|
||||
* Get the replacement quark from old deprecated quarks.
|
||||
*
|
||||
* Note: Temporary shim just for the transition period to snake_case.
|
||||
*/
|
||||
[[nodiscard]] tr_quark tr_quark_convert(tr_quark quark);
|
||||
@@ -795,324 +795,3 @@ std::string_view tr_quark_get_string_view(tr_quark q)
|
||||
{
|
||||
return q < TR_N_KEYS ? MyStatic[q] : my_runtime[q - TR_N_KEYS];
|
||||
}
|
||||
|
||||
tr_quark tr_quark_convert(tr_quark const q)
|
||||
{
|
||||
// clang-format off
|
||||
switch (q)
|
||||
{
|
||||
case TR_KEY_active_torrent_count_camel: return TR_KEY_active_torrent_count;
|
||||
case TR_KEY_activity_date_camel:
|
||||
case TR_KEY_activity_date_kebab:
|
||||
return TR_KEY_activity_date;
|
||||
case TR_KEY_added_date_camel:
|
||||
case TR_KEY_added_date_kebab:
|
||||
return TR_KEY_added_date;
|
||||
case TR_KEY_alt_speed_down_kebab: return TR_KEY_alt_speed_down;
|
||||
case TR_KEY_alt_speed_enabled_kebab: return TR_KEY_alt_speed_enabled;
|
||||
case TR_KEY_alt_speed_time_begin_kebab: return TR_KEY_alt_speed_time_begin;
|
||||
case TR_KEY_alt_speed_time_day_kebab: return TR_KEY_alt_speed_time_day;
|
||||
case TR_KEY_alt_speed_time_enabled_kebab: return TR_KEY_alt_speed_time_enabled;
|
||||
case TR_KEY_alt_speed_time_end_kebab: return TR_KEY_alt_speed_time_end;
|
||||
case TR_KEY_alt_speed_up_kebab: return TR_KEY_alt_speed_up;
|
||||
case TR_KEY_announce_ip_kebab: return TR_KEY_announce_ip;
|
||||
case TR_KEY_announce_ip_enabled_kebab: return TR_KEY_announce_ip_enabled;
|
||||
case TR_KEY_announce_state_camel: return TR_KEY_announce_state;
|
||||
case TR_KEY_anti_brute_force_enabled_kebab: return TR_KEY_anti_brute_force_enabled;
|
||||
case TR_KEY_anti_brute_force_threshold_kebab: return TR_KEY_anti_brute_force_threshold;
|
||||
case TR_KEY_bandwidth_priority_camel:
|
||||
case TR_KEY_bandwidth_priority_kebab:
|
||||
return TR_KEY_bandwidth_priority;
|
||||
case TR_KEY_bind_address_ipv4_kebab: return TR_KEY_bind_address_ipv4;
|
||||
case TR_KEY_bind_address_ipv6_kebab: return TR_KEY_bind_address_ipv6;
|
||||
case TR_KEY_blocklist_date_kebab: return TR_KEY_blocklist_date;
|
||||
case TR_KEY_blocklist_enabled_kebab: return TR_KEY_blocklist_enabled;
|
||||
case TR_KEY_blocklist_size_kebab: return TR_KEY_blocklist_size;
|
||||
case TR_KEY_blocklist_update_kebab: return TR_KEY_blocklist_update;
|
||||
case TR_KEY_blocklist_updates_enabled_kebab: return TR_KEY_blocklist_updates_enabled;
|
||||
case TR_KEY_blocklist_url_kebab: return TR_KEY_blocklist_url;
|
||||
case TR_KEY_bytes_completed_camel: return TR_KEY_bytes_completed;
|
||||
case TR_KEY_cache_size_mb_kebab: return TR_KEY_cache_size_mb;
|
||||
case TR_KEY_client_is_choked_camel: return TR_KEY_client_is_choked;
|
||||
case TR_KEY_client_is_interested_camel: return TR_KEY_client_is_interested;
|
||||
case TR_KEY_client_name_camel: return TR_KEY_client_name;
|
||||
case TR_KEY_compact_view_kebab: return TR_KEY_compact_view;
|
||||
case TR_KEY_config_dir_kebab: return TR_KEY_config_dir;
|
||||
case TR_KEY_corrupt_ever_camel: return TR_KEY_corrupt_ever;
|
||||
case TR_KEY_cumulative_stats_kebab: return TR_KEY_cumulative_stats;
|
||||
case TR_KEY_current_stats_kebab: return TR_KEY_current_stats;
|
||||
case TR_KEY_date_created_camel: return TR_KEY_date_created;
|
||||
case TR_KEY_default_trackers_kebab: return TR_KEY_default_trackers;
|
||||
case TR_KEY_delete_local_data_kebab: return TR_KEY_delete_local_data;
|
||||
case TR_KEY_desired_available_camel: return TR_KEY_desired_available;
|
||||
case TR_KEY_details_window_height_kebab: return TR_KEY_details_window_height;
|
||||
case TR_KEY_details_window_width_kebab: return TR_KEY_details_window_width;
|
||||
case TR_KEY_dht_enabled_kebab: return TR_KEY_dht_enabled;
|
||||
case TR_KEY_done_date_camel:
|
||||
case TR_KEY_done_date_kebab:
|
||||
return TR_KEY_done_date;
|
||||
case TR_KEY_download_count_camel: return TR_KEY_download_count;
|
||||
case TR_KEY_download_dir_camel:
|
||||
case TR_KEY_download_dir_kebab:
|
||||
return TR_KEY_download_dir;
|
||||
case TR_KEY_download_dir_free_space_kebab: return TR_KEY_download_dir_free_space;
|
||||
case TR_KEY_download_limit_camel: return TR_KEY_download_limit;
|
||||
case TR_KEY_download_limited_camel: return TR_KEY_download_limited;
|
||||
case TR_KEY_download_queue_enabled_kebab: return TR_KEY_download_queue_enabled;
|
||||
case TR_KEY_download_queue_size_kebab: return TR_KEY_download_queue_size;
|
||||
case TR_KEY_download_speed_camel: return TR_KEY_download_speed;
|
||||
case TR_KEY_downloaded_bytes_camel:
|
||||
case TR_KEY_downloaded_bytes_kebab:
|
||||
return TR_KEY_downloaded_bytes;
|
||||
case TR_KEY_downloaded_ever_camel: return TR_KEY_downloaded_ever;
|
||||
case TR_KEY_downloading_time_seconds_kebab: return TR_KEY_downloading_time_seconds;
|
||||
case TR_KEY_edit_date_camel: return TR_KEY_edit_date;
|
||||
case TR_KEY_error_string_camel: return TR_KEY_error_string;
|
||||
case TR_KEY_eta_idle_camel: return TR_KEY_eta_idle;
|
||||
case TR_KEY_file_count_kebab: return TR_KEY_file_count;
|
||||
case TR_KEY_file_stats_camel: return TR_KEY_file_stats;
|
||||
case TR_KEY_files_added_camel:
|
||||
case TR_KEY_files_added_kebab:
|
||||
return TR_KEY_files_added;
|
||||
case TR_KEY_files_unwanted_kebab: return TR_KEY_files_unwanted;
|
||||
case TR_KEY_files_wanted_kebab: return TR_KEY_files_wanted;
|
||||
case TR_KEY_filter_mode_kebab: return TR_KEY_filter_mode;
|
||||
case TR_KEY_filter_text_kebab: return TR_KEY_filter_text;
|
||||
case TR_KEY_filter_trackers_kebab: return TR_KEY_filter_trackers;
|
||||
case TR_KEY_flag_str_camel: return TR_KEY_flag_str;
|
||||
case TR_KEY_free_space_kebab: return TR_KEY_free_space;
|
||||
case TR_KEY_from_cache_camel: return TR_KEY_from_cache;
|
||||
case TR_KEY_from_dht_camel: return TR_KEY_from_dht;
|
||||
case TR_KEY_from_incoming_camel: return TR_KEY_from_incoming;
|
||||
case TR_KEY_from_lpd_camel: return TR_KEY_from_lpd;
|
||||
case TR_KEY_from_ltep_camel: return TR_KEY_from_ltep;
|
||||
case TR_KEY_from_pex_camel: return TR_KEY_from_pex;
|
||||
case TR_KEY_from_tracker_camel: return TR_KEY_from_tracker;
|
||||
case TR_KEY_group_get_kebab: return TR_KEY_group_get;
|
||||
case TR_KEY_group_set_kebab: return TR_KEY_group_set;
|
||||
case TR_KEY_hash_string_camel: return TR_KEY_hash_string;
|
||||
case TR_KEY_has_announced_camel: return TR_KEY_has_announced;
|
||||
case TR_KEY_has_scraped_camel: return TR_KEY_has_scraped;
|
||||
case TR_KEY_have_unchecked_camel: return TR_KEY_have_unchecked;
|
||||
case TR_KEY_have_valid_camel: return TR_KEY_have_valid;
|
||||
case TR_KEY_honors_session_limits_camel: return TR_KEY_honors_session_limits;
|
||||
case TR_KEY_idle_limit_kebab: return TR_KEY_idle_limit;
|
||||
case TR_KEY_idle_mode_kebab: return TR_KEY_idle_mode;
|
||||
case TR_KEY_idle_seeding_limit_kebab: return TR_KEY_idle_seeding_limit;
|
||||
case TR_KEY_idle_seeding_limit_enabled_kebab: return TR_KEY_idle_seeding_limit_enabled;
|
||||
case TR_KEY_incomplete_dir_kebab: return TR_KEY_incomplete_dir;
|
||||
case TR_KEY_incomplete_dir_enabled_kebab: return TR_KEY_incomplete_dir_enabled;
|
||||
case TR_KEY_inhibit_desktop_hibernation_kebab: return TR_KEY_inhibit_desktop_hibernation;
|
||||
case TR_KEY_is_backup_camel: return TR_KEY_is_backup;
|
||||
case TR_KEY_is_downloading_from_camel: return TR_KEY_is_downloading_from;
|
||||
case TR_KEY_is_encrypted_camel: return TR_KEY_is_encrypted;
|
||||
case TR_KEY_is_finished_camel: return TR_KEY_is_finished;
|
||||
case TR_KEY_is_incoming_camel: return TR_KEY_is_incoming;
|
||||
case TR_KEY_is_private_camel: return TR_KEY_is_private;
|
||||
case TR_KEY_is_stalled_camel: return TR_KEY_is_stalled;
|
||||
case TR_KEY_is_uploading_to_camel: return TR_KEY_is_uploading_to;
|
||||
case TR_KEY_is_utp_camel: return TR_KEY_is_utp;
|
||||
case TR_KEY_last_announce_peer_count_camel: return TR_KEY_last_announce_peer_count;
|
||||
case TR_KEY_last_announce_result_camel: return TR_KEY_last_announce_result;
|
||||
case TR_KEY_last_announce_start_time_camel: return TR_KEY_last_announce_start_time;
|
||||
case TR_KEY_last_announce_succeeded_camel: return TR_KEY_last_announce_succeeded;
|
||||
case TR_KEY_last_announce_time_camel: return TR_KEY_last_announce_time;
|
||||
case TR_KEY_last_announce_timed_out_camel: return TR_KEY_last_announce_timed_out;
|
||||
case TR_KEY_last_scrape_result_camel: return TR_KEY_last_scrape_result;
|
||||
case TR_KEY_last_scrape_start_time_camel: return TR_KEY_last_scrape_start_time;
|
||||
case TR_KEY_last_scrape_succeeded_camel: return TR_KEY_last_scrape_succeeded;
|
||||
case TR_KEY_last_scrape_time_camel: return TR_KEY_last_scrape_time;
|
||||
case TR_KEY_last_scrape_timed_out_camel: return TR_KEY_last_scrape_timed_out;
|
||||
case TR_KEY_leecher_count_camel: return TR_KEY_leecher_count;
|
||||
case TR_KEY_left_until_done_camel: return TR_KEY_left_until_done;
|
||||
case TR_KEY_lpd_enabled_kebab: return TR_KEY_lpd_enabled;
|
||||
case TR_KEY_magnet_link_camel: return TR_KEY_magnet_link;
|
||||
case TR_KEY_main_window_height_kebab: return TR_KEY_main_window_height;
|
||||
case TR_KEY_main_window_is_maximized_kebab: return TR_KEY_main_window_is_maximized;
|
||||
case TR_KEY_main_window_layout_order_kebab: return TR_KEY_main_window_layout_order;
|
||||
case TR_KEY_main_window_width_kebab: return TR_KEY_main_window_width;
|
||||
case TR_KEY_main_window_x_kebab: return TR_KEY_main_window_x;
|
||||
case TR_KEY_main_window_y_kebab: return TR_KEY_main_window_y;
|
||||
case TR_KEY_manual_announce_time_camel: return TR_KEY_manual_announce_time;
|
||||
case TR_KEY_max_connected_peers_camel: return TR_KEY_max_connected_peers;
|
||||
case TR_KEY_max_peers_kebab: return TR_KEY_max_peers;
|
||||
case TR_KEY_memory_bytes_kebab: return TR_KEY_memory_bytes;
|
||||
case TR_KEY_memory_units_kebab: return TR_KEY_memory_units;
|
||||
case TR_KEY_message_level_kebab: return TR_KEY_message_level;
|
||||
case TR_KEY_metadata_percent_complete_camel: return TR_KEY_metadata_percent_complete;
|
||||
case TR_KEY_next_announce_time_camel: return TR_KEY_next_announce_time;
|
||||
case TR_KEY_next_scrape_time_camel: return TR_KEY_next_scrape_time;
|
||||
case TR_KEY_open_dialog_dir_kebab: return TR_KEY_open_dialog_dir;
|
||||
case TR_KEY_paused_torrent_count_camel: return TR_KEY_paused_torrent_count;
|
||||
case TR_KEY_peer_congestion_algorithm_kebab: return TR_KEY_peer_congestion_algorithm;
|
||||
case TR_KEY_peer_is_choked_camel: return TR_KEY_peer_is_choked;
|
||||
case TR_KEY_peer_is_interested_camel: return TR_KEY_peer_is_interested;
|
||||
case TR_KEY_peer_limit_kebab: return TR_KEY_peer_limit;
|
||||
case TR_KEY_peer_limit_global_kebab: return TR_KEY_peer_limit_global;
|
||||
case TR_KEY_peer_limit_per_torrent_kebab: return TR_KEY_peer_limit_per_torrent;
|
||||
case TR_KEY_peer_port_kebab: return TR_KEY_peer_port;
|
||||
case TR_KEY_peer_port_random_high_kebab: return TR_KEY_peer_port_random_high;
|
||||
case TR_KEY_peer_port_random_low_kebab: return TR_KEY_peer_port_random_low;
|
||||
case TR_KEY_peer_port_random_on_start_kebab: return TR_KEY_peer_port_random_on_start;
|
||||
case TR_KEY_peer_socket_tos_kebab: return TR_KEY_peer_socket_tos;
|
||||
case TR_KEY_peers2_6_kebab: return TR_KEY_peers2_6;
|
||||
case TR_KEY_peers_connected_camel: return TR_KEY_peers_connected;
|
||||
case TR_KEY_peers_from_camel: return TR_KEY_peers_from;
|
||||
case TR_KEY_peers_getting_from_us_camel: return TR_KEY_peers_getting_from_us;
|
||||
case TR_KEY_peers_sending_to_us_camel: return TR_KEY_peers_sending_to_us;
|
||||
case TR_KEY_percent_complete_camel: return TR_KEY_percent_complete;
|
||||
case TR_KEY_percent_done_camel: return TR_KEY_percent_done;
|
||||
case TR_KEY_pex_enabled_kebab: return TR_KEY_pex_enabled;
|
||||
case TR_KEY_piece_count_camel: return TR_KEY_piece_count;
|
||||
case TR_KEY_piece_size_camel: return TR_KEY_piece_size;
|
||||
case TR_KEY_port_forwarding_enabled_kebab: return TR_KEY_port_forwarding_enabled;
|
||||
case TR_KEY_port_is_open_kebab: return TR_KEY_port_is_open;
|
||||
case TR_KEY_port_test_kebab: return TR_KEY_port_test;
|
||||
case TR_KEY_primary_mime_type_kebab: return TR_KEY_primary_mime_type;
|
||||
case TR_KEY_priority_high_kebab: return TR_KEY_priority_high;
|
||||
case TR_KEY_priority_low_kebab: return TR_KEY_priority_low;
|
||||
case TR_KEY_priority_normal_kebab: return TR_KEY_priority_normal;
|
||||
case TR_KEY_prompt_before_exit_kebab: return TR_KEY_prompt_before_exit;
|
||||
case TR_KEY_queue_position_camel: return TR_KEY_queue_position;
|
||||
case TR_KEY_queue_move_bottom_kebab: return TR_KEY_queue_move_bottom;
|
||||
case TR_KEY_queue_move_down_kebab: return TR_KEY_queue_move_down;
|
||||
case TR_KEY_queue_move_top_kebab: return TR_KEY_queue_move_top;
|
||||
case TR_KEY_queue_move_up_kebab: return TR_KEY_queue_move_up;
|
||||
case TR_KEY_queue_stalled_enabled_kebab: return TR_KEY_queue_stalled_enabled;
|
||||
case TR_KEY_queue_stalled_minutes_kebab: return TR_KEY_queue_stalled_minutes;
|
||||
case TR_KEY_rate_download_camel: return TR_KEY_rate_download;
|
||||
case TR_KEY_rate_to_client_camel: return TR_KEY_rate_to_client;
|
||||
case TR_KEY_rate_to_peer_camel: return TR_KEY_rate_to_peer;
|
||||
case TR_KEY_rate_upload_camel: return TR_KEY_rate_upload;
|
||||
case TR_KEY_ratio_limit_kebab: return TR_KEY_ratio_limit;
|
||||
case TR_KEY_ratio_limit_enabled_kebab: return TR_KEY_ratio_limit_enabled;
|
||||
case TR_KEY_ratio_mode_kebab: return TR_KEY_ratio_mode;
|
||||
case TR_KEY_read_clipboard_kebab: return TR_KEY_read_clipboard;
|
||||
case TR_KEY_recheck_progress_camel: return TR_KEY_recheck_progress;
|
||||
case TR_KEY_remote_session_enabled_kebab: return TR_KEY_remote_session_enabled;
|
||||
case TR_KEY_remote_session_host_kebab: return TR_KEY_remote_session_host;
|
||||
case TR_KEY_remote_session_https_kebab: return TR_KEY_remote_session_https;
|
||||
case TR_KEY_remote_session_password_kebab: return TR_KEY_remote_session_password;
|
||||
case TR_KEY_remote_session_port_kebab: return TR_KEY_remote_session_port;
|
||||
case TR_KEY_remote_session_requres_authentication_kebab: return TR_KEY_remote_session_requires_authentication;
|
||||
case TR_KEY_remote_session_username_kebab: return TR_KEY_remote_session_username;
|
||||
case TR_KEY_rename_partial_files_kebab: return TR_KEY_rename_partial_files;
|
||||
case TR_KEY_rpc_authentication_required_kebab: return TR_KEY_rpc_authentication_required;
|
||||
case TR_KEY_rpc_bind_address_kebab: return TR_KEY_rpc_bind_address;
|
||||
case TR_KEY_rpc_enabled_kebab: return TR_KEY_rpc_enabled;
|
||||
case TR_KEY_rpc_host_whitelist_kebab: return TR_KEY_rpc_host_whitelist;
|
||||
case TR_KEY_rpc_host_whitelist_enabled_kebab: return TR_KEY_rpc_host_whitelist_enabled;
|
||||
case TR_KEY_rpc_password_kebab: return TR_KEY_rpc_password;
|
||||
case TR_KEY_rpc_port_kebab: return TR_KEY_rpc_port;
|
||||
case TR_KEY_rpc_socket_mode_kebab: return TR_KEY_rpc_socket_mode;
|
||||
case TR_KEY_rpc_url_kebab: return TR_KEY_rpc_url;
|
||||
case TR_KEY_rpc_username_kebab: return TR_KEY_rpc_username;
|
||||
case TR_KEY_rpc_version_kebab: return TR_KEY_rpc_version;
|
||||
case TR_KEY_rpc_version_minimum_kebab: return TR_KEY_rpc_version_minimum;
|
||||
case TR_KEY_rpc_version_semver_kebab: return TR_KEY_rpc_version_semver;
|
||||
case TR_KEY_rpc_whitelist_kebab: return TR_KEY_rpc_whitelist;
|
||||
case TR_KEY_rpc_whitelist_enabled_kebab: return TR_KEY_rpc_whitelist_enabled;
|
||||
case TR_KEY_seconds_downloading_camel: return TR_KEY_seconds_downloading;
|
||||
case TR_KEY_scrape_paused_torrents_enabled_kebab: return TR_KEY_scrape_paused_torrents_enabled;
|
||||
case TR_KEY_scrape_state_camel: return TR_KEY_scrape_state;
|
||||
case TR_KEY_script_torrent_added_enabled_kebab: return TR_KEY_script_torrent_added_enabled;
|
||||
case TR_KEY_script_torrent_added_filename_kebab: return TR_KEY_script_torrent_added_filename;
|
||||
case TR_KEY_script_torrent_done_enabled_kebab: return TR_KEY_script_torrent_done_enabled;
|
||||
case TR_KEY_script_torrent_done_filename_kebab: return TR_KEY_script_torrent_done_filename;
|
||||
case TR_KEY_script_torrent_done_seeding_enabled_kebab: return TR_KEY_script_torrent_done_seeding_enabled;
|
||||
case TR_KEY_script_torrent_done_seeding_filename_kebab: return TR_KEY_script_torrent_done_seeding_filename;
|
||||
case TR_KEY_seconds_active_camel:
|
||||
case TR_KEY_seconds_active_kebab:
|
||||
return TR_KEY_seconds_active;
|
||||
case TR_KEY_seconds_seeding_camel: return TR_KEY_seconds_seeding;
|
||||
case TR_KEY_seed_idle_limit_camel: return TR_KEY_seed_idle_limit;
|
||||
case TR_KEY_seed_idle_mode_camel: return TR_KEY_seed_idle_mode;
|
||||
case TR_KEY_seed_queue_enabled_kebab: return TR_KEY_seed_queue_enabled;
|
||||
case TR_KEY_seed_queue_size_kebab: return TR_KEY_seed_queue_size;
|
||||
case TR_KEY_seed_ratio_limit_camel: return TR_KEY_seed_ratio_limit;
|
||||
case TR_KEY_seed_ratio_limited_camel: return TR_KEY_seed_ratio_limited;
|
||||
case TR_KEY_seed_ratio_mode_camel: return TR_KEY_seed_ratio_mode;
|
||||
case TR_KEY_seeding_time_seconds_kebab: return TR_KEY_seeding_time_seconds;
|
||||
case TR_KEY_seeder_count_camel: return TR_KEY_seeder_count;
|
||||
case TR_KEY_session_close_kebab: return TR_KEY_session_close;
|
||||
case TR_KEY_session_count_camel:
|
||||
case TR_KEY_session_count_kebab:
|
||||
return TR_KEY_session_count;
|
||||
case TR_KEY_session_get_kebab: return TR_KEY_session_get;
|
||||
case TR_KEY_session_id_kebab: return TR_KEY_session_id;
|
||||
case TR_KEY_session_set_kebab: return TR_KEY_session_set;
|
||||
case TR_KEY_session_stats_kebab: return TR_KEY_session_stats;
|
||||
case TR_KEY_show_backup_trackers_kebab: return TR_KEY_show_backup_trackers;
|
||||
case TR_KEY_show_extra_peer_details_kebab: return TR_KEY_show_extra_peer_details;
|
||||
case TR_KEY_show_filterbar_kebab: return TR_KEY_show_filterbar;
|
||||
case TR_KEY_show_notification_area_icon_kebab: return TR_KEY_show_notification_area_icon;
|
||||
case TR_KEY_show_options_window_kebab: return TR_KEY_show_options_window;
|
||||
case TR_KEY_show_statusbar_kebab: return TR_KEY_show_statusbar;
|
||||
case TR_KEY_show_toolbar_kebab: return TR_KEY_show_toolbar;
|
||||
case TR_KEY_show_tracker_scrapes_kebab: return TR_KEY_show_tracker_scrapes;
|
||||
case TR_KEY_size_bytes_kebab: return TR_KEY_size_bytes;
|
||||
case TR_KEY_size_units_kebab: return TR_KEY_size_units;
|
||||
case TR_KEY_size_when_done_camel: return TR_KEY_size_when_done;
|
||||
case TR_KEY_sleep_per_seconds_during_verify_kebab: return TR_KEY_sleep_per_seconds_during_verify;
|
||||
case TR_KEY_sort_mode_kebab: return TR_KEY_sort_mode;
|
||||
case TR_KEY_sort_reversed_kebab: return TR_KEY_sort_reversed;
|
||||
case TR_KEY_speed_Bps_kebab: return TR_KEY_speed_Bps;
|
||||
case TR_KEY_speed_bytes_kebab: return TR_KEY_speed_bytes;
|
||||
case TR_KEY_speed_limit_down_kebab: return TR_KEY_speed_limit_down;
|
||||
case TR_KEY_speed_limit_down_enabled_kebab: return TR_KEY_speed_limit_down_enabled;
|
||||
case TR_KEY_speed_limit_up_kebab: return TR_KEY_speed_limit_up;
|
||||
case TR_KEY_speed_limit_up_enabled_kebab: return TR_KEY_speed_limit_up_enabled;
|
||||
case TR_KEY_speed_units_kebab: return TR_KEY_speed_units;
|
||||
case TR_KEY_start_added_torrents_kebab: return TR_KEY_start_added_torrents;
|
||||
case TR_KEY_start_date_camel: return TR_KEY_start_date;
|
||||
case TR_KEY_start_minimized_kebab: return TR_KEY_start_minimized;
|
||||
case TR_KEY_statusbar_stats_kebab: return TR_KEY_statusbar_stats;
|
||||
case TR_KEY_tcp_enabled_kebab: return TR_KEY_tcp_enabled;
|
||||
case TR_KEY_torrent_add_kebab: return TR_KEY_torrent_add;
|
||||
case TR_KEY_torrent_added_kebab: return TR_KEY_torrent_added;
|
||||
case TR_KEY_torrent_added_notification_enabled_kebab: return TR_KEY_torrent_added_notification_enabled;
|
||||
case TR_KEY_torrent_added_verify_mode_kebab: return TR_KEY_torrent_added_verify_mode;
|
||||
case TR_KEY_torrent_complete_notification_enabled_kebab: return TR_KEY_torrent_complete_notification_enabled;
|
||||
case TR_KEY_torrent_complete_sound_command_kebab: return TR_KEY_torrent_complete_sound_command;
|
||||
case TR_KEY_torrent_complete_sound_enabled_kebab: return TR_KEY_torrent_complete_sound_enabled;
|
||||
case TR_KEY_torrent_count_camel: return TR_KEY_torrent_count;
|
||||
case TR_KEY_torrent_duplicate_kebab: return TR_KEY_torrent_duplicate;
|
||||
case TR_KEY_torrent_file_camel: return TR_KEY_torrent_file;
|
||||
case TR_KEY_torrent_get_kebab: return TR_KEY_torrent_get;
|
||||
case TR_KEY_torrent_reannounce_kebab: return TR_KEY_torrent_reannounce;
|
||||
case TR_KEY_torrent_remove_kebab: return TR_KEY_torrent_remove;
|
||||
case TR_KEY_torrent_rename_path_kebab: return TR_KEY_torrent_rename_path;
|
||||
case TR_KEY_torrent_set_kebab: return TR_KEY_torrent_set;
|
||||
case TR_KEY_torrent_set_location_kebab: return TR_KEY_torrent_set_location;
|
||||
case TR_KEY_torrent_start_kebab: return TR_KEY_torrent_start;
|
||||
case TR_KEY_torrent_start_now_kebab: return TR_KEY_torrent_start_now;
|
||||
case TR_KEY_torrent_stop_kebab: return TR_KEY_torrent_stop;
|
||||
case TR_KEY_torrent_verify_kebab: return TR_KEY_torrent_verify;
|
||||
case TR_KEY_total_size_camel: return TR_KEY_total_size;
|
||||
case TR_KEY_tracker_add_camel: return TR_KEY_tracker_add;
|
||||
case TR_KEY_tracker_list_camel: return TR_KEY_tracker_list;
|
||||
case TR_KEY_tracker_remove_camel: return TR_KEY_tracker_remove;
|
||||
case TR_KEY_tracker_replace_camel: return TR_KEY_tracker_replace;
|
||||
case TR_KEY_tracker_stats_camel: return TR_KEY_tracker_stats;
|
||||
case TR_KEY_trash_can_enabled_kebab: return TR_KEY_trash_can_enabled;
|
||||
case TR_KEY_trash_original_torrent_files_kebab: return TR_KEY_trash_original_torrent_files;
|
||||
case TR_KEY_upload_limit_camel: return TR_KEY_upload_limit;
|
||||
case TR_KEY_upload_limited_camel: return TR_KEY_upload_limited;
|
||||
case TR_KEY_upload_slots_per_torrent_kebab: return TR_KEY_upload_slots_per_torrent;
|
||||
case TR_KEY_upload_ratio_camel: return TR_KEY_upload_ratio;
|
||||
case TR_KEY_upload_speed_camel: return TR_KEY_upload_speed;
|
||||
case TR_KEY_uploaded_bytes_camel:
|
||||
case TR_KEY_uploaded_bytes_kebab:
|
||||
return TR_KEY_uploaded_bytes;
|
||||
case TR_KEY_uploaded_ever_camel: return TR_KEY_uploaded_ever;
|
||||
case TR_KEY_use_global_speed_limit_kebab: return TR_KEY_use_global_speed_limit;
|
||||
case TR_KEY_use_speed_limit_kebab: return TR_KEY_use_speed_limit;
|
||||
case TR_KEY_utp_enabled_kebab: return TR_KEY_utp_enabled;
|
||||
case TR_KEY_watch_dir_kebab: return TR_KEY_watch_dir;
|
||||
case TR_KEY_watch_dir_enabled_kebab: return TR_KEY_watch_dir_enabled;
|
||||
case TR_KEY_watch_dir_force_generic_kebab: return TR_KEY_watch_dir_force_generic;
|
||||
case TR_KEY_webseeds_sending_to_us_camel: return TR_KEY_webseeds_sending_to_us;
|
||||
default: return q;
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
@@ -752,10 +752,3 @@ enum // NOLINT(performance-enum-size)
|
||||
* created.
|
||||
*/
|
||||
[[nodiscard]] tr_quark tr_quark_new(std::string_view str);
|
||||
|
||||
/**
|
||||
* Get the replacement quark from old deprecated quarks.
|
||||
*
|
||||
* Note: Temporary shim just for the transition period to snake_case.
|
||||
*/
|
||||
[[nodiscard]] tr_quark tr_quark_convert(tr_quark quark);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "libtransmission/log.h"
|
||||
#include "libtransmission/net.h"
|
||||
#include "libtransmission/peer-mgr.h"
|
||||
#include "libtransmission/api-compat.h"
|
||||
#include "libtransmission/quark.h"
|
||||
#include "libtransmission/rpcimpl.h"
|
||||
#include "libtransmission/session.h"
|
||||
@@ -54,9 +55,7 @@ namespace JsonRpc
|
||||
// https://www.jsonrpc.org/specification#error_object
|
||||
namespace Error
|
||||
{
|
||||
namespace
|
||||
{
|
||||
[[nodiscard]] constexpr std::string_view get_message(Code code)
|
||||
[[nodiscard]] std::string_view to_string(Code const code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
@@ -95,6 +94,8 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
[[nodiscard]] tr_variant::Map build_data(std::string_view error_string, tr_variant::Map&& result)
|
||||
{
|
||||
auto ret = tr_variant::Map{ 2U };
|
||||
@@ -116,7 +117,7 @@ namespace
|
||||
{
|
||||
auto ret = tr_variant::Map{ 3U };
|
||||
ret.try_emplace(TR_KEY_code, code);
|
||||
ret.try_emplace(TR_KEY_message, tr_variant::unmanaged_string(get_message(code)));
|
||||
ret.try_emplace(TR_KEY_message, tr_variant::unmanaged_string(to_string(code)));
|
||||
if (!std::empty(data))
|
||||
{
|
||||
ret.try_emplace(TR_KEY_data, std::move(data));
|
||||
@@ -205,7 +206,7 @@ void tr_rpc_idle_done_legacy(struct tr_rpc_idle_data* data, JsonRpc::Error::Code
|
||||
// build the response
|
||||
auto response_map = tr_variant::Map{ 3U };
|
||||
response_map.try_emplace(TR_KEY_arguments, std::move(data->args_out));
|
||||
response_map.try_emplace(TR_KEY_result, std::empty(result) ? JsonRpc::Error::get_message(code) : result);
|
||||
response_map.try_emplace(TR_KEY_result, std::empty(result) ? JsonRpc::Error::to_string(code) : result);
|
||||
if (auto& tag = data->id; tag.has_value())
|
||||
{
|
||||
response_map.try_emplace(TR_KEY_tag, std::move(tag));
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // int16_t
|
||||
#include <functional>
|
||||
|
||||
struct tr_session;
|
||||
@@ -34,7 +35,9 @@ enum Code : int16_t
|
||||
HTTP_ERROR,
|
||||
CORRUPT_TORRENT
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string_view to_string(Code code);
|
||||
} // namespace Error
|
||||
} // namespace JsonRpc
|
||||
|
||||
using tr_rpc_response_func = std::function<void(tr_session* session, tr_variant&& response)>;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#define LIBTRANSMISSION_VARIANT_MODULE
|
||||
|
||||
#include "libtransmission/api-compat.h"
|
||||
#include "libtransmission/error.h"
|
||||
#include "libtransmission/log.h"
|
||||
#include "libtransmission/quark.h"
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#endif
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
|
||||
#include <libtransmission/api-compat.h>
|
||||
#include <libtransmission/variant.h>
|
||||
|
||||
#include "CustomVariantType.h"
|
||||
|
||||
@@ -7,6 +7,7 @@ target_sources(libtransmission-test
|
||||
announce-list-test.cc
|
||||
announcer-test.cc
|
||||
announcer-udp-test.cc
|
||||
api-compat-test.cc
|
||||
benc-test.cc
|
||||
bitfield-test.cc
|
||||
block-info-test.cc
|
||||
@@ -16,8 +17,8 @@ target_sources(libtransmission-test
|
||||
completion-test.cc
|
||||
copy-test.cc
|
||||
crypto-test.cc
|
||||
error-test.cc
|
||||
dht-test.cc
|
||||
error-test.cc
|
||||
file-piece-map-test.cc
|
||||
file-test.cc
|
||||
getopt-test.cc
|
||||
|
||||
738
tests/libtransmission/api-compat-test.cc
Normal file
738
tests/libtransmission/api-compat-test.cc
Normal file
@@ -0,0 +1,738 @@
|
||||
// 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.
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <libtransmission/api-compat.h>
|
||||
#include <libtransmission/quark.h>
|
||||
#include <libtransmission/variant.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "test-fixtures.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr std::string_view LegacySessionGetJson = R"json({
|
||||
"method": "session-get",
|
||||
"tag": 0
|
||||
})json";
|
||||
|
||||
constexpr std::string_view CurrentSessionGetJson = R"json({
|
||||
"id": 0,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "session_get"
|
||||
})json";
|
||||
|
||||
constexpr std::string_view LegacySessionGetResponseJson = R"json({
|
||||
"arguments": {
|
||||
"alt-speed-down": 50,
|
||||
"alt-speed-enabled": false,
|
||||
"alt-speed-time-begin": 540,
|
||||
"alt-speed-time-day": 127,
|
||||
"alt-speed-time-enabled": false,
|
||||
"alt-speed-time-end": 1020,
|
||||
"alt-speed-up": 50,
|
||||
"anti-brute-force-enabled": false,
|
||||
"anti-brute-force-threshold": 100,
|
||||
"blocklist-enabled": false,
|
||||
"blocklist-size": 0,
|
||||
"blocklist-url": "http://www.example.com/blocklist",
|
||||
"cache-size-mb": 4,
|
||||
"config-dir": "/home/user/.config/transmission",
|
||||
"default-trackers": "",
|
||||
"dht-enabled": true,
|
||||
"download-dir": "/home/user/Downloads",
|
||||
"download-dir-free-space": 2199023255552,
|
||||
"download-queue-enabled": true,
|
||||
"download-queue-size": 4,
|
||||
"encryption": "preferred",
|
||||
"idle-seeding-limit": 30,
|
||||
"idle-seeding-limit-enabled": false,
|
||||
"incomplete-dir": "/home/user/Downloads",
|
||||
"incomplete-dir-enabled": false,
|
||||
"lpd-enabled": false,
|
||||
"peer-limit-global": 200,
|
||||
"peer-limit-per-torrent": 50,
|
||||
"peer-port": 51413,
|
||||
"peer-port-random-on-start": false,
|
||||
"pex-enabled": true,
|
||||
"port-forwarding-enabled": true,
|
||||
"preferred_transports": [
|
||||
"utp",
|
||||
"tcp"
|
||||
],
|
||||
"queue-stalled-enabled": true,
|
||||
"queue-stalled-minutes": 30,
|
||||
"rename-partial-files": true,
|
||||
"reqq": 2000,
|
||||
"rpc-version": 18,
|
||||
"rpc-version-minimum": 14,
|
||||
"rpc-version-semver": "6.0.0",
|
||||
"script-torrent-added-enabled": false,
|
||||
"script-torrent-added-filename": "",
|
||||
"script-torrent-done-enabled": false,
|
||||
"script-torrent-done-filename": "/home/user/scripts/script.sh",
|
||||
"script-torrent-done-seeding-enabled": false,
|
||||
"script-torrent-done-seeding-filename": "",
|
||||
"seed-queue-enabled": false,
|
||||
"seed-queue-size": 10,
|
||||
"seedRatioLimit": 2.0,
|
||||
"seedRatioLimited": false,
|
||||
"sequential_download": false,
|
||||
"session-id": "pdvuklydohaohwwluzpmpmllkaopzzlzzpvupkpuavhjhlzhyjfwoly",
|
||||
"speed-limit-down": 100.0,
|
||||
"speed-limit-down-enabled": false,
|
||||
"speed-limit-up": 100.0,
|
||||
"speed-limit-up-enabled": false,
|
||||
"start-added-torrents": true,
|
||||
"tcp-enabled": true,
|
||||
"trash-original-torrent-files": false,
|
||||
"units": {
|
||||
"memory-bytes": 1024,
|
||||
"memory-units": [
|
||||
"B",
|
||||
"KiB",
|
||||
"MiB",
|
||||
"GiB",
|
||||
"TiB"
|
||||
],
|
||||
"size-bytes": 1000,
|
||||
"size-units": [
|
||||
"B",
|
||||
"kB",
|
||||
"MB",
|
||||
"GB",
|
||||
"TB"
|
||||
],
|
||||
"speed-bytes": 1000,
|
||||
"speed-units": [
|
||||
"B/s",
|
||||
"kB/s",
|
||||
"MB/s",
|
||||
"GB/s",
|
||||
"TB/s"
|
||||
]
|
||||
},
|
||||
"utp-enabled": true,
|
||||
"version": "4.1.0-beta.4 (b11bfd9712)"
|
||||
},
|
||||
"result": "success",
|
||||
"tag": 40
|
||||
})json";
|
||||
|
||||
constexpr std::string_view CurrentSessionGetResponseJson = R"json({
|
||||
"id": 40,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"alt_speed_down": 50,
|
||||
"alt_speed_enabled": false,
|
||||
"alt_speed_time_begin": 540,
|
||||
"alt_speed_time_day": 127,
|
||||
"alt_speed_time_enabled": false,
|
||||
"alt_speed_time_end": 1020,
|
||||
"alt_speed_up": 50,
|
||||
"anti_brute_force_enabled": false,
|
||||
"anti_brute_force_threshold": 100,
|
||||
"blocklist_enabled": false,
|
||||
"blocklist_size": 0,
|
||||
"blocklist_url": "http://www.example.com/blocklist",
|
||||
"cache_size_mb": 4,
|
||||
"config_dir": "/home/user/.config/transmission",
|
||||
"default_trackers": "",
|
||||
"dht_enabled": true,
|
||||
"download_dir": "/home/user/Downloads",
|
||||
"download_dir_free_space": 2199023255552,
|
||||
"download_queue_enabled": true,
|
||||
"download_queue_size": 4,
|
||||
"encryption": "preferred",
|
||||
"idle_seeding_limit": 30,
|
||||
"idle_seeding_limit_enabled": false,
|
||||
"incomplete_dir": "/home/user/Downloads",
|
||||
"incomplete_dir_enabled": false,
|
||||
"lpd_enabled": false,
|
||||
"peer_limit_global": 200,
|
||||
"peer_limit_per_torrent": 50,
|
||||
"peer_port": 51413,
|
||||
"peer_port_random_on_start": false,
|
||||
"pex_enabled": true,
|
||||
"port_forwarding_enabled": true,
|
||||
"preferred_transports": [
|
||||
"utp",
|
||||
"tcp"
|
||||
],
|
||||
"queue_stalled_enabled": true,
|
||||
"queue_stalled_minutes": 30,
|
||||
"rename_partial_files": true,
|
||||
"reqq": 2000,
|
||||
"rpc_version": 18,
|
||||
"rpc_version_minimum": 14,
|
||||
"rpc_version_semver": "6.0.0",
|
||||
"script_torrent_added_enabled": false,
|
||||
"script_torrent_added_filename": "",
|
||||
"script_torrent_done_enabled": false,
|
||||
"script_torrent_done_filename": "/home/user/scripts/script.sh",
|
||||
"script_torrent_done_seeding_enabled": false,
|
||||
"script_torrent_done_seeding_filename": "",
|
||||
"seed_queue_enabled": false,
|
||||
"seed_queue_size": 10,
|
||||
"seed_ratio_limit": 2.0,
|
||||
"seed_ratio_limited": false,
|
||||
"sequential_download": false,
|
||||
"session_id": "pdvuklydohaohwwluzpmpmllkaopzzlzzpvupkpuavhjhlzhyjfwoly",
|
||||
"speed_limit_down": 100.0,
|
||||
"speed_limit_down_enabled": false,
|
||||
"speed_limit_up": 100.0,
|
||||
"speed_limit_up_enabled": false,
|
||||
"start_added_torrents": true,
|
||||
"tcp_enabled": true,
|
||||
"trash_original_torrent_files": false,
|
||||
"units": {
|
||||
"memory_bytes": 1024,
|
||||
"memory_units": [
|
||||
"B",
|
||||
"KiB",
|
||||
"MiB",
|
||||
"GiB",
|
||||
"TiB"
|
||||
],
|
||||
"size_bytes": 1000,
|
||||
"size_units": [
|
||||
"B",
|
||||
"kB",
|
||||
"MB",
|
||||
"GB",
|
||||
"TB"
|
||||
],
|
||||
"speed_bytes": 1000,
|
||||
"speed_units": [
|
||||
"B/s",
|
||||
"kB/s",
|
||||
"MB/s",
|
||||
"GB/s",
|
||||
"TB/s"
|
||||
]
|
||||
},
|
||||
"utp_enabled": true,
|
||||
"version": "4.1.0-beta.4 (b11bfd9712)"
|
||||
}
|
||||
})json";
|
||||
|
||||
constexpr std::string_view LegacyTorrentGetJson = R"json({
|
||||
"arguments": {
|
||||
"fields": [
|
||||
"downloadDir",
|
||||
"downloadedEver",
|
||||
"editDate",
|
||||
"error",
|
||||
"errorString",
|
||||
"eta",
|
||||
"haveUnchecked",
|
||||
"haveValid",
|
||||
"id",
|
||||
"isFinished",
|
||||
"leftUntilDone",
|
||||
"manualAnnounceTime",
|
||||
"metadataPercentComplete",
|
||||
"name",
|
||||
"peersConnected",
|
||||
"peersGettingFromUs",
|
||||
"peersSendingToUs",
|
||||
"percentDone",
|
||||
"queuePosition",
|
||||
"rateDownload",
|
||||
"rateUpload",
|
||||
"recheckProgress",
|
||||
"seedRatioLimit",
|
||||
"seedRatioMode",
|
||||
"sizeWhenDone",
|
||||
"status",
|
||||
"uploadRatio",
|
||||
"uploadedEver",
|
||||
"webseedsSendingToUs"
|
||||
],
|
||||
"ids": "recently-active"
|
||||
},
|
||||
"method": "torrent-get",
|
||||
"tag": 6
|
||||
})json";
|
||||
|
||||
constexpr std::string_view CurrentTorrentGetJson = R"json({
|
||||
"id": 6,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "torrent_get",
|
||||
"params": {
|
||||
"fields": [
|
||||
"download_dir",
|
||||
"downloaded_ever",
|
||||
"edit_date",
|
||||
"error",
|
||||
"error_string",
|
||||
"eta",
|
||||
"have_unchecked",
|
||||
"have_valid",
|
||||
"id",
|
||||
"is_finished",
|
||||
"left_until_done",
|
||||
"manual_announce_time",
|
||||
"metadata_percent_complete",
|
||||
"name",
|
||||
"peers_connected",
|
||||
"peers_getting_from_us",
|
||||
"peers_sending_to_us",
|
||||
"percent_done",
|
||||
"queue_position",
|
||||
"rate_download",
|
||||
"rate_upload",
|
||||
"recheck_progress",
|
||||
"seed_ratio_limit",
|
||||
"seed_ratio_mode",
|
||||
"size_when_done",
|
||||
"status",
|
||||
"upload_ratio",
|
||||
"uploaded_ever",
|
||||
"webseeds_sending_to_us"
|
||||
],
|
||||
"ids": "recently_active"
|
||||
}
|
||||
})json";
|
||||
|
||||
constexpr std::string_view CurrentPortTestErrorResponse = R"json({
|
||||
"error": {
|
||||
"code": 8,
|
||||
"data": {
|
||||
"error_string": "Couldn't test port: No Response (0)",
|
||||
"result": {
|
||||
"ip_protocol": "ipv6"
|
||||
}
|
||||
},
|
||||
"message": "HTTP error from backend service"
|
||||
},
|
||||
"id": 9,
|
||||
"jsonrpc": "2.0"
|
||||
})json";
|
||||
|
||||
constexpr std::string_view LegacyPortTestErrorResponse = R"json({
|
||||
"arguments": {
|
||||
"ip_protocol": "ipv6"
|
||||
},
|
||||
"result": "Couldn't test port: No Response (0)",
|
||||
"tag": 9
|
||||
})json";
|
||||
|
||||
constexpr std::string_view LegacyStatsJson = R"json({
|
||||
"downloaded-bytes": 12,
|
||||
"files-added": 34,
|
||||
"seconds-active": 56,
|
||||
"session-count": 78,
|
||||
"uploaded-bytes": 90
|
||||
})json";
|
||||
|
||||
constexpr std::string_view CurrentStatsJson = R"json({
|
||||
"downloaded_bytes": 12,
|
||||
"files_added": 34,
|
||||
"seconds_active": 56,
|
||||
"session_count": 78,
|
||||
"uploaded_bytes": 90
|
||||
})json";
|
||||
|
||||
constexpr std::string_view LegacySettingsJson = R"json({
|
||||
"alt-speed-down": 50,
|
||||
"alt-speed-enabled": false,
|
||||
"alt-speed-time-begin": 540,
|
||||
"alt-speed-time-day": 127,
|
||||
"alt-speed-time-enabled": false,
|
||||
"alt-speed-time-end": 1020,
|
||||
"alt-speed-up": 50,
|
||||
"blocklist-date": 0,
|
||||
"blocklist-enabled": false,
|
||||
"blocklist-updates-enabled": true,
|
||||
"blocklist-url": "http://www.example.com/blocklist",
|
||||
"compact-view": false,
|
||||
"default-trackers": "",
|
||||
"dht-enabled": true,
|
||||
"download-dir": "/home/user/Downloads",
|
||||
"download-queue-enabled": true,
|
||||
"download-queue-size": 5,
|
||||
"encryption": 1,
|
||||
"filter-mode": "show-all",
|
||||
"filter-trackers": "",
|
||||
"idle-seeding-limit": 30,
|
||||
"idle-seeding-limit-enabled": false,
|
||||
"incomplete-dir": "/home/user/Downloads",
|
||||
"incomplete-dir-enabled": false,
|
||||
"inhibit-desktop-hibernation": false,
|
||||
"lpd-enabled": true,
|
||||
"main-window-height": 500,
|
||||
"main-window-layout-order": "menu,toolbar,filter,list,statusbar",
|
||||
"main-window-width": 650,
|
||||
"main-window-x": 3840,
|
||||
"main-window-y": 0,
|
||||
"message-level": 4,
|
||||
"open-dialog-dir": "/home/user",
|
||||
"peer-limit-global": 200,
|
||||
"peer-limit-per-torrent": 50,
|
||||
"peer-port": 51413,
|
||||
"peer-port-random-high": 65535,
|
||||
"peer-port-random-low": 49152,
|
||||
"peer-port-random-on-start": false,
|
||||
"peer-socket-tos": "le",
|
||||
"pex-enabled": true,
|
||||
"port-forwarding-enabled": true,
|
||||
"preallocation": 1,
|
||||
"prompt-before-exit": true,
|
||||
"queue-stalled-minutes": 30,
|
||||
"ratio-limit": 2.0,
|
||||
"ratio-limit-enabled": false,
|
||||
"read-clipboard": false,
|
||||
"remote-session-enabled": false,
|
||||
"remote-session-host": "localhost",
|
||||
"remote-session-https": false,
|
||||
"remote-session-password": "",
|
||||
"remote-session-port": 9091,
|
||||
"remote-session-requres-authentication": false,
|
||||
"remote-session-username": "",
|
||||
"rename-partial-files": true,
|
||||
"rpc-authentication-required": false,
|
||||
"rpc-enabled": false,
|
||||
"rpc-password": "",
|
||||
"rpc-port": 9091,
|
||||
"rpc-username": "",
|
||||
"rpc-whitelist": "127.0.0.1,::1",
|
||||
"rpc-whitelist-enabled": true,
|
||||
"script-torrent-done-enabled": false,
|
||||
"script-torrent-done-filename": "",
|
||||
"script-torrent-done-seeding-enabled": false,
|
||||
"script-torrent-done-seeding-filename": "",
|
||||
"show-backup-trackers": false,
|
||||
"show-filterbar": true,
|
||||
"show-notification-area-icon": false,
|
||||
"show-options-window": true,
|
||||
"show-statusbar": true,
|
||||
"show-toolbar": true,
|
||||
"show-tracker-scrapes": false,
|
||||
"sleep-per-seconds-during-verify": 100,
|
||||
"sort-mode": "sort-by-name",
|
||||
"sort-reversed": false,
|
||||
"speed-limit-down": 100,
|
||||
"speed-limit-down-enabled": false,
|
||||
"speed-limit-up": 100,
|
||||
"speed-limit-up-enabled": false,
|
||||
"start-added-torrents": true,
|
||||
"start-minimized": false,
|
||||
"statusbar-stats": "total-ratio",
|
||||
"torrent-added-notification-enabled": true,
|
||||
"torrent-complete-notification-enabled": true,
|
||||
"torrent-complete-sound-command": [
|
||||
"canberra-gtk-play",
|
||||
"-i",
|
||||
"complete-download",
|
||||
"-d",
|
||||
"transmission torrent downloaded"
|
||||
],
|
||||
"torrent-complete-sound-enabled": true,
|
||||
"trash-original-torrent-files": false,
|
||||
"upload-slots-per-torrent": 8,
|
||||
"utp-enabled": true,
|
||||
"watch-dir": "/home/user/Downloads",
|
||||
"watch-dir-enabled": false
|
||||
})json";
|
||||
|
||||
constexpr std::string_view CurrentSettingsJson = R"json({
|
||||
"alt_speed_down": 50,
|
||||
"alt_speed_enabled": false,
|
||||
"alt_speed_time_begin": 540,
|
||||
"alt_speed_time_day": 127,
|
||||
"alt_speed_time_enabled": false,
|
||||
"alt_speed_time_end": 1020,
|
||||
"alt_speed_up": 50,
|
||||
"blocklist_date": 0,
|
||||
"blocklist_enabled": false,
|
||||
"blocklist_updates_enabled": true,
|
||||
"blocklist_url": "http://www.example.com/blocklist",
|
||||
"compact_view": false,
|
||||
"default_trackers": "",
|
||||
"dht_enabled": true,
|
||||
"download_dir": "/home/user/Downloads",
|
||||
"download_queue_enabled": true,
|
||||
"download_queue_size": 5,
|
||||
"encryption": 1,
|
||||
"filter_mode": "show-all",
|
||||
"filter_trackers": "",
|
||||
"idle_seeding_limit": 30,
|
||||
"idle_seeding_limit_enabled": false,
|
||||
"incomplete_dir": "/home/user/Downloads",
|
||||
"incomplete_dir_enabled": false,
|
||||
"inhibit_desktop_hibernation": false,
|
||||
"lpd_enabled": true,
|
||||
"main_window_height": 500,
|
||||
"main_window_layout_order": "menu,toolbar,filter,list,statusbar",
|
||||
"main_window_width": 650,
|
||||
"main_window_x": 3840,
|
||||
"main_window_y": 0,
|
||||
"message_level": 4,
|
||||
"open_dialog_dir": "/home/user",
|
||||
"peer_limit_global": 200,
|
||||
"peer_limit_per_torrent": 50,
|
||||
"peer_port": 51413,
|
||||
"peer_port_random_high": 65535,
|
||||
"peer_port_random_low": 49152,
|
||||
"peer_port_random_on_start": false,
|
||||
"peer_socket_tos": "le",
|
||||
"pex_enabled": true,
|
||||
"port_forwarding_enabled": true,
|
||||
"preallocation": 1,
|
||||
"prompt_before_exit": true,
|
||||
"queue_stalled_minutes": 30,
|
||||
"ratio_limit": 2.0,
|
||||
"ratio_limit_enabled": false,
|
||||
"read_clipboard": false,
|
||||
"remote_session_enabled": false,
|
||||
"remote_session_host": "localhost",
|
||||
"remote_session_https": false,
|
||||
"remote_session_password": "",
|
||||
"remote_session_port": 9091,
|
||||
"remote_session_requires_authentication": false,
|
||||
"remote_session_username": "",
|
||||
"rename_partial_files": true,
|
||||
"rpc_authentication_required": false,
|
||||
"rpc_enabled": false,
|
||||
"rpc_password": "",
|
||||
"rpc_port": 9091,
|
||||
"rpc_username": "",
|
||||
"rpc_whitelist": "127.0.0.1,::1",
|
||||
"rpc_whitelist_enabled": true,
|
||||
"script_torrent_done_enabled": false,
|
||||
"script_torrent_done_filename": "",
|
||||
"script_torrent_done_seeding_enabled": false,
|
||||
"script_torrent_done_seeding_filename": "",
|
||||
"show_backup_trackers": false,
|
||||
"show_filterbar": true,
|
||||
"show_notification_area_icon": false,
|
||||
"show_options_window": true,
|
||||
"show_statusbar": true,
|
||||
"show_toolbar": true,
|
||||
"show_tracker_scrapes": false,
|
||||
"sleep_per_seconds_during_verify": 100,
|
||||
"sort_mode": "sort-by-name",
|
||||
"sort_reversed": false,
|
||||
"speed_limit_down": 100,
|
||||
"speed_limit_down_enabled": false,
|
||||
"speed_limit_up": 100,
|
||||
"speed_limit_up_enabled": false,
|
||||
"start_added_torrents": true,
|
||||
"start_minimized": false,
|
||||
"statusbar_stats": "total-ratio",
|
||||
"torrent_added_notification_enabled": true,
|
||||
"torrent_complete_notification_enabled": true,
|
||||
"torrent_complete_sound_command": [
|
||||
"canberra-gtk-play",
|
||||
"-i",
|
||||
"complete-download",
|
||||
"-d",
|
||||
"transmission torrent downloaded"
|
||||
],
|
||||
"torrent_complete_sound_enabled": true,
|
||||
"trash_original_torrent_files": false,
|
||||
"upload_slots_per_torrent": 8,
|
||||
"utp_enabled": true,
|
||||
"watch_dir": "/home/user/Downloads",
|
||||
"watch_dir_enabled": false
|
||||
})json";
|
||||
|
||||
constexpr std::string_view BadFreeSpaceRequest = R"json({
|
||||
"id": 39693,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "free_space",
|
||||
"params": {
|
||||
"path": "this/path/is/not/absolute"
|
||||
}
|
||||
})json";
|
||||
|
||||
constexpr std::string_view BadFreeSpaceRequestLegacy = R"json({
|
||||
"arguments": {
|
||||
"path": "this/path/is/not/absolute"
|
||||
},
|
||||
"method": "free-space",
|
||||
"tag": 39693
|
||||
})json";
|
||||
|
||||
constexpr std::string_view BadFreeSpaceResponse = R"json({
|
||||
"error": {
|
||||
"code": 3,
|
||||
"data": {
|
||||
"error_string": "directory path is not absolute"
|
||||
},
|
||||
"message": "path is not absolute"
|
||||
},
|
||||
"id": 39693,
|
||||
"jsonrpc": "2.0"
|
||||
})json";
|
||||
|
||||
constexpr std::string_view BadFreeSpaceResponseLegacy = R"json({
|
||||
"arguments": {},
|
||||
"result": "directory path is not absolute",
|
||||
"tag": 39693
|
||||
})json";
|
||||
|
||||
constexpr std::string_view WellFormedFreeSpaceRequest = R"json({
|
||||
"id": 41414,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "free_space",
|
||||
"params": {
|
||||
"path": "/this/path/does/not/exist"
|
||||
}
|
||||
})json";
|
||||
|
||||
constexpr std::string_view WellFormedFreeSpaceResponse = R"json({
|
||||
"id": 41414,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"path": "/this/path/does/not/exist",
|
||||
"size_bytes": -1,
|
||||
"total_size": -1
|
||||
}
|
||||
})json";
|
||||
|
||||
constexpr std::string_view WellFormedFreeSpaceLegacyRequest = R"json({
|
||||
"arguments": {
|
||||
"path": "/this/path/does/not/exist"
|
||||
},
|
||||
"method": "free-space",
|
||||
"tag": 41414
|
||||
})json";
|
||||
|
||||
constexpr std::string_view WellFormedFreeSpaceLegacyResponse = R"json({
|
||||
"arguments": {
|
||||
"path": "/this/path/does/not/exist",
|
||||
"size-bytes": -1,
|
||||
"total_size": -1
|
||||
},
|
||||
"result": "success",
|
||||
"tag": 41414
|
||||
})json";
|
||||
|
||||
constexpr std::string_view BadMethodNameResponse = R"json({
|
||||
"error": {
|
||||
"code": -32601,
|
||||
"message": "Method not found"
|
||||
},
|
||||
"id": 39693,
|
||||
"jsonrpc": "2.0"
|
||||
})json";
|
||||
|
||||
constexpr std::string_view BadMethodNameLegacyResponse = R"json({
|
||||
"arguments": {},
|
||||
"result": "no method name",
|
||||
"tag": 39693
|
||||
})json";
|
||||
|
||||
constexpr std::string_view UnrecognisedInfoResponse = R"json({
|
||||
"error": {
|
||||
"code": 4,
|
||||
"message": "unrecognized info"
|
||||
},
|
||||
"id": 10,
|
||||
"jsonrpc": "2.0"
|
||||
})json";
|
||||
|
||||
constexpr std::string_view UnrecognisedInfoLegacyResponse = R"json({
|
||||
"arguments": {},
|
||||
"result": "unrecognized info",
|
||||
"tag": 10
|
||||
})json";
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ApiCompatTest, canConvertRpc)
|
||||
{
|
||||
using Style = libtransmission::api_compat::Style;
|
||||
using TestCase = std::tuple<std::string_view, std::string_view, Style, std::string_view>;
|
||||
|
||||
// clang-format off
|
||||
static auto constexpr TestCases = std::array<TestCase, 40U>{ {
|
||||
{ "free_space tr5 -> tr5", BadFreeSpaceRequest, Style::Tr5, BadFreeSpaceRequest },
|
||||
{ "free_space tr5 -> tr4", BadFreeSpaceRequest, Style::Tr4, BadFreeSpaceRequestLegacy },
|
||||
{ "free_space tr4 -> tr5", BadFreeSpaceRequestLegacy, Style::Tr5, BadFreeSpaceRequest },
|
||||
{ "free_space tr4 -> tr4", BadFreeSpaceRequestLegacy, Style::Tr4, BadFreeSpaceRequestLegacy },
|
||||
{ "free_space error response tr5 -> tr5", BadFreeSpaceResponse, Style::Tr5, BadFreeSpaceResponse },
|
||||
{ "free_space error response tr5 -> tr4", BadFreeSpaceResponse, Style::Tr4, BadFreeSpaceResponseLegacy },
|
||||
{ "free_space error response tr4 -> tr5", BadFreeSpaceResponseLegacy, Style::Tr5, BadFreeSpaceResponse },
|
||||
{ "free_space error response tr4 -> tr4", BadFreeSpaceResponseLegacy, Style::Tr4, BadFreeSpaceResponseLegacy },
|
||||
{ "free_space req tr5 -> tr5", WellFormedFreeSpaceRequest, Style::Tr5, WellFormedFreeSpaceRequest },
|
||||
{ "free_space req tr5 -> tr4", WellFormedFreeSpaceRequest, Style::Tr4, WellFormedFreeSpaceLegacyRequest },
|
||||
{ "free_space req tr4 -> tr5", WellFormedFreeSpaceLegacyRequest, Style::Tr5, WellFormedFreeSpaceRequest },
|
||||
{ "free_space req tr4 -> tr4", WellFormedFreeSpaceLegacyRequest, Style::Tr4, WellFormedFreeSpaceLegacyRequest },
|
||||
{ "free_space response tr5 -> tr5", WellFormedFreeSpaceResponse, Style::Tr5, WellFormedFreeSpaceResponse },
|
||||
{ "free_space response tr5 -> tr4", WellFormedFreeSpaceResponse, Style::Tr4, WellFormedFreeSpaceLegacyResponse },
|
||||
{ "free_space response tr4 -> tr5", WellFormedFreeSpaceLegacyResponse, Style::Tr5, WellFormedFreeSpaceResponse },
|
||||
{ "free_space response tr4 -> tr4", WellFormedFreeSpaceLegacyResponse, Style::Tr4, WellFormedFreeSpaceLegacyResponse },
|
||||
{ "session_get tr5 -> tr5", CurrentSessionGetJson, Style::Tr5, CurrentSessionGetJson },
|
||||
{ "session_get tr5 -> tr4", CurrentSessionGetJson, Style::Tr4, LegacySessionGetJson },
|
||||
{ "session_get tr4 -> tr5", LegacySessionGetJson, Style::Tr5, CurrentSessionGetJson },
|
||||
{ "session_get tr4 -> tr4", LegacySessionGetJson, Style::Tr4, LegacySessionGetJson },
|
||||
{ "session_get response tr5 -> tr5", CurrentSessionGetResponseJson, Style::Tr5, CurrentSessionGetResponseJson },
|
||||
{ "session_get response tr5 -> tr4", CurrentSessionGetResponseJson, Style::Tr4, LegacySessionGetResponseJson },
|
||||
{ "session_get response tr4 -> tr5", LegacySessionGetResponseJson, Style::Tr5, CurrentSessionGetResponseJson },
|
||||
{ "session_get response tr4 -> tr4", LegacySessionGetResponseJson, Style::Tr4, LegacySessionGetResponseJson },
|
||||
{ "torrent_get tr5 -> tr5", CurrentTorrentGetJson, Style::Tr5, CurrentTorrentGetJson },
|
||||
{ "torrent_get tr5 -> tr4", CurrentTorrentGetJson, Style::Tr4, LegacyTorrentGetJson },
|
||||
{ "torrent_get tr4 -> tr5", LegacyTorrentGetJson, Style::Tr5, CurrentTorrentGetJson },
|
||||
{ "torrent_get tr4 -> tr4", LegacyTorrentGetJson, Style::Tr4, LegacyTorrentGetJson },
|
||||
{ "port_test error response tr5 -> tr5", CurrentPortTestErrorResponse, Style::Tr5, CurrentPortTestErrorResponse },
|
||||
{ "port_test error response tr5 -> tr4", CurrentPortTestErrorResponse, Style::Tr4, LegacyPortTestErrorResponse },
|
||||
{ "port_test error response tr4 -> tr5", LegacyPortTestErrorResponse, Style::Tr5, CurrentPortTestErrorResponse },
|
||||
{ "port_test error response tr4 -> tr4", LegacyPortTestErrorResponse, Style::Tr4, LegacyPortTestErrorResponse },
|
||||
{ "bad method name tr5 -> tr5", BadMethodNameResponse, Style::Tr5, BadMethodNameResponse },
|
||||
{ "bad method name tr5 -> tr4", BadMethodNameResponse, Style::Tr4, BadMethodNameLegacyResponse },
|
||||
{ "bad method name tr4 -> tr5", BadMethodNameLegacyResponse, Style::Tr5, BadMethodNameResponse },
|
||||
{ "bad method name tr4 -> tr4", BadMethodNameLegacyResponse, Style::Tr4, BadMethodNameLegacyResponse },
|
||||
{ "unrecognised info tr5 -> tr5", UnrecognisedInfoResponse, Style::Tr5, UnrecognisedInfoResponse},
|
||||
{ "unrecognised info tr5 -> tr4", UnrecognisedInfoResponse, Style::Tr4, UnrecognisedInfoLegacyResponse},
|
||||
{ "unrecognised info tr4 -> tr5", UnrecognisedInfoLegacyResponse, Style::Tr5, UnrecognisedInfoResponse},
|
||||
{ "unrecognised info tr4 -> tr4", UnrecognisedInfoLegacyResponse, Style::Tr4, UnrecognisedInfoLegacyResponse},
|
||||
|
||||
// TODO(ckerr): torrent-get with 'table'
|
||||
} };
|
||||
// clang-format on
|
||||
|
||||
for (auto const& [name, src, tgt_style, expected] : TestCases)
|
||||
{
|
||||
auto serde = tr_variant_serde::json();
|
||||
auto parsed = serde.parse(src);
|
||||
ASSERT_TRUE(parsed.has_value()) << name << ": " << serde.error_;
|
||||
auto converted = libtransmission::api_compat::convert(*parsed, tgt_style);
|
||||
EXPECT_EQ(expected, serde.to_string(converted)) << name;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ApiCompatTest, canConvertDataFiles)
|
||||
{
|
||||
using Style = libtransmission::api_compat::Style;
|
||||
using TestCase = std::tuple<std::string_view, std::string_view, Style, std::string_view>;
|
||||
|
||||
// clang-format off
|
||||
static auto constexpr TestCases = std::array<TestCase, 8U>{ {
|
||||
{ "settings tr5 -> tr5", CurrentSettingsJson, Style::Tr5, CurrentSettingsJson },
|
||||
{ "settings tr5 -> tr4", CurrentSettingsJson, Style::Tr4, LegacySettingsJson },
|
||||
{ "settings tr4 -> tr5", LegacySettingsJson, Style::Tr5, CurrentSettingsJson },
|
||||
{ "settings tr4 -> tr4", LegacySettingsJson, Style::Tr4, LegacySettingsJson },
|
||||
|
||||
{ "stats tr5 -> tr5", CurrentStatsJson, Style::Tr5, CurrentStatsJson },
|
||||
{ "stats tr5 -> tr4", CurrentStatsJson, Style::Tr4, LegacyStatsJson },
|
||||
{ "stats tr4 -> tr5", LegacyStatsJson, Style::Tr5, CurrentStatsJson },
|
||||
{ "stats tr4 -> tr4", LegacyStatsJson, Style::Tr4, LegacyStatsJson },
|
||||
} };
|
||||
// clang-format on
|
||||
|
||||
for (auto const& [name, src, tgt_style, expected] : TestCases)
|
||||
{
|
||||
auto serde = tr_variant_serde::json();
|
||||
auto parsed = serde.parse(src);
|
||||
ASSERT_TRUE(parsed.has_value());
|
||||
auto converted = libtransmission::api_compat::convert(*parsed, tgt_style);
|
||||
EXPECT_EQ(expected, serde.to_string(converted)) << name;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user