mirror of
https://github.com/transmission/transmission.git
synced 2026-02-14 23:19:34 +00:00
refactor: use sigslot (#8309)
* fix: warning: declaration shadows a variable in the global namespace [clang-diagnostic-shadow] * fix: warning: use 'contains' to check for membership [readability-container-contains] * fix: warning: variable gl_confdir can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage] * warning: function 'TorrentFilter::match_mode' has a definition with different parameter names [readability-inconsistent-declaration-parameter-name] * build: add sigslot dependency * refactor: use sigslot for tr::Blocklists * refactor: use sigslot for torrent, peer-mgr, wishlist * refactor: remove tr::SimpleObservable * chore: make lint happy warning: method 'make_wishlist' can be made static [readability-convert-member-functions-to-static] warning: invalid case style for function 'make_wishlist' [readability-identifier-naming] warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays] * refactor: remove unused forward declaration of tr_peer * chore: remove slop * refactor: Blocklist::observe_changes() now returns a scoped connection * build: use transmission/sigslot fork * refactor: copyediting * refactor: fix cyclical dependency loop between Wishlist and tr_peerMgr::WishlistMediator
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -64,3 +64,6 @@
|
||||
[submodule "third-party/crc32c"]
|
||||
path = third-party/crc32c
|
||||
url = https://github.com/google/crc32c.git
|
||||
[submodule "third-party/sigslot"]
|
||||
path = third-party/sigslot
|
||||
url = https://github.com/transmission/sigslot
|
||||
|
||||
@@ -4346,6 +4346,7 @@
|
||||
"third-party/dht",
|
||||
"third-party/fast_float/include",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/rapidjson/include",
|
||||
"third-party/libb64/include",
|
||||
@@ -4389,6 +4390,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
);
|
||||
WRAPPER_EXTENSION = app;
|
||||
@@ -4407,6 +4409,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -4429,6 +4432,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -4447,6 +4451,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -4592,6 +4597,7 @@
|
||||
"third-party/dht",
|
||||
"third-party/fast_float/include",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/rapidjson/include",
|
||||
"third-party/libb64/include",
|
||||
@@ -4624,6 +4630,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -4653,6 +4660,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
);
|
||||
WRAPPER_EXTENSION = app;
|
||||
@@ -4859,6 +4867,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
);
|
||||
WRAPPER_EXTENSION = app;
|
||||
@@ -4877,6 +4886,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -4918,6 +4928,7 @@
|
||||
"third-party/dht",
|
||||
"third-party/fast_float/include",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/rapidjson/include",
|
||||
"third-party/libb64/include",
|
||||
@@ -4954,6 +4965,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -4972,6 +4984,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5046,6 +5059,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
);
|
||||
WRAPPER_EXTENSION = qlgenerator;
|
||||
@@ -5074,6 +5088,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
);
|
||||
WRAPPER_EXTENSION = qlgenerator;
|
||||
@@ -5102,6 +5117,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
);
|
||||
WRAPPER_EXTENSION = qlgenerator;
|
||||
@@ -5164,6 +5180,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5182,6 +5199,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5332,6 +5350,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5350,6 +5369,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5368,6 +5388,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5386,6 +5407,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5404,6 +5426,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5422,6 +5445,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5440,6 +5464,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5458,6 +5483,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5476,6 +5502,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
"third-party/libevent/include",
|
||||
);
|
||||
@@ -5509,6 +5536,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
);
|
||||
};
|
||||
@@ -5541,6 +5569,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
);
|
||||
};
|
||||
@@ -5573,6 +5602,7 @@
|
||||
SYSTEM_HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"third-party/fmt/include",
|
||||
"third-party/sigslot/include",
|
||||
"third-party/small/include",
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,6 +12,8 @@ add_compile_options(
|
||||
# equivalent of XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES for this directory
|
||||
$<$<AND:$<BOOL:${APPLE}>,$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>,$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>>:-fobjc-arc>)
|
||||
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/third-party/sigslot ${CMAKE_BINARY_DIR}/third-party/sigslot)
|
||||
|
||||
add_library(${TR_NAME} STATIC)
|
||||
|
||||
set(IS_APPLE_CLANG FALSE)
|
||||
@@ -78,7 +80,6 @@ target_sources(${TR_NAME}
|
||||
mime-types.h
|
||||
net.cc
|
||||
net.h
|
||||
observable.h
|
||||
open-files.cc
|
||||
open-files.h
|
||||
peer-common.h
|
||||
@@ -286,6 +287,7 @@ target_link_libraries(${TR_NAME}
|
||||
PUBLIC
|
||||
transmission::crypto_impl
|
||||
fmt::fmt-header-only
|
||||
sigslot
|
||||
transmission::small
|
||||
libevent::event)
|
||||
|
||||
|
||||
@@ -515,7 +515,7 @@ void Blocklists::set_enabled(bool is_enabled)
|
||||
blocklist.setEnabled(is_enabled);
|
||||
}
|
||||
|
||||
changed_.emit();
|
||||
changed_();
|
||||
}
|
||||
|
||||
void Blocklists::load(std::string_view folder, bool is_enabled)
|
||||
@@ -523,7 +523,7 @@ void Blocklists::load(std::string_view folder, bool is_enabled)
|
||||
folder_ = folder;
|
||||
blocklists_ = load_folder(folder, is_enabled);
|
||||
|
||||
changed_.emit();
|
||||
changed_();
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -590,7 +590,7 @@ size_t Blocklists::update_primary_blocklist(std::string_view const external_file
|
||||
blocklists_.emplace_back(std::move(*added));
|
||||
}
|
||||
|
||||
changed_.emit();
|
||||
changed_();
|
||||
|
||||
return n_rules;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
#include <utility> // for std::pair
|
||||
#include <vector>
|
||||
|
||||
#include <sigslot/signal.hpp>
|
||||
|
||||
#include "libtransmission/net.h" // for tr_address
|
||||
#include "libtransmission/observable.h"
|
||||
|
||||
namespace tr
|
||||
{
|
||||
@@ -56,9 +57,9 @@ public:
|
||||
size_t update_primary_blocklist(std::string_view external_file, bool is_enabled);
|
||||
|
||||
template<typename Observer>
|
||||
[[nodiscard]] auto observe_changes(Observer observer)
|
||||
[[nodiscard]] sigslot::scoped_connection observe_changes(Observer observer) const
|
||||
{
|
||||
return changed_.observe(std::move(observer));
|
||||
return changed_.connect_scoped(std::move(observer));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -112,7 +113,7 @@ private:
|
||||
|
||||
std::string folder_;
|
||||
|
||||
tr::SimpleObservable<> changed_;
|
||||
mutable sigslot::signal<> changed_;
|
||||
|
||||
[[nodiscard]] static std::vector<Blocklist> load_folder(std::string_view folder, bool is_enabled);
|
||||
};
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __TRANSMISSION__
|
||||
#error only libtransmission should #include this header.
|
||||
#endif
|
||||
|
||||
#include <cstddef> // for size_t
|
||||
#include <functional>
|
||||
#include <utility> // for std::move
|
||||
|
||||
#include <small/map.hpp>
|
||||
|
||||
#include "libtransmission/tr-assert.h"
|
||||
|
||||
namespace tr
|
||||
{
|
||||
|
||||
// An RAII-based subscription to an Observable.
|
||||
// Returned by SimpleObservable::observe().
|
||||
// Let it go out-of-scope to cancel the subscription.
|
||||
class ObserverTag
|
||||
{
|
||||
public:
|
||||
using Callback = std::function<void()>;
|
||||
|
||||
ObserverTag() = default;
|
||||
|
||||
ObserverTag(ObserverTag&& that) noexcept
|
||||
{
|
||||
*this = std::forward<ObserverTag>(that);
|
||||
}
|
||||
|
||||
ObserverTag& operator=(ObserverTag&& that) noexcept
|
||||
{
|
||||
on_destroy_ = std::move(that.on_destroy_);
|
||||
that.on_destroy_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ObserverTag(ObserverTag const&) = delete;
|
||||
ObserverTag& operator=(ObserverTag const&) = delete;
|
||||
|
||||
explicit ObserverTag(Callback on_destroy)
|
||||
: on_destroy_{ std::move(on_destroy) }
|
||||
{
|
||||
}
|
||||
|
||||
~ObserverTag()
|
||||
{
|
||||
if (on_destroy_)
|
||||
{
|
||||
on_destroy_();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Callback on_destroy_;
|
||||
};
|
||||
|
||||
// A simple observer/observable implementation.
|
||||
// Intentionally avoids edge cases like thread safety and
|
||||
// remove-during-emit; this is meant to be as lightweight
|
||||
// as possible for very basic use cases.
|
||||
template<typename... Args>
|
||||
class SimpleObservable // NOLINT(cppcoreguidelines-special-member-functions)
|
||||
{
|
||||
using Key = size_t;
|
||||
|
||||
public:
|
||||
using Observer = std::function<void(Args...)>;
|
||||
|
||||
~SimpleObservable()
|
||||
{
|
||||
TR_ASSERT(std::empty(observers_));
|
||||
}
|
||||
|
||||
[[nodiscard]] auto observe(Observer observer)
|
||||
{
|
||||
auto const key = next_key++;
|
||||
observers_.emplace(key, std::move(observer));
|
||||
// clang-format off: TODO: remove when we bump to clang-format >= 21
|
||||
return ObserverTag{ [this, key]() { remove(key); } };
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void emit(Args... args) const
|
||||
{
|
||||
for (auto& [tag, observer] : observers_)
|
||||
{
|
||||
observer(args...);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void remove(Key key)
|
||||
{
|
||||
[[maybe_unused]] auto const n_removed = observers_.erase(key);
|
||||
TR_ASSERT(n_removed == 1U);
|
||||
}
|
||||
|
||||
static auto inline next_key = Key{ 1U };
|
||||
small::map<Key, Observer, 4U> observers_;
|
||||
};
|
||||
|
||||
} // namespace tr
|
||||
@@ -4,6 +4,7 @@
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#include <algorithm> // std::adjacent_find, std::sort
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
@@ -19,8 +20,9 @@
|
||||
|
||||
#include "libtransmission/bitfield.h"
|
||||
#include "libtransmission/crypto-utils.h" // for tr_salt_shaker
|
||||
#include "libtransmission/tr-macros.h"
|
||||
#include "libtransmission/tr-assert.h"
|
||||
#include "libtransmission/peer-mgr-wishlist.h"
|
||||
#include "libtransmission/utils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -109,6 +111,81 @@ class Wishlist::Impl
|
||||
public:
|
||||
explicit Impl(Mediator& mediator_in);
|
||||
|
||||
void on_files_wanted_changed()
|
||||
{
|
||||
candidate_list_upkeep();
|
||||
}
|
||||
|
||||
void on_got_bad_piece(tr_piece_index_t const piece)
|
||||
{
|
||||
got_bad_piece(piece);
|
||||
}
|
||||
|
||||
void on_got_bitfield(tr_bitfield const& bitfield)
|
||||
{
|
||||
inc_replication_bitfield(bitfield);
|
||||
}
|
||||
|
||||
void on_got_block(tr_block_index_t const block)
|
||||
{
|
||||
client_got_block(block);
|
||||
}
|
||||
|
||||
void on_got_choke(tr_bitfield const& requests)
|
||||
{
|
||||
reset_blocks_bitfield(requests);
|
||||
}
|
||||
|
||||
void on_got_have(tr_piece_index_t const piece)
|
||||
{
|
||||
inc_replication_piece(piece);
|
||||
}
|
||||
|
||||
void on_got_have_all()
|
||||
{
|
||||
inc_replication();
|
||||
}
|
||||
|
||||
void on_got_reject(tr_block_index_t const block)
|
||||
{
|
||||
reset_block(block);
|
||||
}
|
||||
|
||||
void on_peer_disconnect(tr_bitfield const& have, tr_bitfield const& requests)
|
||||
{
|
||||
peer_disconnect(have, requests);
|
||||
}
|
||||
|
||||
void on_piece_completed(tr_piece_index_t const piece)
|
||||
{
|
||||
remove_piece(piece);
|
||||
}
|
||||
|
||||
void on_priority_changed()
|
||||
{
|
||||
recalculate_priority();
|
||||
}
|
||||
|
||||
void on_sent_cancel(tr_block_index_t const block)
|
||||
{
|
||||
reset_block(block);
|
||||
}
|
||||
|
||||
void on_sent_request(tr_block_span_t const block_span)
|
||||
{
|
||||
requested_block_span(block_span);
|
||||
}
|
||||
|
||||
void on_sequential_download_changed()
|
||||
{
|
||||
recalculate_salt();
|
||||
}
|
||||
|
||||
void on_sequential_download_from_piece_changed()
|
||||
{
|
||||
recalculate_salt();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<tr_block_span_t> next(
|
||||
size_t n_wanted_blocks,
|
||||
std::function<bool(tr_piece_index_t)> const& peer_has_piece);
|
||||
@@ -523,49 +600,11 @@ private:
|
||||
|
||||
CandidateVec candidates_;
|
||||
|
||||
std::array<tr::ObserverTag, 15U> const tags_;
|
||||
|
||||
Mediator& mediator_;
|
||||
};
|
||||
|
||||
Wishlist::Impl::Impl(Mediator& mediator_in)
|
||||
: tags_{ {
|
||||
// candidates
|
||||
mediator_in.observe_files_wanted_changed([this](tr_torrent*, tr_file_index_t const*, tr_file_index_t, bool)
|
||||
{ candidate_list_upkeep(); }),
|
||||
// replication, unrequested
|
||||
mediator_in.observe_peer_disconnect([this](tr_torrent*, tr_bitfield const& b, tr_bitfield const& ar)
|
||||
{ peer_disconnect(b, ar); }),
|
||||
// unrequested
|
||||
mediator_in.observe_got_bad_piece([this](tr_torrent*, tr_piece_index_t p) { got_bad_piece(p); }),
|
||||
// replication
|
||||
mediator_in.observe_got_bitfield([this](tr_torrent*, tr_bitfield const& b) { inc_replication_bitfield(b); }),
|
||||
// unrequested
|
||||
mediator_in.observe_got_block([this](tr_torrent*, tr_block_index_t b) { client_got_block(b); }),
|
||||
// unrequested
|
||||
mediator_in.observe_got_choke([this](tr_torrent*, tr_bitfield const& b) { reset_blocks_bitfield(b); }),
|
||||
// replication
|
||||
mediator_in.observe_got_have([this](tr_torrent*, tr_piece_index_t p) { inc_replication_piece(p); }),
|
||||
// replication
|
||||
mediator_in.observe_got_have_all([this](tr_torrent*) { inc_replication(); }),
|
||||
// unrequested
|
||||
mediator_in.observe_got_reject([this](tr_torrent*, tr_peer*, tr_block_index_t b) { reset_block(b); }),
|
||||
// candidates
|
||||
mediator_in.observe_piece_completed([this](tr_torrent*, tr_piece_index_t p) { remove_piece(p); }),
|
||||
// priority
|
||||
mediator_in.observe_priority_changed([this](tr_torrent*, tr_file_index_t const*, tr_file_index_t, tr_priority_t)
|
||||
{ recalculate_priority(); }),
|
||||
// unrequested
|
||||
mediator_in.observe_sent_cancel([this](tr_torrent*, tr_peer*, tr_block_index_t b) { reset_block(b); }),
|
||||
// unrequested
|
||||
mediator_in.observe_sent_request([this](tr_torrent*, tr_peer*, tr_block_span_t bs) { requested_block_span(bs); }),
|
||||
// salt
|
||||
mediator_in.observe_sequential_download_changed([this](tr_torrent*, bool) { recalculate_salt(); }),
|
||||
// salt
|
||||
mediator_in.observe_sequential_download_from_piece_changed([this](tr_torrent*, tr_piece_index_t)
|
||||
{ recalculate_salt(); }),
|
||||
} }
|
||||
, mediator_{ mediator_in }
|
||||
: mediator_{ mediator_in }
|
||||
{
|
||||
candidate_list_upkeep();
|
||||
}
|
||||
@@ -641,6 +680,81 @@ Wishlist::Wishlist(Mediator& mediator_in)
|
||||
|
||||
Wishlist::~Wishlist() = default;
|
||||
|
||||
void Wishlist::on_files_wanted_changed()
|
||||
{
|
||||
impl_->on_files_wanted_changed();
|
||||
}
|
||||
|
||||
void Wishlist::on_got_bad_piece(tr_piece_index_t const piece)
|
||||
{
|
||||
impl_->on_got_bad_piece(piece);
|
||||
}
|
||||
|
||||
void Wishlist::on_got_bitfield(tr_bitfield const& bitfield)
|
||||
{
|
||||
impl_->on_got_bitfield(bitfield);
|
||||
}
|
||||
|
||||
void Wishlist::on_got_block(tr_block_index_t const block)
|
||||
{
|
||||
impl_->on_got_block(block);
|
||||
}
|
||||
|
||||
void Wishlist::on_got_choke(tr_bitfield const& requests)
|
||||
{
|
||||
impl_->on_got_choke(requests);
|
||||
}
|
||||
|
||||
void Wishlist::on_got_have(tr_piece_index_t const piece)
|
||||
{
|
||||
impl_->on_got_have(piece);
|
||||
}
|
||||
|
||||
void Wishlist::on_got_have_all()
|
||||
{
|
||||
impl_->on_got_have_all();
|
||||
}
|
||||
|
||||
void Wishlist::on_got_reject(tr_block_index_t const block)
|
||||
{
|
||||
impl_->on_got_reject(block);
|
||||
}
|
||||
|
||||
void Wishlist::on_peer_disconnect(tr_bitfield const& have, tr_bitfield const& requests)
|
||||
{
|
||||
impl_->on_peer_disconnect(have, requests);
|
||||
}
|
||||
|
||||
void Wishlist::on_piece_completed(tr_piece_index_t const piece)
|
||||
{
|
||||
impl_->on_piece_completed(piece);
|
||||
}
|
||||
|
||||
void Wishlist::on_priority_changed()
|
||||
{
|
||||
impl_->on_priority_changed();
|
||||
}
|
||||
|
||||
void Wishlist::on_sent_cancel(tr_block_index_t const block)
|
||||
{
|
||||
impl_->on_sent_cancel(block);
|
||||
}
|
||||
|
||||
void Wishlist::on_sent_request(tr_block_span_t const block_span)
|
||||
{
|
||||
impl_->on_sent_request(block_span);
|
||||
}
|
||||
|
||||
void Wishlist::on_sequential_download_changed()
|
||||
{
|
||||
impl_->on_sequential_download_changed();
|
||||
}
|
||||
|
||||
void Wishlist::on_sequential_download_from_piece_changed()
|
||||
{
|
||||
impl_->on_sequential_download_from_piece_changed();
|
||||
}
|
||||
|
||||
std::vector<tr_block_span_t> Wishlist::next(
|
||||
size_t const n_wanted_blocks,
|
||||
std::function<bool(tr_piece_index_t)> const& peer_has_piece)
|
||||
|
||||
@@ -16,11 +16,7 @@
|
||||
|
||||
#include "libtransmission/transmission.h"
|
||||
|
||||
#include "libtransmission/observable.h"
|
||||
#include "libtransmission/utils.h"
|
||||
|
||||
class tr_bitfield;
|
||||
struct tr_peer;
|
||||
|
||||
/**
|
||||
* Figures out what blocks we want to request next.
|
||||
@@ -39,43 +35,28 @@ public:
|
||||
[[nodiscard]] virtual tr_block_span_t block_span(tr_piece_index_t piece) const = 0;
|
||||
[[nodiscard]] virtual tr_piece_index_t piece_count() const = 0;
|
||||
[[nodiscard]] virtual tr_priority_t priority(tr_piece_index_t piece) const = 0;
|
||||
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_files_wanted_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, bool>::Observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_peer_disconnect(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&, tr_bitfield const&>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_got_bad_piece(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_got_bitfield(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_got_block(
|
||||
tr::SimpleObservable<tr_torrent*, tr_block_index_t>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_got_choke(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_got_have(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_got_have_all(tr::SimpleObservable<tr_torrent*>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_got_reject(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_piece_completed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_priority_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, tr_priority_t>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_sent_cancel(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_sent_request(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_span_t>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_sequential_download_changed(
|
||||
tr::SimpleObservable<tr_torrent*, bool>::Observer observer) = 0;
|
||||
[[nodiscard]] virtual tr::ObserverTag observe_sequential_download_from_piece_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) = 0;
|
||||
|
||||
virtual ~Mediator() = default;
|
||||
};
|
||||
|
||||
explicit Wishlist(Mediator& mediator_in);
|
||||
~Wishlist();
|
||||
|
||||
void on_files_wanted_changed();
|
||||
void on_got_bad_piece(tr_piece_index_t piece);
|
||||
void on_got_bitfield(tr_bitfield const& bitfield);
|
||||
void on_got_block(tr_block_index_t block);
|
||||
void on_got_choke(tr_bitfield const& requests);
|
||||
void on_got_have(tr_piece_index_t piece);
|
||||
void on_got_have_all();
|
||||
void on_got_reject(tr_block_index_t block);
|
||||
void on_peer_disconnect(tr_bitfield const& have, tr_bitfield const& requests);
|
||||
void on_piece_completed(tr_piece_index_t piece);
|
||||
void on_priority_changed();
|
||||
void on_sent_cancel(tr_block_index_t block);
|
||||
void on_sent_request(tr_block_span_t block_span);
|
||||
void on_sequential_download_changed();
|
||||
void on_sequential_download_from_piece_changed();
|
||||
|
||||
// the next blocks that we should request from a peer
|
||||
[[nodiscard]] std::vector<tr_block_span_t> next(
|
||||
size_t n_wanted_blocks,
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <small/map.hpp>
|
||||
#include <small/vector.hpp>
|
||||
|
||||
#include <sigslot/signal.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#define LIBTRANSMISSION_PEER_MODULE
|
||||
@@ -36,7 +38,6 @@
|
||||
#include "libtransmission/interned-string.h"
|
||||
#include "libtransmission/log.h"
|
||||
#include "libtransmission/net.h"
|
||||
#include "libtransmission/observable.h"
|
||||
#include "libtransmission/peer-common.h"
|
||||
#include "libtransmission/peer-io.h"
|
||||
#include "libtransmission/peer-mgr-wishlist.h"
|
||||
@@ -366,59 +367,108 @@ public:
|
||||
using Peers = std::vector<std::shared_ptr<tr_peerMsgs>>;
|
||||
using Pool = small::map<tr_socket_address, std::shared_ptr<tr_peer_info>>;
|
||||
|
||||
class WishlistMediator final : public Wishlist::Mediator
|
||||
class WishlistController final : public Wishlist::Mediator
|
||||
{
|
||||
public:
|
||||
explicit WishlistMediator(tr_swarm& swarm)
|
||||
explicit WishlistController(tr_swarm& swarm)
|
||||
: tor_{ *swarm.tor }
|
||||
, swarm_{ swarm }
|
||||
, wishlist_{ *this }
|
||||
, signal_tags_{ {
|
||||
tor_.files_wanted_changed_.connect_scoped([this](tr_torrent*, tr_file_index_t const*, tr_file_index_t, bool)
|
||||
{ wishlist_.on_files_wanted_changed(); }),
|
||||
swarm_.peer_disconnect.connect_scoped(
|
||||
[this](tr_torrent*, tr_bitfield const& have, tr_bitfield const& requests)
|
||||
{ wishlist_.on_peer_disconnect(have, requests); }),
|
||||
tor_.got_bad_piece_.connect_scoped([this](tr_torrent*, tr_piece_index_t piece)
|
||||
{ wishlist_.on_got_bad_piece(piece); }),
|
||||
swarm_.got_bitfield.connect_scoped([this](tr_torrent*, tr_bitfield const& bitfield)
|
||||
{ wishlist_.on_got_bitfield(bitfield); }),
|
||||
swarm_.got_block.connect_scoped([this](tr_torrent*, tr_block_index_t block)
|
||||
{ wishlist_.on_got_block(block); }),
|
||||
swarm_.got_choke.connect_scoped([this](tr_torrent*, tr_bitfield const& bitfield)
|
||||
{ wishlist_.on_got_choke(bitfield); }),
|
||||
swarm_.got_have.connect_scoped([this](tr_torrent*, tr_piece_index_t piece) { wishlist_.on_got_have(piece); }),
|
||||
swarm_.got_have_all.connect_scoped([this](tr_torrent*) { wishlist_.on_got_have_all(); }),
|
||||
swarm_.got_reject.connect_scoped([this](tr_torrent*, tr_peer*, tr_block_index_t block)
|
||||
{ wishlist_.on_got_reject(block); }),
|
||||
tor_.piece_completed_.connect_scoped([this](tr_torrent*, tr_piece_index_t piece)
|
||||
{ wishlist_.on_piece_completed(piece); }),
|
||||
tor_.priority_changed_.connect_scoped(
|
||||
[this](tr_torrent*, tr_file_index_t const*, tr_file_index_t, tr_priority_t)
|
||||
{ wishlist_.on_priority_changed(); }),
|
||||
swarm_.sent_cancel.connect_scoped([this](tr_torrent*, tr_peer*, tr_block_index_t block)
|
||||
{ wishlist_.on_sent_cancel(block); }),
|
||||
swarm_.sent_request.connect_scoped([this](tr_torrent*, tr_peer*, tr_block_span_t block_span)
|
||||
{ wishlist_.on_sent_request(block_span); }),
|
||||
tor_.sequential_download_changed_.connect_scoped([this](tr_torrent*, bool)
|
||||
{ wishlist_.on_sequential_download_changed(); }),
|
||||
tor_.sequential_download_from_piece_changed_.connect_scoped(
|
||||
[this](tr_torrent*, tr_piece_index_t) { wishlist_.on_sequential_download_from_piece_changed(); }),
|
||||
} }
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool client_has_block(tr_block_index_t block) const override;
|
||||
[[nodiscard]] bool client_has_piece(tr_piece_index_t piece) const override;
|
||||
[[nodiscard]] bool client_wants_piece(tr_piece_index_t piece) const override;
|
||||
[[nodiscard]] bool is_sequential_download() const override;
|
||||
[[nodiscard]] tr_piece_index_t sequential_download_from_piece() const override;
|
||||
[[nodiscard]] size_t count_piece_replication(tr_piece_index_t piece) const override;
|
||||
[[nodiscard]] tr_block_span_t block_span(tr_piece_index_t piece) const override;
|
||||
[[nodiscard]] tr_piece_index_t piece_count() const override;
|
||||
[[nodiscard]] tr_priority_t priority(tr_piece_index_t piece) const override;
|
||||
[[nodiscard]] auto next(size_t const n_wanted_blocks, std::function<bool(tr_piece_index_t)> const& peer_has_piece)
|
||||
{
|
||||
return wishlist_.next(n_wanted_blocks, peer_has_piece);
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_files_wanted_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, bool>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_peer_disconnect(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&, tr_bitfield const&>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_got_bad_piece(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_got_bitfield(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_got_block(
|
||||
tr::SimpleObservable<tr_torrent*, tr_block_index_t>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_got_choke(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_got_have(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_got_have_all(tr::SimpleObservable<tr_torrent*>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_got_reject(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_piece_completed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_priority_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, tr_priority_t>::Observer observer)
|
||||
override;
|
||||
[[nodiscard]] tr::ObserverTag observe_sent_cancel(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_sent_request(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_span_t>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_sequential_download_changed(
|
||||
tr::SimpleObservable<tr_torrent*, bool>::Observer observer) override;
|
||||
[[nodiscard]] tr::ObserverTag observe_sequential_download_from_piece_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) override;
|
||||
[[nodiscard]] bool client_has_block(tr_block_index_t const block) const override
|
||||
{
|
||||
return tor_.has_block(block);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool client_has_piece(tr_piece_index_t const piece) const override
|
||||
{
|
||||
return tor_.has_blocks(block_span(piece));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool client_wants_piece(tr_piece_index_t const piece) const override
|
||||
{
|
||||
return tor_.piece_is_wanted(piece);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_sequential_download() const override
|
||||
{
|
||||
return tor_.is_sequential_download();
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_piece_index_t sequential_download_from_piece() const override
|
||||
{
|
||||
return tor_.sequential_download_from_piece();
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t count_piece_replication(tr_piece_index_t const piece) const override
|
||||
{
|
||||
auto const op = [piece](size_t acc, auto const& peer)
|
||||
{
|
||||
return acc + (peer->has_piece(piece) ? 1U : 0U);
|
||||
};
|
||||
return std::accumulate(std::begin(swarm_.peers), std::end(swarm_.peers), size_t{}, op) +
|
||||
std::accumulate(std::begin(swarm_.webseeds), std::end(swarm_.webseeds), size_t{}, op);
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_block_span_t block_span(tr_piece_index_t const piece) const override
|
||||
{
|
||||
return tor_.block_span_for_piece(piece);
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_piece_index_t piece_count() const override
|
||||
{
|
||||
return tor_.piece_count();
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_priority_t priority(tr_piece_index_t const piece) const override
|
||||
{
|
||||
return tor_.piece_priority(piece);
|
||||
}
|
||||
|
||||
private:
|
||||
tr_torrent& tor_;
|
||||
tr_swarm& swarm_;
|
||||
Wishlist wishlist_;
|
||||
std::array<sigslot::scoped_connection, 15U> signal_tags_; // depends-on: wishlist_
|
||||
};
|
||||
|
||||
[[nodiscard]] auto unique_lock() const
|
||||
@@ -430,14 +480,14 @@ public:
|
||||
: manager{ manager_in }
|
||||
, tor{ tor_in }
|
||||
, tags_{ {
|
||||
tor_in->done_.observe([this](tr_torrent*, bool) { on_torrent_done(); }),
|
||||
tor_in->doomed_.observe([this](tr_torrent*) { on_torrent_doomed(); }),
|
||||
tor_in->got_bad_piece_.observe([this](tr_torrent*, tr_piece_index_t p) { on_got_bad_piece(p); }),
|
||||
tor_in->got_metainfo_.observe([this](tr_torrent*) { on_got_metainfo(); }),
|
||||
tor_in->piece_completed_.observe([this](tr_torrent*, tr_piece_index_t p) { on_piece_completed(p); }),
|
||||
tor_in->started_.observe([this](tr_torrent*) { on_torrent_started(); }),
|
||||
tor_in->stopped_.observe([this](tr_torrent*) { on_torrent_stopped(); }),
|
||||
tor_in->swarm_is_all_upload_only_.observe([this](tr_torrent* /*tor*/) { on_swarm_is_all_upload_only(); }),
|
||||
tor_in->done_.connect_scoped([this](tr_torrent*, bool) { on_torrent_done(); }),
|
||||
tor_in->doomed_.connect_scoped([this](tr_torrent*) { on_torrent_doomed(); }),
|
||||
tor_in->got_bad_piece_.connect_scoped([this](tr_torrent*, tr_piece_index_t p) { on_got_bad_piece(p); }),
|
||||
tor_in->got_metainfo_.connect_scoped([this](tr_torrent*) { on_got_metainfo(); }),
|
||||
tor_in->piece_completed_.connect_scoped([this](tr_torrent*, tr_piece_index_t p) { on_piece_completed(p); }),
|
||||
tor_in->started_.connect_scoped([this](tr_torrent*) { on_torrent_started(); }),
|
||||
tor_in->stopped_.connect_scoped([this](tr_torrent*) { on_torrent_stopped(); }),
|
||||
tor_in->swarm_is_all_upload_only_.connect_scoped([this](tr_torrent* /*tor*/) { on_swarm_is_all_upload_only(); }),
|
||||
} }
|
||||
{
|
||||
rebuild_webseeds();
|
||||
@@ -450,6 +500,8 @@ public:
|
||||
|
||||
~tr_swarm()
|
||||
{
|
||||
wishlist_controller.reset();
|
||||
|
||||
auto const lock = unique_lock();
|
||||
TR_ASSERT(!is_running);
|
||||
TR_ASSERT(std::empty(peers));
|
||||
@@ -477,7 +529,7 @@ public:
|
||||
{
|
||||
auto const lock = unique_lock();
|
||||
|
||||
peer_disconnect.emit(tor, peer->has(), peer->active_requests);
|
||||
peer_disconnect(tor, peer->has(), peer->active_requests);
|
||||
|
||||
auto const& peer_info = peer->peer_info;
|
||||
TR_ASSERT(peer_info);
|
||||
@@ -573,7 +625,7 @@ public:
|
||||
{
|
||||
auto* const tor = s->tor;
|
||||
auto const loc = tor->piece_loc(event.pieceIndex, event.offset);
|
||||
s->sent_cancel.emit(tor, msgs, loc.block);
|
||||
s->sent_cancel(tor, msgs, loc.block);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -594,12 +646,12 @@ public:
|
||||
break;
|
||||
|
||||
case tr_peer_event::Type::ClientGotHave:
|
||||
s->got_have.emit(s->tor, event.pieceIndex);
|
||||
s->got_have(s->tor, event.pieceIndex);
|
||||
s->mark_all_upload_only_flag_dirty();
|
||||
break;
|
||||
|
||||
case tr_peer_event::Type::ClientGotHaveAll:
|
||||
s->got_have_all.emit(s->tor);
|
||||
s->got_have_all(s->tor);
|
||||
s->mark_all_upload_only_flag_dirty();
|
||||
break;
|
||||
|
||||
@@ -608,12 +660,12 @@ public:
|
||||
break;
|
||||
|
||||
case tr_peer_event::Type::ClientGotBitfield:
|
||||
s->got_bitfield.emit(s->tor, msgs->has());
|
||||
s->got_bitfield(s->tor, msgs->has());
|
||||
s->mark_all_upload_only_flag_dirty();
|
||||
break;
|
||||
|
||||
case tr_peer_event::Type::ClientGotChoke:
|
||||
s->got_choke.emit(s->tor, msgs->active_requests);
|
||||
s->got_choke(s->tor, msgs->active_requests);
|
||||
break;
|
||||
|
||||
case tr_peer_event::Type::ClientGotPort:
|
||||
@@ -659,15 +711,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const& /*bitfield*/, tr_bitfield const& /*active requests*/> peer_disconnect;
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&> got_bitfield;
|
||||
tr::SimpleObservable<tr_torrent*, tr_block_index_t> got_block;
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&> got_choke;
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t> got_have;
|
||||
tr::SimpleObservable<tr_torrent*> got_have_all;
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t> got_reject;
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t> sent_cancel;
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_span_t> sent_request;
|
||||
sigslot::signal<tr_torrent*, tr_bitfield const& /*bitfield*/, tr_bitfield const& /*active requests*/> peer_disconnect;
|
||||
sigslot::signal<tr_torrent*, tr_bitfield const&> got_bitfield;
|
||||
sigslot::signal<tr_torrent*, tr_block_index_t> got_block;
|
||||
sigslot::signal<tr_torrent*, tr_bitfield const&> got_choke;
|
||||
sigslot::signal<tr_torrent*, tr_piece_index_t> got_have;
|
||||
sigslot::signal<tr_torrent*> got_have_all;
|
||||
sigslot::signal<tr_torrent*, tr_peer*, tr_block_index_t> got_reject;
|
||||
sigslot::signal<tr_torrent*, tr_peer*, tr_block_index_t> sent_cancel;
|
||||
sigslot::signal<tr_torrent*, tr_peer*, tr_block_span_t> sent_request;
|
||||
|
||||
mutable tr_swarm_stats stats = {};
|
||||
|
||||
@@ -684,8 +736,7 @@ public:
|
||||
Peers peers;
|
||||
|
||||
// depends-on: tor
|
||||
WishlistMediator wishlist_mediator{ *this };
|
||||
std::unique_ptr<Wishlist> wishlist;
|
||||
std::unique_ptr<WishlistController> wishlist_controller;
|
||||
|
||||
Pool connectable_pool;
|
||||
|
||||
@@ -731,7 +782,7 @@ private:
|
||||
|
||||
is_running = false;
|
||||
remove_all_peers();
|
||||
wishlist.reset();
|
||||
wishlist_controller.reset();
|
||||
for (auto& [sockaddr, peer_info] : connectable_pool)
|
||||
{
|
||||
peer_info->destroy_handshake();
|
||||
@@ -770,7 +821,7 @@ private:
|
||||
void on_torrent_done()
|
||||
{
|
||||
std::ranges::for_each(peers, [](auto const& peer) { peer->set_interested(false); });
|
||||
wishlist.reset();
|
||||
wishlist_controller.reset();
|
||||
}
|
||||
|
||||
void on_swarm_is_all_upload_only()
|
||||
@@ -881,7 +932,8 @@ private:
|
||||
auto* const tor = s->tor;
|
||||
auto const loc_begin = tor->piece_loc(event.pieceIndex, event.offset);
|
||||
auto const loc_end = tor->piece_loc(event.pieceIndex, event.offset, event.length);
|
||||
s->sent_request.emit(tor, peer, { .begin = loc_begin.block, .end = loc_end.block });
|
||||
auto const span = tr_block_span_t{ .begin = loc_begin.block, .end = loc_end.block };
|
||||
s->sent_request(tor, peer, span);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -889,7 +941,7 @@ private:
|
||||
{
|
||||
auto* const tor = s->tor;
|
||||
auto const loc = tor->piece_loc(event.pieceIndex, event.offset);
|
||||
s->got_reject.emit(tor, peer, loc.block);
|
||||
s->got_reject(tor, peer, loc.block);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -900,7 +952,7 @@ private:
|
||||
s->cancel_all_requests_for_block(loc.block, peer);
|
||||
peer->blocks_sent_to_client.add(tr_time(), 1);
|
||||
peer->blame.set(loc.piece);
|
||||
s->got_block.emit(tor, loc.block); // put this line before calling tr_torrent callback
|
||||
s->got_block(tor, loc.block); // put this line before calling tr_torrent callback
|
||||
tor->on_block_received(loc.block);
|
||||
}
|
||||
break;
|
||||
@@ -989,150 +1041,11 @@ EXIT:
|
||||
// number of bad pieces a peer is allowed to send before we ban them
|
||||
static auto constexpr MaxBadPiecesPerPeer = 5U;
|
||||
|
||||
std::array<tr::ObserverTag, 8> const tags_;
|
||||
std::array<sigslot::scoped_connection, 8> const tags_;
|
||||
|
||||
mutable std::optional<bool> pool_is_all_upload_only_;
|
||||
};
|
||||
|
||||
bool tr_swarm::WishlistMediator::client_has_block(tr_block_index_t block) const
|
||||
{
|
||||
return tor_.has_block(block);
|
||||
}
|
||||
|
||||
bool tr_swarm::WishlistMediator::client_has_piece(tr_piece_index_t piece) const
|
||||
{
|
||||
return tor_.has_blocks(block_span(piece));
|
||||
}
|
||||
|
||||
bool tr_swarm::WishlistMediator::client_wants_piece(tr_piece_index_t piece) const
|
||||
{
|
||||
return tor_.piece_is_wanted(piece);
|
||||
}
|
||||
|
||||
bool tr_swarm::WishlistMediator::is_sequential_download() const
|
||||
{
|
||||
return tor_.is_sequential_download();
|
||||
}
|
||||
|
||||
tr_piece_index_t tr_swarm::WishlistMediator::sequential_download_from_piece() const
|
||||
{
|
||||
return tor_.sequential_download_from_piece();
|
||||
}
|
||||
|
||||
size_t tr_swarm::WishlistMediator::count_piece_replication(tr_piece_index_t piece) const
|
||||
{
|
||||
auto const op = [piece](size_t acc, auto const& peer)
|
||||
{
|
||||
return acc + (peer->has_piece(piece) ? 1U : 0U);
|
||||
};
|
||||
return std::accumulate(std::begin(swarm_.peers), std::end(swarm_.peers), size_t{}, op) +
|
||||
std::accumulate(std::begin(swarm_.webseeds), std::end(swarm_.webseeds), size_t{}, op);
|
||||
}
|
||||
|
||||
tr_block_span_t tr_swarm::WishlistMediator::block_span(tr_piece_index_t piece) const
|
||||
{
|
||||
return tor_.block_span_for_piece(piece);
|
||||
}
|
||||
|
||||
tr_piece_index_t tr_swarm::WishlistMediator::piece_count() const
|
||||
{
|
||||
return tor_.piece_count();
|
||||
}
|
||||
|
||||
tr_priority_t tr_swarm::WishlistMediator::priority(tr_piece_index_t piece) const
|
||||
{
|
||||
return tor_.piece_priority(piece);
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_files_wanted_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, bool>::Observer observer)
|
||||
{
|
||||
return tor_.files_wanted_changed_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_peer_disconnect(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&, tr_bitfield const&>::Observer observer)
|
||||
{
|
||||
return swarm_.peer_disconnect.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_got_bad_piece(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer)
|
||||
{
|
||||
return tor_.got_bad_piece_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_got_bitfield(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&>::Observer observer)
|
||||
{
|
||||
return swarm_.got_bitfield.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_got_block(
|
||||
tr::SimpleObservable<tr_torrent*, tr_block_index_t>::Observer observer)
|
||||
{
|
||||
return swarm_.got_block.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_got_choke(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&>::Observer observer)
|
||||
{
|
||||
return swarm_.got_choke.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_got_have(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer)
|
||||
{
|
||||
return swarm_.got_have.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_got_have_all(tr::SimpleObservable<tr_torrent*>::Observer observer)
|
||||
{
|
||||
return swarm_.got_have_all.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_got_reject(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t>::Observer observer)
|
||||
{
|
||||
return swarm_.got_reject.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_piece_completed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer)
|
||||
{
|
||||
return tor_.piece_completed_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_priority_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, tr_priority_t>::Observer observer)
|
||||
{
|
||||
return tor_.priority_changed_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_sent_cancel(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t>::Observer observer)
|
||||
{
|
||||
return swarm_.sent_cancel.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_sent_request(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_span_t>::Observer observer)
|
||||
{
|
||||
return swarm_.sent_request.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_sequential_download_changed(
|
||||
tr::SimpleObservable<tr_torrent*, bool>::Observer observer)
|
||||
{
|
||||
return tor_.sequential_download_changed_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
tr::ObserverTag tr_swarm::WishlistMediator::observe_sequential_download_from_piece_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer)
|
||||
{
|
||||
return tor_.sequential_download_from_piece_changed_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
struct tr_peerMgr
|
||||
@@ -1163,7 +1076,11 @@ public:
|
||||
using OutboundCandidates = small::
|
||||
max_size_vector<std::pair<tr_torrent_id_t, tr_socket_address>, OutboundCandidateListCapacity>;
|
||||
|
||||
explicit tr_peerMgr(tr_session* session_in, tr::TimerMaker& timer_maker, tr_torrents& torrents, tr::Blocklists& blocklist)
|
||||
explicit tr_peerMgr(
|
||||
tr_session* session_in,
|
||||
tr::TimerMaker& timer_maker,
|
||||
tr_torrents& torrents,
|
||||
tr::Blocklists const& blocklist)
|
||||
: session{ session_in }
|
||||
, torrents_{ torrents }
|
||||
, blocklists_{ blocklist }
|
||||
@@ -1254,7 +1171,7 @@ private:
|
||||
std::unique_ptr<tr::Timer> const peer_info_timer_;
|
||||
std::unique_ptr<tr::Timer> const rechoke_timer_;
|
||||
|
||||
tr::ObserverTag const blocklists_tag_;
|
||||
sigslot::scoped_connection blocklists_tag_;
|
||||
};
|
||||
|
||||
// --- tr_peer virtual functions
|
||||
@@ -1299,13 +1216,13 @@ void tr_peerMgrFree(tr_peerMgr* manager)
|
||||
std::vector<tr_block_span_t> tr_peerMgrGetNextRequests(tr_torrent* torrent, tr_peer const* peer, size_t numwant)
|
||||
{
|
||||
TR_ASSERT(!torrent->is_done());
|
||||
tr_swarm const& swarm = *torrent->swarm;
|
||||
TR_ASSERT(swarm.wishlist);
|
||||
if (!swarm.wishlist)
|
||||
|
||||
if (auto& controller = torrent->swarm->wishlist_controller)
|
||||
{
|
||||
return {};
|
||||
return controller->next(numwant, [peer](tr_piece_index_t p) { return peer->has_piece(p); });
|
||||
}
|
||||
return swarm.wishlist->next(numwant, [peer](tr_piece_index_t p) { return peer->has_piece(p); });
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -1688,7 +1605,7 @@ void tr_swarm::on_torrent_started()
|
||||
auto const lock = unique_lock();
|
||||
is_running = true;
|
||||
manager->rechokeSoon();
|
||||
wishlist = std::make_unique<Wishlist>(wishlist_mediator);
|
||||
wishlist_controller = std::make_unique<WishlistController>(*this);
|
||||
}
|
||||
|
||||
void tr_swarm::on_torrent_stopped()
|
||||
|
||||
@@ -541,7 +541,7 @@ void freeTorrent(tr_torrent* tor)
|
||||
|
||||
tr_session* session = tor->session;
|
||||
|
||||
tor->doomed_.emit(tor);
|
||||
tor->doomed_(tor);
|
||||
|
||||
session->announcer_->removeTorrent(tor);
|
||||
|
||||
@@ -643,7 +643,7 @@ void tr_torrent::start_in_session_thread()
|
||||
|
||||
session->announcer_->startTorrent(this);
|
||||
lpdAnnounceAt = now;
|
||||
started_.emit(this);
|
||||
started_(this);
|
||||
}
|
||||
|
||||
void tr_torrent::stop_now()
|
||||
@@ -666,7 +666,7 @@ void tr_torrent::stop_now()
|
||||
|
||||
session->verify_remove(this);
|
||||
|
||||
stopped_.emit(this);
|
||||
stopped_(this);
|
||||
session->announcer_->stopTorrent(this);
|
||||
|
||||
session->close_torrent_files(id());
|
||||
@@ -1022,7 +1022,7 @@ void tr_torrent::set_metainfo(tr_torrent_metainfo tm)
|
||||
metainfo_ = std::move(tm);
|
||||
on_metainfo_updated();
|
||||
|
||||
got_metainfo_.emit(this);
|
||||
got_metainfo_(this);
|
||||
session->onMetadataCompleted(this);
|
||||
set_dirty();
|
||||
mark_edited();
|
||||
@@ -1826,7 +1826,7 @@ void tr_torrent::recheck_completeness()
|
||||
set_location(download_dir(), true, nullptr);
|
||||
}
|
||||
|
||||
done_.emit(this, recent_change);
|
||||
done_(this, recent_change);
|
||||
}
|
||||
|
||||
session->onTorrentCompletenessChanged(this, completeness_, was_running);
|
||||
@@ -1960,7 +1960,7 @@ void tr_torrent::set_file_priorities(tr_file_index_t const* files, tr_file_index
|
||||
[this, priority](tr_file_index_t file) { return priority != file_priorities_.file_priority(file); }))
|
||||
{
|
||||
file_priorities_.set(files, file_count, priority);
|
||||
priority_changed_.emit(this, files, file_count, priority);
|
||||
priority_changed_(this, files, file_count, priority);
|
||||
set_dirty();
|
||||
mark_changed();
|
||||
}
|
||||
@@ -2052,7 +2052,7 @@ void tr_torrent::on_tracker_response(tr_tracker_event const* event)
|
||||
case tr_tracker_event::Type::Counts:
|
||||
if (is_private() && (event->leechers == 0 || event->downloaders == 0))
|
||||
{
|
||||
swarm_is_all_upload_only_.emit(this);
|
||||
swarm_is_all_upload_only_(this);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2163,7 +2163,7 @@ void tr_torrent::on_file_completed(tr_file_index_t const file)
|
||||
|
||||
void tr_torrent::on_piece_completed(tr_piece_index_t const piece)
|
||||
{
|
||||
piece_completed_.emit(this, piece);
|
||||
piece_completed_(this, piece);
|
||||
|
||||
// bookkeeping
|
||||
set_needs_completeness_check();
|
||||
@@ -2192,7 +2192,7 @@ void tr_torrent::on_piece_failed(tr_piece_index_t const piece)
|
||||
auto const n = piece_size(piece);
|
||||
bytes_corrupt_ += n;
|
||||
bytes_downloaded_.reduce(n);
|
||||
got_bad_piece_.emit(this, piece);
|
||||
got_bad_piece_(this, piece);
|
||||
set_has_piece(piece, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <sigslot/signal.hpp>
|
||||
|
||||
#include "libtransmission/transmission.h"
|
||||
|
||||
#include "libtransmission/announce-list.h"
|
||||
@@ -31,7 +33,6 @@
|
||||
#include "libtransmission/file-piece-map.h"
|
||||
#include "libtransmission/interned-string.h"
|
||||
#include "libtransmission/log.h"
|
||||
#include "libtransmission/observable.h"
|
||||
#include "libtransmission/session.h"
|
||||
#include "libtransmission/torrent-files.h"
|
||||
#include "libtransmission/torrent-magnet.h"
|
||||
@@ -438,7 +439,7 @@ struct tr_torrent
|
||||
if (priority != file_priorities_.file_priority(file))
|
||||
{
|
||||
file_priorities_.set(file, priority);
|
||||
priority_changed_.emit(this, &file, 1U, priority);
|
||||
priority_changed_(this, &file, 1U, priority);
|
||||
set_dirty();
|
||||
mark_changed();
|
||||
}
|
||||
@@ -768,7 +769,7 @@ struct tr_torrent
|
||||
session->flush_torrent_files(id());
|
||||
}
|
||||
sequential_download_ = is_sequential;
|
||||
sequential_download_changed_.emit(this, is_sequential);
|
||||
sequential_download_changed_(this, is_sequential);
|
||||
set_dirty();
|
||||
}
|
||||
}
|
||||
@@ -784,7 +785,7 @@ struct tr_torrent
|
||||
if (is_valid && piece != sequential_download_from_piece_)
|
||||
{
|
||||
sequential_download_from_piece_ = piece;
|
||||
sequential_download_from_piece_changed_.emit(this, piece);
|
||||
sequential_download_from_piece_changed_(this, piece);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1012,18 +1013,18 @@ struct tr_torrent
|
||||
|
||||
// ---
|
||||
|
||||
tr::SimpleObservable<tr_torrent*, bool /*because_downloaded_last_piece*/> done_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t> got_bad_piece_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t> piece_completed_;
|
||||
tr::SimpleObservable<tr_torrent*> doomed_;
|
||||
tr::SimpleObservable<tr_torrent*> got_metainfo_;
|
||||
tr::SimpleObservable<tr_torrent*> started_;
|
||||
tr::SimpleObservable<tr_torrent*> stopped_;
|
||||
tr::SimpleObservable<tr_torrent*> swarm_is_all_upload_only_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, bool> files_wanted_changed_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, tr_priority_t> priority_changed_;
|
||||
tr::SimpleObservable<tr_torrent*, bool> sequential_download_changed_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t> sequential_download_from_piece_changed_;
|
||||
sigslot::signal<tr_torrent*, bool /*because_downloaded_last_piece*/> done_;
|
||||
sigslot::signal<tr_torrent*, tr_piece_index_t> got_bad_piece_;
|
||||
sigslot::signal<tr_torrent*, tr_piece_index_t> piece_completed_;
|
||||
sigslot::signal<tr_torrent*> doomed_;
|
||||
sigslot::signal<tr_torrent*> got_metainfo_;
|
||||
sigslot::signal<tr_torrent*> started_;
|
||||
sigslot::signal<tr_torrent*> stopped_;
|
||||
sigslot::signal<tr_torrent*> swarm_is_all_upload_only_;
|
||||
sigslot::signal<tr_torrent*, tr_file_index_t const*, tr_file_index_t, bool> files_wanted_changed_;
|
||||
sigslot::signal<tr_torrent*, tr_file_index_t const*, tr_file_index_t, tr_priority_t> priority_changed_;
|
||||
sigslot::signal<tr_torrent*, bool> sequential_download_changed_;
|
||||
sigslot::signal<tr_torrent*, tr_piece_index_t> sequential_download_from_piece_changed_;
|
||||
|
||||
CumulativeCount bytes_corrupt_;
|
||||
CumulativeCount bytes_downloaded_;
|
||||
@@ -1260,7 +1261,7 @@ private:
|
||||
|
||||
files_wanted_.set(files, n_files, wanted);
|
||||
completion_.invalidate_size_when_done();
|
||||
files_wanted_changed_.emit(this, files, n_files, wanted);
|
||||
files_wanted_changed_(this, files, n_files, wanted);
|
||||
|
||||
if (!is_bootstrapping)
|
||||
{
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#include <array>
|
||||
#include <cstddef> // size_t
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#define LIBTRANSMISSION_PEER_MODULE
|
||||
@@ -33,12 +33,7 @@ protected:
|
||||
bool is_sequential_download_ = false;
|
||||
tr_piece_index_t sequential_download_from_piece_ = 0;
|
||||
|
||||
PeerMgrWishlistTest& parent_;
|
||||
|
||||
explicit MockMediator(PeerMgrWishlistTest& parent)
|
||||
: parent_{ parent }
|
||||
{
|
||||
}
|
||||
MockMediator() = default;
|
||||
|
||||
[[nodiscard]] bool client_has_block(tr_block_index_t block) const override
|
||||
{
|
||||
@@ -84,114 +79,8 @@ protected:
|
||||
{
|
||||
return piece_priority_[piece];
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_files_wanted_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, bool>::Observer observer) override
|
||||
{
|
||||
return parent_.files_wanted_changed_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_peer_disconnect(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&, tr_bitfield const&>::Observer observer) override
|
||||
{
|
||||
return parent_.peer_disconnect_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_got_bad_piece(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) override
|
||||
{
|
||||
return parent_.got_bad_piece_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_got_bitfield(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&>::Observer observer) override
|
||||
{
|
||||
return parent_.got_bitfield_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_got_block(
|
||||
tr::SimpleObservable<tr_torrent*, tr_block_index_t>::Observer observer) override
|
||||
{
|
||||
return parent_.got_block_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_got_choke(
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&>::Observer observer) override
|
||||
{
|
||||
return parent_.got_choke_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_got_have(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) override
|
||||
{
|
||||
return parent_.got_have_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_got_have_all(tr::SimpleObservable<tr_torrent*>::Observer observer) override
|
||||
{
|
||||
return parent_.got_have_all_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_got_reject(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t>::Observer observer) override
|
||||
{
|
||||
return parent_.got_reject_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_piece_completed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) override
|
||||
{
|
||||
return parent_.piece_completed_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_priority_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, tr_priority_t>::Observer observer)
|
||||
override
|
||||
{
|
||||
return parent_.priority_changed_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_sent_cancel(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t>::Observer observer) override
|
||||
{
|
||||
return parent_.sent_cancel_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_sent_request(
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_span_t>::Observer observer) override
|
||||
{
|
||||
return parent_.sent_request_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_sequential_download_changed(
|
||||
tr::SimpleObservable<tr_torrent*, bool>::Observer observer) override
|
||||
{
|
||||
return parent_.sequential_download_changed_.observe(std::move(observer));
|
||||
}
|
||||
|
||||
[[nodiscard]] tr::ObserverTag observe_sequential_download_from_piece_changed(
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t>::Observer observer) override
|
||||
{
|
||||
return parent_.sequential_download_from_piece_changed_.observe(std::move(observer));
|
||||
}
|
||||
};
|
||||
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, bool> files_wanted_changed_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&, tr_bitfield const&> peer_disconnect_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t> got_bad_piece_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&> got_bitfield_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_block_index_t> got_block_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_bitfield const&> got_choke_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t> got_have_;
|
||||
tr::SimpleObservable<tr_torrent*> got_have_all_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t> got_reject_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_index_t> sent_cancel_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_peer*, tr_block_span_t> sent_request_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t> piece_completed_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_file_index_t const*, tr_file_index_t, tr_priority_t> priority_changed_;
|
||||
tr::SimpleObservable<tr_torrent*, bool> sequential_download_changed_;
|
||||
tr::SimpleObservable<tr_torrent*, tr_piece_index_t> sequential_download_from_piece_changed_;
|
||||
|
||||
static auto constexpr PeerHasAllPieces = [](tr_piece_index_t)
|
||||
{
|
||||
return true;
|
||||
@@ -200,7 +89,7 @@ protected:
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, doesNotRequestPiecesThatAreNotWanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -224,7 +113,7 @@ TEST_F(PeerMgrWishlistTest, doesNotRequestPiecesThatAreNotWanted)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, doesNotRequestPiecesThatClientHas)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -254,7 +143,7 @@ TEST_F(PeerMgrWishlistTest, doesNotRequestPiecesThatClientHas)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, onlyRequestBlocksThePeerHas)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -294,7 +183,7 @@ TEST_F(PeerMgrWishlistTest, onlyRequestBlocksThePeerHas)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, doesNotRequestSameBlockTwice)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -316,7 +205,7 @@ TEST_F(PeerMgrWishlistTest, doesNotRequestSameBlockTwice)
|
||||
|
||||
// but we've already requested blocks [0..10) from this peer,
|
||||
// so we don't want to send repeated requests
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 10 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 10 });
|
||||
|
||||
// even if we ask wishlist for all the blocks,
|
||||
// it should omit blocks [0..10) from the return set
|
||||
@@ -333,9 +222,9 @@ TEST_F(PeerMgrWishlistTest, doesNotRequestSameBlockTwice)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, sequentialDownload)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -397,9 +286,9 @@ TEST_F(PeerMgrWishlistTest, sequentialDownload)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, sequentialDownloadFromPiece)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: four pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -452,7 +341,7 @@ TEST_F(PeerMgrWishlistTest, sequentialDownloadFromPiece)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, doesNotRequestTooManyBlocks)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -484,9 +373,9 @@ TEST_F(PeerMgrWishlistTest, doesNotRequestTooManyBlocks)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, prefersHighPriorityPieces)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -533,9 +422,9 @@ TEST_F(PeerMgrWishlistTest, prefersHighPriorityPieces)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, prefersNearlyCompletePieces)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, same size
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -609,9 +498,9 @@ TEST_F(PeerMgrWishlistTest, prefersNearlyCompletePieces)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, prefersRarerPieces)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -671,9 +560,9 @@ TEST_F(PeerMgrWishlistTest, prefersRarerPieces)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, peerDisconnectDecrementsReplication)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -698,7 +587,7 @@ TEST_F(PeerMgrWishlistTest, peerDisconnectDecrementsReplication)
|
||||
// first piece should be the rarest piece according to the cache
|
||||
auto have = tr_bitfield{ 3 };
|
||||
have.set(0);
|
||||
peer_disconnect_.emit(nullptr, have, tr_bitfield{ 300 });
|
||||
wishlist.on_peer_disconnect(have, tr_bitfield{ 300 });
|
||||
|
||||
// this is what a real mediator should return at this point:
|
||||
// mediator.piece_replication_[0] = 1;
|
||||
@@ -744,9 +633,9 @@ TEST_F(PeerMgrWishlistTest, peerDisconnectDecrementsReplication)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, gotBadPieceResetsPiece)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -768,16 +657,16 @@ TEST_F(PeerMgrWishlistTest, gotBadPieceResetsPiece)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// we already requested 50 blocks each from every piece
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 50 });
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 100, .end = 150 });
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 200, .end = 250 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 50 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 100, .end = 150 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 200, .end = 250 });
|
||||
|
||||
// we request the rest of a random piece
|
||||
auto const random_piece = tr_rand_int(3U);
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = (random_piece * 100U) + 50U, .end = (random_piece + 1U) * 100U });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = (random_piece * 100U) + 50U, .end = (random_piece + 1U) * 100U });
|
||||
|
||||
// the random piece turns out to be corrupted, so all blocks should be missing again
|
||||
got_bad_piece_.emit(nullptr, random_piece);
|
||||
wishlist.on_got_bad_piece(random_piece);
|
||||
|
||||
return std::pair{ wishlist.next(n_wanted, PeerHasAllPieces), random_piece };
|
||||
};
|
||||
@@ -803,9 +692,9 @@ TEST_F(PeerMgrWishlistTest, gotBadPieceResetsPiece)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, gotBitfieldIncrementsReplication)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -830,7 +719,7 @@ TEST_F(PeerMgrWishlistTest, gotBitfieldIncrementsReplication)
|
||||
// third piece should be the rarest piece according to the cache
|
||||
auto have = tr_bitfield{ 3 };
|
||||
have.set_span(0, 2);
|
||||
got_bitfield_.emit(nullptr, have);
|
||||
wishlist.on_got_bitfield(have);
|
||||
|
||||
// this is what a real mediator should return at this point:
|
||||
// mediator.piece_replication_[0] = 3;
|
||||
@@ -877,9 +766,9 @@ TEST_F(PeerMgrWishlistTest, gotBitfieldIncrementsReplication)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, sentRequestsResortsPiece)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -902,7 +791,7 @@ TEST_F(PeerMgrWishlistTest, sentRequestsResortsPiece)
|
||||
|
||||
// we requested block 0 from someone, the wishlist should resort the
|
||||
// candidate list cache
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 1 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 1 });
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -945,9 +834,9 @@ TEST_F(PeerMgrWishlistTest, sentRequestsResortsPiece)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, gotBlockResortsPiece)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -970,7 +859,7 @@ TEST_F(PeerMgrWishlistTest, gotBlockResortsPiece)
|
||||
|
||||
// we received block 0 from someone, the wishlist should resort the
|
||||
// candidate list cache
|
||||
got_block_.emit(nullptr, 0);
|
||||
wishlist.on_got_block(0);
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -1013,9 +902,9 @@ TEST_F(PeerMgrWishlistTest, gotBlockResortsPiece)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, gotHaveIncrementsReplication)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1038,7 +927,7 @@ TEST_F(PeerMgrWishlistTest, gotHaveIncrementsReplication)
|
||||
|
||||
// a peer sent a "Have" message for the first piece, now the
|
||||
// first piece should be the least rare piece according to the cache
|
||||
got_have_.emit(nullptr, 0);
|
||||
wishlist.on_got_have(0);
|
||||
|
||||
// this is what a real mediator should return at this point:
|
||||
// mediator.piece_replication_[0] = 3;
|
||||
@@ -1084,9 +973,9 @@ TEST_F(PeerMgrWishlistTest, gotHaveIncrementsReplication)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, gotChokeResetsRequestedBlocks)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1108,12 +997,12 @@ TEST_F(PeerMgrWishlistTest, gotChokeResetsRequestedBlocks)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// we have active requests to the first 250 blocks
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 250 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 250 });
|
||||
|
||||
// a peer sent a "Choke" message, which cancels some active requests
|
||||
tr_bitfield requested{ 300 };
|
||||
requested.set_span(0, 10);
|
||||
got_choke_.emit(nullptr, requested);
|
||||
wishlist.on_got_choke(requested);
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -1141,9 +1030,9 @@ TEST_F(PeerMgrWishlistTest, gotChokeResetsRequestedBlocks)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, gotHaveAllDoesNotAffectOrder)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1165,7 +1054,7 @@ TEST_F(PeerMgrWishlistTest, gotHaveAllDoesNotAffectOrder)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// a peer sent a "Have All" message, this should not affect the piece order
|
||||
got_have_all_.emit(nullptr);
|
||||
wishlist.on_got_have_all();
|
||||
|
||||
// this is what a real mediator should return at this point:
|
||||
// mediator.piece_replication_[0] = 2;
|
||||
@@ -1212,9 +1101,9 @@ TEST_F(PeerMgrWishlistTest, gotHaveAllDoesNotAffectOrder)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, gotRejectResetsBlock)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1236,7 +1125,7 @@ TEST_F(PeerMgrWishlistTest, gotRejectResetsBlock)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// we have active requests to the first 250 blocks
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 250 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 250 });
|
||||
|
||||
// a peer sent some "Reject" messages, which cancels active requests
|
||||
auto rejected_bitfield = tr_bitfield{ 300 };
|
||||
@@ -1244,7 +1133,7 @@ TEST_F(PeerMgrWishlistTest, gotRejectResetsBlock)
|
||||
{
|
||||
auto const block = tr_rand_int(250U);
|
||||
rejected_bitfield.set(block);
|
||||
got_reject_.emit(nullptr, nullptr, block);
|
||||
wishlist.on_got_reject(block);
|
||||
}
|
||||
|
||||
return std::pair{ wishlist.next(n_wanted, PeerHasAllPieces), std::move(rejected_bitfield) };
|
||||
@@ -1275,9 +1164,9 @@ TEST_F(PeerMgrWishlistTest, gotRejectResetsBlock)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, gotRejectResortsPiece)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: two pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1295,12 +1184,12 @@ TEST_F(PeerMgrWishlistTest, gotRejectResortsPiece)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// we have active requests to the first 50 blocks of each piece
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 50 });
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 100, .end = 150 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 50 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 100, .end = 150 });
|
||||
|
||||
// a peer sent a "Reject" messages, which cancels active requests
|
||||
auto const random_piece = tr_rand_int(2U);
|
||||
got_reject_.emit(nullptr, nullptr, mediator.block_span_[random_piece].begin);
|
||||
wishlist.on_got_reject(mediator.block_span_[random_piece].begin);
|
||||
|
||||
return std::pair{ wishlist.next(n_wanted, PeerHasAllPieces), 1U - random_piece };
|
||||
};
|
||||
@@ -1325,9 +1214,9 @@ TEST_F(PeerMgrWishlistTest, gotRejectResortsPiece)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, sentCancelResetsBlocks)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1349,7 +1238,7 @@ TEST_F(PeerMgrWishlistTest, sentCancelResetsBlocks)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// we have active requests to the first 250 blocks
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 250 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 250 });
|
||||
|
||||
// we sent some "Cancel" messages
|
||||
auto cancelled_bitfield = tr_bitfield{ 300 };
|
||||
@@ -1357,7 +1246,7 @@ TEST_F(PeerMgrWishlistTest, sentCancelResetsBlocks)
|
||||
{
|
||||
auto const block = tr_rand_int(250U);
|
||||
cancelled_bitfield.set(block);
|
||||
sent_cancel_.emit(nullptr, nullptr, block);
|
||||
wishlist.on_sent_cancel(block);
|
||||
}
|
||||
|
||||
return std::pair{ wishlist.next(n_wanted, PeerHasAllPieces), std::move(cancelled_bitfield) };
|
||||
@@ -1388,9 +1277,9 @@ TEST_F(PeerMgrWishlistTest, sentCancelResetsBlocks)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, doesNotRequestBlockAfterBlockCompleted)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1412,7 +1301,7 @@ TEST_F(PeerMgrWishlistTest, doesNotRequestBlockAfterBlockCompleted)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// we sent "Request" messages
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 120 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 120 });
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -1439,7 +1328,7 @@ TEST_F(PeerMgrWishlistTest, doesNotRequestBlockAfterBlockCompleted)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, doesNotRequestPieceAfterPieceCompleted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, piece 0 is nearly complete
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1462,14 +1351,14 @@ TEST_F(PeerMgrWishlistTest, doesNotRequestPieceAfterPieceCompleted)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// we just completed piece 0
|
||||
sent_request_.emit(nullptr, nullptr, mediator.block_span_[0]);
|
||||
wishlist.on_sent_request(mediator.block_span_[0]);
|
||||
for (auto [block, end] = mediator.block_span_[0]; block < end; ++block)
|
||||
{
|
||||
mediator.client_has_block_.insert(block);
|
||||
got_block_.emit(nullptr, block);
|
||||
wishlist.on_got_block(block);
|
||||
}
|
||||
mediator.client_has_piece_.insert(0);
|
||||
piece_completed_.emit(nullptr, 0);
|
||||
wishlist.on_piece_completed(0);
|
||||
|
||||
// receiving a "piece_completed" signal removes the piece from the
|
||||
// wishlist's cache, its blocks should not be in the return set.
|
||||
@@ -1486,9 +1375,9 @@ TEST_F(PeerMgrWishlistTest, doesNotRequestPieceAfterPieceCompleted)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, settingPriorityResortsCandidates)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1512,7 +1401,7 @@ TEST_F(PeerMgrWishlistTest, settingPriorityResortsCandidates)
|
||||
// a file priority changed, the cache should be rebuilt.
|
||||
// let's say the file was in piece 1
|
||||
mediator.piece_priority_[1] = TR_PRI_HIGH;
|
||||
priority_changed_.emit(nullptr, nullptr, 0U, TR_PRI_HIGH);
|
||||
wishlist.on_priority_changed();
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -1540,9 +1429,9 @@ TEST_F(PeerMgrWishlistTest, settingPriorityResortsCandidates)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, settingSequentialDownloadResortsCandidates)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: three pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1566,7 +1455,7 @@ TEST_F(PeerMgrWishlistTest, settingSequentialDownloadResortsCandidates)
|
||||
// the sequential download setting was changed,
|
||||
// the cache should be rebuilt
|
||||
mediator.is_sequential_download_ = true;
|
||||
sequential_download_changed_.emit(nullptr, true);
|
||||
wishlist.on_sequential_download_changed();
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -1609,9 +1498,9 @@ TEST_F(PeerMgrWishlistTest, settingSequentialDownloadResortsCandidates)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, sequentialDownloadFromPieceResortsCandidates)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: four pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1636,9 +1525,9 @@ TEST_F(PeerMgrWishlistTest, sequentialDownloadFromPieceResortsCandidates)
|
||||
|
||||
// we enabled sequential download, from piece 2
|
||||
mediator.is_sequential_download_ = true;
|
||||
sequential_download_changed_.emit(nullptr, true);
|
||||
wishlist.on_sequential_download_changed();
|
||||
mediator.sequential_download_from_piece_ = 2;
|
||||
sequential_download_from_piece_changed_.emit(nullptr, 2);
|
||||
wishlist.on_sequential_download_from_piece_changed();
|
||||
|
||||
// the sequential download setting was changed,
|
||||
// the candidate list should be resorted
|
||||
@@ -1671,9 +1560,9 @@ TEST_F(PeerMgrWishlistTest, sequentialDownloadFromPieceResortsCandidates)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, setFileWantedUpdatesCandidateListAdd)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: four pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1697,7 +1586,7 @@ TEST_F(PeerMgrWishlistTest, setFileWantedUpdatesCandidateListAdd)
|
||||
// now we want the file that consists of piece 2 and piece 3 also
|
||||
mediator.client_wants_piece_.insert(2);
|
||||
mediator.client_wants_piece_.insert(3);
|
||||
files_wanted_changed_.emit(nullptr, nullptr, 0, true);
|
||||
wishlist.on_files_wanted_changed();
|
||||
|
||||
// a candidate should be inserted into the wishlist for
|
||||
// piece 2 and piece 3
|
||||
@@ -1727,9 +1616,9 @@ TEST_F(PeerMgrWishlistTest, setFileWantedUpdatesCandidateListAdd)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, setFileWantedUpdatesCandidateListAddHad)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: four pieces
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1757,7 +1646,7 @@ TEST_F(PeerMgrWishlistTest, setFileWantedUpdatesCandidateListAddHad)
|
||||
// now we want piece 2 and piece 3
|
||||
mediator.client_wants_piece_.insert(2);
|
||||
mediator.client_wants_piece_.insert(3);
|
||||
files_wanted_changed_.emit(nullptr, nullptr, 0, true);
|
||||
wishlist.on_files_wanted_changed();
|
||||
|
||||
// the candidate list should remain unchanged
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
@@ -1786,9 +1675,9 @@ TEST_F(PeerMgrWishlistTest, setFileWantedUpdatesCandidateListAddHad)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, setFileWantedUpdatesCandidateListRemove)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: four pieces, all missing
|
||||
mediator.block_span_[0] = { .begin = 0, .end = 100 };
|
||||
@@ -1814,7 +1703,7 @@ TEST_F(PeerMgrWishlistTest, setFileWantedUpdatesCandidateListRemove)
|
||||
// we no longer want the file that consists of piece 2 and piece 3
|
||||
mediator.client_wants_piece_.erase(2);
|
||||
mediator.client_wants_piece_.erase(3);
|
||||
files_wanted_changed_.emit(nullptr, nullptr, 0, true);
|
||||
wishlist.on_files_wanted_changed();
|
||||
|
||||
// the candidate objects for piece 2 and piece 3 should be removed
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
@@ -1843,9 +1732,9 @@ TEST_F(PeerMgrWishlistTest, setFileWantedUpdatesCandidateListRemove)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrent)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each, all missing
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -1898,9 +1787,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrent)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentPartiallyCompletedPiece)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -1969,9 +1858,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentPartiallyCompletedPiece)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentPartiallyCompleted)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -2025,9 +1914,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentPartiallyCompleted)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentGotBadPiece)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -2054,11 +1943,11 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentGotBadPiece)
|
||||
// requested all blocks and "download" piece 1,
|
||||
// as well as parts of piece 0 and piece 2 that
|
||||
// is next to piece 1
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 134 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 134 });
|
||||
for (auto block = mediator.block_span_[0].end - 10; block < mediator.block_span_[1].end + 10; ++block)
|
||||
{
|
||||
mediator.client_has_block_.insert(block);
|
||||
got_block_.emit(nullptr, block);
|
||||
wishlist.on_got_block(block);
|
||||
}
|
||||
|
||||
// piece 1 turned out to be corrupt, needs to be re-downloaded
|
||||
@@ -2066,7 +1955,7 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentGotBadPiece)
|
||||
{
|
||||
mediator.client_has_block_.erase(block);
|
||||
}
|
||||
got_bad_piece_.emit(nullptr, 1);
|
||||
wishlist.on_got_bad_piece(1);
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -2093,9 +1982,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentGotBadPiece)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentGotBadPieceSurroundingCompleted)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -2120,23 +2009,23 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentGotBadPieceSurroundingCompleted)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// pieces 0, 2 completed normally, piece 3 has pending requests
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 134 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 134 });
|
||||
for (tr_block_index_t block = 0; block < 120; ++block)
|
||||
{
|
||||
mediator.client_has_block_.insert(block);
|
||||
got_block_.emit(nullptr, block);
|
||||
wishlist.on_got_block(block);
|
||||
}
|
||||
mediator.client_has_piece_.insert(0);
|
||||
piece_completed_.emit(nullptr, 0);
|
||||
wishlist.on_piece_completed(0);
|
||||
mediator.client_has_piece_.insert(2);
|
||||
piece_completed_.emit(nullptr, 2);
|
||||
wishlist.on_piece_completed(2);
|
||||
|
||||
// piece 1 turned out to be corrupt, needs to be re-downloaded
|
||||
for (auto [block, end] = mediator.block_span_[1]; block < end; ++block)
|
||||
{
|
||||
mediator.client_has_block_.erase(block);
|
||||
}
|
||||
got_bad_piece_.emit(nullptr, 1);
|
||||
wishlist.on_got_bad_piece(1);
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -2163,9 +2052,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentGotBadPieceSurroundingCompleted)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentGot2ConsectutiveBadPieces)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -2190,28 +2079,28 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentGot2ConsectutiveBadPieces)
|
||||
auto wishlist = Wishlist{ mediator };
|
||||
|
||||
// pieces 0, 3 completed normally
|
||||
sent_request_.emit(nullptr, nullptr, { .begin = 0, .end = 134 });
|
||||
wishlist.on_sent_request(tr_block_span_t{ .begin = 0, .end = 134 });
|
||||
for (tr_block_index_t block = 0; block < 134; ++block)
|
||||
{
|
||||
mediator.client_has_block_.insert(block);
|
||||
got_block_.emit(nullptr, block);
|
||||
wishlist.on_got_block(block);
|
||||
}
|
||||
mediator.client_has_piece_.insert(0);
|
||||
piece_completed_.emit(nullptr, 0);
|
||||
wishlist.on_piece_completed(0);
|
||||
mediator.client_has_piece_.insert(3);
|
||||
piece_completed_.emit(nullptr, 3);
|
||||
wishlist.on_piece_completed(3);
|
||||
|
||||
// pieces 1, 2 turned out to be corrupt, need to be re-downloaded
|
||||
for (auto [block, end] = mediator.block_span_[1]; block < end; ++block)
|
||||
{
|
||||
mediator.client_has_block_.erase(block);
|
||||
}
|
||||
got_bad_piece_.emit(nullptr, 1);
|
||||
wishlist.on_got_bad_piece(1);
|
||||
for (auto [block, end] = mediator.block_span_[2]; block < end; ++block)
|
||||
{
|
||||
mediator.client_has_block_.erase(block);
|
||||
}
|
||||
got_bad_piece_.emit(nullptr, 2);
|
||||
wishlist.on_got_bad_piece(2);
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -2243,9 +2132,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentGot2ConsectutiveBadPieces)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentPartiallyWanted)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each, all missing
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -2296,9 +2185,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentPartiallyWanted)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentDeselectedPiece)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each, all missing
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -2325,7 +2214,7 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentDeselectedPiece)
|
||||
// we don't want piece 1 anymore
|
||||
tr_file_index_t constexpr Deselected = 1;
|
||||
mediator.client_wants_piece_.erase(Deselected);
|
||||
files_wanted_changed_.emit(nullptr, &Deselected, 1, false);
|
||||
wishlist.on_files_wanted_changed();
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -2356,9 +2245,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentDeselectedPiece)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentDeselected2ConsecutivePieces)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each, all missing
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -2388,7 +2277,7 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentDeselected2ConsecutivePieces)
|
||||
{
|
||||
mediator.client_wants_piece_.erase(idx);
|
||||
}
|
||||
files_wanted_changed_.emit(nullptr, std::data(Deselected), std::size(Deselected), false);
|
||||
wishlist.on_files_wanted_changed();
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -2419,9 +2308,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentDeselected2ConsecutivePieces)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentSelectedPiece)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each, all missing
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -2447,7 +2336,7 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentSelectedPiece)
|
||||
// we want piece 1 now
|
||||
tr_file_index_t constexpr Selected = 1;
|
||||
mediator.client_wants_piece_.insert(Selected);
|
||||
files_wanted_changed_.emit(nullptr, &Selected, 1, true);
|
||||
wishlist.on_files_wanted_changed();
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
@@ -2476,9 +2365,9 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentSelectedPiece)
|
||||
|
||||
TEST_F(PeerMgrWishlistTest, unalignedTorrentSelected2ConsecutivePieces)
|
||||
{
|
||||
auto const get_spans = [this](size_t n_wanted)
|
||||
auto const get_spans = [](size_t n_wanted)
|
||||
{
|
||||
auto mediator = MockMediator{ *this };
|
||||
auto mediator = MockMediator{};
|
||||
|
||||
// setup: 4 pieces, (100 / 3 * 16) KiB each, all missing
|
||||
// N.B. only the boundary of piece 2 and 3 is aligned
|
||||
@@ -2506,7 +2395,7 @@ TEST_F(PeerMgrWishlistTest, unalignedTorrentSelected2ConsecutivePieces)
|
||||
{
|
||||
mediator.client_wants_piece_.insert(idx);
|
||||
}
|
||||
files_wanted_changed_.emit(nullptr, std::data(Selected), std::size(Selected), true);
|
||||
wishlist.on_files_wanted_changed();
|
||||
|
||||
return wishlist.next(n_wanted, PeerHasAllPieces);
|
||||
};
|
||||
|
||||
1
third-party/sigslot
vendored
Submodule
1
third-party/sigslot
vendored
Submodule
Submodule third-party/sigslot added at b588b791b9
Reference in New Issue
Block a user