From c1c27f3da02434a950d2836ed32c0d4ce0b40dc4 Mon Sep 17 00:00:00 2001 From: Daniel Kamil Kozar Date: Mon, 5 Jun 2023 20:15:32 +0200 Subject: [PATCH] Expose files' begin and end pieces via RPC (#5578) * Expose files' begin and end pieces via RPC This adds two arguments, `beginPiece` and `endPiece`, for each of the entries in the `files` array of the RPC's `torrent-`get` method. The point is to allow RPC clients to display a file's completion progress as piece-based in addition to byte-based. --- docs/rpc-spec.md | 4 ++++ libtransmission/quark.cc | 4 +++- libtransmission/quark.h | 2 ++ libtransmission/rpcimpl.cc | 4 +++- libtransmission/torrent.cc | 5 +++-- libtransmission/transmission.h | 2 ++ tests/libtransmission/torrents-test.cc | 12 ++++++++++++ 7 files changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/rpc-spec.md b/docs/rpc-spec.md index 9bfb8af76..e6119374f 100644 --- a/docs/rpc-spec.md +++ b/docs/rpc-spec.md @@ -294,6 +294,8 @@ The 'source' column here corresponds to the data structure there. | `bytesCompleted` | number | tr_file_view | `length` | number | tr_file_view | `name` | string | tr_file_view +| `beginPiece` | number | tr_file_view +| `endPiece` | number | tr_file_view `fileStats`: a file's non-constant properties. An array of `tr_info.filecount` objects, each containing: @@ -1009,3 +1011,5 @@ Transmission 4.1.0 (`rpc-version-semver` 5.4.0, `rpc-version`: 18) |:---|:--- | `torrent-get` | new arg `sequentialDownload` | `torrent-set` | new arg `sequentialDownload` +| `torrent-get` | new arg `files.beginPiece` +| `torrent-get` | new arg `files.endPiece` diff --git a/libtransmission/quark.cc b/libtransmission/quark.cc index 12bd03502..c69a26525 100644 --- a/libtransmission/quark.cc +++ b/libtransmission/quark.cc @@ -18,7 +18,7 @@ using namespace std::literals; namespace { -auto constexpr MyStatic = std::array{ ""sv, +auto constexpr MyStatic = std::array{ ""sv, "activeTorrentCount"sv, "activity-date"sv, "activityDate"sv, @@ -47,6 +47,7 @@ auto constexpr MyStatic = std::array{ ""sv, "availability"sv, "bandwidth-priority"sv, "bandwidthPriority"sv, + "beginPiece"sv, "bind-address-ipv4"sv, "bind-address-ipv6"sv, "bitfield"sv, @@ -108,6 +109,7 @@ auto constexpr MyStatic = std::array{ ""sv, "editDate"sv, "encoding"sv, "encryption"sv, + "endPiece"sv, "error"sv, "errorString"sv, "eta"sv, diff --git a/libtransmission/quark.h b/libtransmission/quark.h index c3db9ce1a..1e3b317d9 100644 --- a/libtransmission/quark.h +++ b/libtransmission/quark.h @@ -50,6 +50,7 @@ enum TR_KEY_availability, // rpc TR_KEY_bandwidth_priority, TR_KEY_bandwidthPriority, + TR_KEY_beginPiece, TR_KEY_bind_address_ipv4, TR_KEY_bind_address_ipv6, TR_KEY_bitfield, @@ -111,6 +112,7 @@ enum TR_KEY_editDate, TR_KEY_encoding, TR_KEY_encryption, + TR_KEY_endPiece, TR_KEY_error, TR_KEY_errorString, TR_KEY_eta, diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index b952695d7..c27c559af 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -326,8 +326,10 @@ void addFiles(tr_torrent const* tor, tr_variant* list) for (tr_file_index_t i = 0, n = tor->file_count(); i < n; ++i) { auto const file = tr_torrentFile(tor, i); - tr_variant* d = tr_variantListAddDict(list, 3); + tr_variant* d = tr_variantListAddDict(list, 5); + tr_variantDictAddInt(d, TR_KEY_beginPiece, file.beginPiece); tr_variantDictAddInt(d, TR_KEY_bytesCompleted, file.have); + tr_variantDictAddInt(d, TR_KEY_endPiece, file.endPiece); tr_variantDictAddInt(d, TR_KEY_length, file.length); tr_variantDictAddStr(d, TR_KEY_name, file.name); } diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index 1bd1ed299..17676bb28 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -1615,14 +1615,15 @@ tr_file_view tr_torrentFile(tr_torrent const* tor, tr_file_index_t file) auto const priority = tor->file_priorities_.file_priority(file); auto const wanted = tor->files_wanted_.file_wanted(file); auto const length = tor->file_size(file); + auto const [begin, end] = tor->pieces_in_file(file); if (tor->completeness == TR_SEED || length == 0) { - return { subpath.c_str(), length, length, 1.0, priority, wanted }; + return { subpath.c_str(), length, length, 1.0, begin, end, priority, wanted }; } auto const have = tor->completion.count_has_bytes_in_span(tor->fpm_.byte_span(file)); - return { subpath.c_str(), have, length, have >= length ? 1.0 : have / double(length), priority, wanted }; + return { subpath.c_str(), have, length, have >= length ? 1.0 : have / double(length), begin, end, priority, wanted }; } size_t tr_torrentFileCount(tr_torrent const* torrent) diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index b2d9015ab..f1e7b5013 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -1334,6 +1334,8 @@ struct tr_file_view uint64_t have; // the current size of the file, i.e. how much we've downloaded uint64_t length; // the total size of the file double progress; // have / length + tr_piece_index_t beginPiece; // piece index where this file starts + tr_piece_index_t endPiece; // piece index where this file ends (exclusive) tr_priority_t priority; // the file's priority bool wanted; // do we want to download this file? }; diff --git a/tests/libtransmission/torrents-test.cc b/tests/libtransmission/torrents-test.cc index 07738cda7..e3696a9d8 100644 --- a/tests/libtransmission/torrents-test.cc +++ b/tests/libtransmission/torrents-test.cc @@ -14,6 +14,8 @@ #include "gtest/gtest.h" +#include "test-fixtures.h" + using namespace std::literals; using TorrentsTest = ::testing::Test; @@ -128,3 +130,13 @@ TEST_F(TorrentsTest, removedSince) remove = { torrents_v[0]->id(), torrents_v[1]->id(), torrents_v[2]->id(), torrents_v[3]->id() }; EXPECT_EQ(remove, torrents.removedSince(50)); } + +using TorrentsPieceSpanTest = libtransmission::test::SessionTest; + +TEST_F(TorrentsPieceSpanTest, exposesFilePieceSpan) +{ + auto tor = zeroTorrentInit(ZeroTorrentState::Complete); + auto file_view = tr_torrentFile(tor, 0); + EXPECT_EQ(file_view.beginPiece, 0); + EXPECT_EQ(file_view.endPiece, 32); +}