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_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_downloaded_bytes, TR_KEY_downloaded_bytes_kebab_APICOMPAT },
{ 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_text, TR_KEY_filter_text_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_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_seconds_active, TR_KEY_seconds_active_kebab_APICOMPAT },
{ 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_session_count, TR_KEY_session_count_kebab_APICOMPAT },
{ 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 },
@@ -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_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_uploaded_bytes, TR_KEY_uploaded_bytes_kebab_APICOMPAT },
{ 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 },

View File

@@ -9,11 +9,26 @@
#include <optional>
#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;
/*
/**
* 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)
{
@@ -149,7 +164,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_download_queue_size,
TR_KEY_download_speed,
TR_KEY_downloaded,
TR_KEY_downloaded_bytes_kebab,
TR_KEY_downloaded_bytes_kebab_APICOMPAT,
TR_KEY_downloaded_bytes_camel,
TR_KEY_downloaded_ever_camel,
TR_KEY_downloaded_bytes,
@@ -178,7 +193,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_file_stats,
TR_KEY_filename,
TR_KEY_files,
TR_KEY_files_added_kebab,
TR_KEY_files_added_kebab_APICOMPAT,
TR_KEY_files_unwanted_kebab,
TR_KEY_files_wanted_kebab,
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_seeding_enabled,
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_downloading_camel,
TR_KEY_seconds_seeding_camel,
@@ -554,7 +569,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_sequential_download,
TR_KEY_sequential_download_from_piece,
TR_KEY_session_close_kebab,
TR_KEY_session_count_kebab,
TR_KEY_session_count_kebab_APICOMPAT,
TR_KEY_session_get_kebab,
TR_KEY_session_id_kebab,
TR_KEY_session_set_kebab,
@@ -701,7 +716,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_upload_slots_per_torrent,
TR_KEY_upload_speed,
TR_KEY_uploaded,
TR_KEY_uploaded_bytes_kebab,
TR_KEY_uploaded_bytes_kebab_APICOMPAT,
TR_KEY_uploaded_bytes_camel,
TR_KEY_uploaded_ever_camel,
TR_KEY_uploaded_bytes,

View File

@@ -9,6 +9,7 @@
#include "libtransmission/transmission.h"
#include "libtransmission/api-compat.h"
#include "libtransmission/file.h"
#include "libtransmission/quark.h"
#include "libtransmission/stats.h"
@@ -17,24 +18,29 @@
#include "libtransmission/variant.h"
using namespace std::literals;
namespace api_compat = libtransmission::api_compat;
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
// that was still using stats.benc
if (auto filename = tr_pathbuf{ config_dir, "/stats.benc"sv }; tr_sys_path_exists(filename))
if (var)
{
return tr_variant_serde::benc().parse_file(filename);
var = api_compat::convert_incoming_data(*var);
}
return {};
return var;
}
} // namespace
@@ -52,21 +58,21 @@ tr_session_stats tr_stats::load_old_stats(std::string_view config_dir)
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{};
load({ TR_KEY_downloaded_bytes, TR_KEY_downloaded_bytes_kebab }, ret.downloadedBytes);
load({ TR_KEY_files_added, TR_KEY_files_added_kebab }, ret.filesAdded);
load({ TR_KEY_seconds_active, TR_KEY_seconds_active_kebab }, ret.secondsActive);
load({ TR_KEY_session_count, TR_KEY_session_count_kebab }, ret.sessionCount);
load({ TR_KEY_uploaded_bytes, TR_KEY_uploaded_bytes_kebab }, ret.uploadedBytes);
load(TR_KEY_downloaded_bytes, ret.downloadedBytes);
load(TR_KEY_files_added, ret.filesAdded);
load(TR_KEY_seconds_active, ret.secondsActive);
load(TR_KEY_session_count, ret.sessionCount);
load(TR_KEY_uploaded_bytes, ret.uploadedBytes);
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_session_count, saveme.sessionCount);
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()