feat: use api_compat for stats.json (#7918)

* feat: use api_compat for stats.json

* chore: flag old stats.json keys as api_compat-only
This commit is contained in:
Charles Kerr
2025-12-14 19:44:20 -06:00
committed by GitHub
parent 887473cade
commit d7f022599c
3 changed files with 53 additions and 29 deletions

View File

@@ -276,9 +276,9 @@ auto constexpr SessionKeys = std::array<ApiKey, 139U>{ {
{ TR_KEY_download_dir, TR_KEY_download_dir_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_enabled, TR_KEY_download_queue_enabled_kebab },
{ TR_KEY_download_queue_size, TR_KEY_download_queue_size_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_downloaded_bytes, TR_KEY_downloaded_bytes_kebab_APICOMPAT },
{ TR_KEY_downloading_time_seconds, TR_KEY_downloading_time_seconds_kebab }, { 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_files_added, TR_KEY_files_added_kebab_APICOMPAT },
{ TR_KEY_filter_mode, TR_KEY_filter_mode_kebab }, { TR_KEY_filter_mode, TR_KEY_filter_mode_kebab },
{ TR_KEY_filter_text, TR_KEY_filter_text_kebab }, { TR_KEY_filter_text, TR_KEY_filter_text_kebab },
{ TR_KEY_filter_trackers, TR_KEY_filter_trackers_kebab }, { TR_KEY_filter_trackers, TR_KEY_filter_trackers_kebab },
@@ -344,11 +344,11 @@ auto constexpr SessionKeys = std::array<ApiKey, 139U>{ {
{ TR_KEY_script_torrent_done_filename, TR_KEY_script_torrent_done_filename_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_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_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_seconds_active, TR_KEY_seconds_active_kebab_APICOMPAT },
{ TR_KEY_seed_queue_enabled, TR_KEY_seed_queue_enabled_kebab }, { 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_queue_size, TR_KEY_seed_queue_size_kebab },
{ TR_KEY_seeding_time_seconds, TR_KEY_seeding_time_seconds_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_session_count, TR_KEY_session_count_kebab_APICOMPAT },
{ TR_KEY_show_backup_trackers, TR_KEY_show_backup_trackers_kebab }, { 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_extra_peer_details, TR_KEY_show_extra_peer_details_kebab },
{ TR_KEY_show_filterbar, TR_KEY_show_filterbar_kebab }, { TR_KEY_show_filterbar, TR_KEY_show_filterbar_kebab },
@@ -378,7 +378,7 @@ auto constexpr SessionKeys = std::array<ApiKey, 139U>{ {
{ TR_KEY_trash_can_enabled, TR_KEY_trash_can_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_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_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_uploaded_bytes, TR_KEY_uploaded_bytes_kebab_APICOMPAT },
{ TR_KEY_use_global_speed_limit, TR_KEY_use_global_speed_limit_kebab }, { 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_use_speed_limit, TR_KEY_use_speed_limit_kebab },
{ TR_KEY_utp_enabled, TR_KEY_utp_enabled_kebab }, { TR_KEY_utp_enabled, TR_KEY_utp_enabled_kebab },

View File

@@ -9,11 +9,26 @@
#include <optional> #include <optional>
#include <string_view> #include <string_view>
/* Quarks — a 2-way association between a string and a unique integer identifier */ /**
* Quarks — a 2-way association between a compile-time interned string
* and a unique integer identifier. Used to make well-known strings
* (e.g. strings in settings files, the JSON-RPC API, and BitTorrent protocol)
* cheap to store, cheap to compare, and usable in switch-case statements.
*/
using tr_quark = size_t; using tr_quark = size_t;
/* /**
* Predefined Quarks. * Predefined Quarks.
*
* IMPORTANT:
*
* * Use snake case for new entries.
*
* * Entries whose names contain `_camel`, `_kebab`, or `_APICOMPAT` are
* all deprecated. Do not use them in new code except in api_compat.
* - `_camel` means the entry's string is in camelCase.
* - `_kebab` means the entry's string is in kebab-case.
* - `_APICOMPAT` means the entry is only used in api_compat.
*/ */
enum // NOLINT(performance-enum-size) enum // NOLINT(performance-enum-size)
{ {
@@ -149,7 +164,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_download_queue_size, TR_KEY_download_queue_size,
TR_KEY_download_speed, TR_KEY_download_speed,
TR_KEY_downloaded, TR_KEY_downloaded,
TR_KEY_downloaded_bytes_kebab, TR_KEY_downloaded_bytes_kebab_APICOMPAT,
TR_KEY_downloaded_bytes_camel, TR_KEY_downloaded_bytes_camel,
TR_KEY_downloaded_ever_camel, TR_KEY_downloaded_ever_camel,
TR_KEY_downloaded_bytes, TR_KEY_downloaded_bytes,
@@ -178,7 +193,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_file_stats, TR_KEY_file_stats,
TR_KEY_filename, TR_KEY_filename,
TR_KEY_files, TR_KEY_files,
TR_KEY_files_added_kebab, TR_KEY_files_added_kebab_APICOMPAT,
TR_KEY_files_unwanted_kebab, TR_KEY_files_unwanted_kebab,
TR_KEY_files_wanted_kebab, TR_KEY_files_wanted_kebab,
TR_KEY_files_added_camel, TR_KEY_files_added_camel,
@@ -526,7 +541,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_script_torrent_done_filename, TR_KEY_script_torrent_done_filename,
TR_KEY_script_torrent_done_seeding_enabled, TR_KEY_script_torrent_done_seeding_enabled,
TR_KEY_script_torrent_done_seeding_filename, TR_KEY_script_torrent_done_seeding_filename,
TR_KEY_seconds_active_kebab, TR_KEY_seconds_active_kebab_APICOMPAT,
TR_KEY_seconds_active_camel, TR_KEY_seconds_active_camel,
TR_KEY_seconds_downloading_camel, TR_KEY_seconds_downloading_camel,
TR_KEY_seconds_seeding_camel, TR_KEY_seconds_seeding_camel,
@@ -554,7 +569,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_sequential_download, TR_KEY_sequential_download,
TR_KEY_sequential_download_from_piece, TR_KEY_sequential_download_from_piece,
TR_KEY_session_close_kebab, TR_KEY_session_close_kebab,
TR_KEY_session_count_kebab, TR_KEY_session_count_kebab_APICOMPAT,
TR_KEY_session_get_kebab, TR_KEY_session_get_kebab,
TR_KEY_session_id_kebab, TR_KEY_session_id_kebab,
TR_KEY_session_set_kebab, TR_KEY_session_set_kebab,
@@ -701,7 +716,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_upload_slots_per_torrent, TR_KEY_upload_slots_per_torrent,
TR_KEY_upload_speed, TR_KEY_upload_speed,
TR_KEY_uploaded, TR_KEY_uploaded,
TR_KEY_uploaded_bytes_kebab, TR_KEY_uploaded_bytes_kebab_APICOMPAT,
TR_KEY_uploaded_bytes_camel, TR_KEY_uploaded_bytes_camel,
TR_KEY_uploaded_ever_camel, TR_KEY_uploaded_ever_camel,
TR_KEY_uploaded_bytes, TR_KEY_uploaded_bytes,

View File

@@ -9,6 +9,7 @@
#include "libtransmission/transmission.h" #include "libtransmission/transmission.h"
#include "libtransmission/api-compat.h"
#include "libtransmission/file.h" #include "libtransmission/file.h"
#include "libtransmission/quark.h" #include "libtransmission/quark.h"
#include "libtransmission/stats.h" #include "libtransmission/stats.h"
@@ -17,24 +18,29 @@
#include "libtransmission/variant.h" #include "libtransmission/variant.h"
using namespace std::literals; using namespace std::literals;
namespace api_compat = libtransmission::api_compat;
namespace namespace
{ {
std::optional<tr_variant> load_stats(std::string_view config_dir) [[nodiscard]] auto load_stats(std::string_view config_dir)
{ {
if (auto filename = tr_pathbuf{ config_dir, "/stats.json"sv }; tr_sys_path_exists(filename)) auto var = std::optional<tr_variant>{};
if (auto file = tr_pathbuf{ config_dir, "/stats.json"sv }; tr_sys_path_exists(file))
{ {
return tr_variant_serde::json().parse_file(filename); var = tr_variant_serde::json().parse_file(file);
}
else if (auto oldfile = tr_pathbuf{ config_dir, "/stats.benc"sv }; tr_sys_path_exists(oldfile))
{
var = tr_variant_serde::benc().parse_file(oldfile);
} }
// maybe the user just upgraded from an old version of Transmission if (var)
// that was still using stats.benc
if (auto filename = tr_pathbuf{ config_dir, "/stats.benc"sv }; tr_sys_path_exists(filename))
{ {
return tr_variant_serde::benc().parse_file(filename); var = api_compat::convert_incoming_data(*var);
} }
return {}; return var;
} }
} // namespace } // namespace
@@ -52,21 +58,21 @@ tr_session_stats tr_stats::load_old_stats(std::string_view config_dir)
return {}; return {};
} }
auto const load = [map](std::initializer_list<tr_quark> keys, uint64_t& dst) auto const load = [map](auto const key, uint64_t& tgt)
{ {
if (auto const val = map->value_if<int64_t>(keys); val) if (auto const val = map->value_if<int64_t>(key))
{ {
dst = *val; tgt = *val;
} }
}; };
auto ret = tr_session_stats{}; auto ret = tr_session_stats{};
load({ TR_KEY_downloaded_bytes, TR_KEY_downloaded_bytes_kebab }, ret.downloadedBytes); load(TR_KEY_downloaded_bytes, ret.downloadedBytes);
load({ TR_KEY_files_added, TR_KEY_files_added_kebab }, ret.filesAdded); load(TR_KEY_files_added, ret.filesAdded);
load({ TR_KEY_seconds_active, TR_KEY_seconds_active_kebab }, ret.secondsActive); load(TR_KEY_seconds_active, ret.secondsActive);
load({ TR_KEY_session_count, TR_KEY_session_count_kebab }, ret.sessionCount); load(TR_KEY_session_count, ret.sessionCount);
load({ TR_KEY_uploaded_bytes, TR_KEY_uploaded_bytes_kebab }, ret.uploadedBytes); load(TR_KEY_uploaded_bytes, ret.uploadedBytes);
return ret; return ret;
} }
@@ -80,7 +86,10 @@ void tr_stats::save() const
map.try_emplace(TR_KEY_seconds_active, saveme.secondsActive); map.try_emplace(TR_KEY_seconds_active, saveme.secondsActive);
map.try_emplace(TR_KEY_session_count, saveme.sessionCount); map.try_emplace(TR_KEY_session_count, saveme.sessionCount);
map.try_emplace(TR_KEY_uploaded_bytes, saveme.uploadedBytes); map.try_emplace(TR_KEY_uploaded_bytes, saveme.uploadedBytes);
tr_variant_serde::json().to_file(tr_variant{ std::move(map) }, tr_pathbuf{ config_dir_, "/stats.json"sv });
auto var = tr_variant{ std::move(map) };
var = api_compat::convert_outgoing_data(var);
tr_variant_serde::json().to_file(var, tr_pathbuf{ config_dir_, "/stats.json"sv });
} }
void tr_stats::clear() void tr_stats::clear()