diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9229b6899..d35d54152 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,6 +2,7 @@ project(libtorrent-examples) set(single_file_examples simple_client + custom_storage stats_counters dump_torrent make_torrent diff --git a/examples/Jamfile b/examples/Jamfile index 312531397..670499fc6 100644 --- a/examples/Jamfile +++ b/examples/Jamfile @@ -18,6 +18,7 @@ project client_test # C4268: 'identifier' : 'const' static/global data initialized # with compiler generated default constructor fills the object with zeros msvc:/wd4268 + msvc:/wd4373 : default-build static ; @@ -25,6 +26,7 @@ project client_test exe client_test : client_test.cpp print.cpp torrent_view.cpp session_view.cpp ; exe simple_client : simple_client.cpp ; +exe custom_storage : custom_storage.cpp ; exe bt-get : bt-get.cpp ; exe bt-get2 : bt-get2.cpp ; exe stats_counters : stats_counters.cpp ; diff --git a/examples/Makefile.am b/examples/Makefile.am index 3fc5754fe..9d31acde0 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -4,6 +4,7 @@ example_programs = \ dump_torrent \ make_torrent \ simple_client \ + custom_storage \ upnp_test \ bt_get \ bt_get2 \ @@ -23,6 +24,7 @@ bt_get2_SOURCES = bt-get2.cpp dump_torrent_SOURCES = dump_torrent.cpp make_torrent_SOURCES = make_torrent.cpp simple_client_SOURCES = simple_client.cpp +custom_storage_SOURCES = custom_storage.cpp connection_tester_SOURCES = connection_tester.cpp upnp_test_SOURCES = upnp_test.cpp diff --git a/examples/custom_storage.cpp b/examples/custom_storage.cpp new file mode 100644 index 000000000..8e4424223 --- /dev/null +++ b/examples/custom_storage.cpp @@ -0,0 +1,125 @@ +/* + +Copyright (c) 2019, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include "libtorrent/entry.hpp" +#include "libtorrent/bencode.hpp" +#include "libtorrent/session.hpp" +#include "libtorrent/torrent_info.hpp" +#include "libtorrent/fwd.hpp" + +#include + +// -- example begin +struct temp_storage : lt::storage_interface +{ + explicit temp_storage(lt::file_storage const& fs) : lt::storage_interface(fs) {} + void initialize(lt::storage_error&) override {} + bool has_any_file(lt::storage_error&) override { return false; } + virtual void set_file_priority(lt::aux::vector& + , lt::storage_error&) override {} + int readv(lt::span bufs, lt::piece_index_t piece + , int offset, lt::open_mode_t, lt::storage_error&) override + { + auto const i = m_file_data.find(piece); + if (i == m_file_data.end()) return 0; + if (int(i->second.size()) <= offset) return 0; + lt::iovec_t data{ i->second.data() + offset, int(i->second.size() - offset) }; + int ret = 0; + for (lt::iovec_t const& b : bufs) { + int const to_copy = std::min(int(b.size()), int(data.size())); + memcpy(b.data(), data.data(), to_copy); + data = data.subspan(to_copy); + ret += to_copy; + if (data.empty()) break; + } + return ret; + } + int writev(lt::span bufs + , lt::piece_index_t const piece, int offset, lt::open_mode_t, lt::storage_error&) override + { + auto& data = m_file_data[piece]; + int ret = 0; + for (auto& b : bufs) { + if (int(data.size()) < offset + b.size()) data.resize(offset + b.size()); + std::memcpy(data.data() + offset, b.data(), b.size()); + offset += int(b.size()); + ret += int(b.size()); + } + return ret; + } + void rename_file(lt::file_index_t, std::string const&, lt::storage_error&) override + { assert(false); } + lt::status_t move_storage(std::string const& + , lt::move_flags_t, lt::storage_error&) override { return lt::status_t::no_error; } + bool verify_resume_data(lt::add_torrent_params const& + , lt::aux::vector const& + , lt::storage_error&) override + { return false; } + void release_files(lt::storage_error&) override {} + void delete_files(lt::remove_flags_t, lt::storage_error&) override {} + + std::map> m_file_data; +}; + +lt::storage_interface* temp_storage_constructor(lt::storage_params const& params, lt::file_pool&) +{ + return new temp_storage(params.files); +} + +// -- example end + +int main(int argc, char* argv[]) try +{ + if (argc != 2) { + std::cerr << "usage: ./custom_storage torrent-file\n" + "to stop the client, press return.\n"; + return 1; + } + + lt::session s; + lt::add_torrent_params p; + p.storage = temp_storage_constructor; + p.save_path = "./"; + p.ti = std::make_shared(argv[1]); + s.add_torrent(p); + + // wait for the user to end + char a; + int ret = std::scanf("%c\n", &a); + (void)ret; // ignore + return 0; +} +catch (std::exception const& e) { + std::cerr << "ERROR: " << e.what() << "\n"; +} + diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index c055ced11..fe2e8f7b6 100644 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -67,64 +67,11 @@ POSSIBILITY OF SUCH DAMAGE. // ``std::map``, i.e. in RAM. It's not necessarily very useful in practice, but // illustrates the basics of implementing a custom storage. // -// .. code:: c++ -// -// struct temp_storage : storage_interface -// { -// temp_storage(file_storage const& fs) : storage_interface(fs) {} -// bool initialize(storage_error& se) override { return false; } -// bool has_any_file() override { return false; } -// int read(char* buf, int piece, int offset, int size) override -// { -// std::map>::const_iterator i = m_file_data.find(piece); -// if (i == m_file_data.end()) return 0; -// int available = i->second.size() - offset; -// if (available <= 0) return 0; -// if (available > size) available = size; -// memcpy(buf, &i->second[offset], available); -// return available; -// } -// int write(const char* buf, int piece, int offset, int size) override -// { -// std::vector& data = m_file_data[piece]; -// if (data.size() < offset + size) data.resize(offset + size); -// std::memcpy(&data[offset], buf, size); -// return size; -// } -// bool rename_file(file_index_t file, std::string const& new_name) override -// { assert(false); return false; } -// status_t move_storage(std::string const& save_path) override { return false; } -// bool verify_resume_data(add_torrent_params const& rd -// , std::vector const* links -// , storage_error& error) override { return false; } -// std::int64_t physical_offset(int piece, int offset) override -// { return piece * files().piece_length() + offset; }; -// sha1_hash hash_for_slot(int piece, partial_hash& ph, int piece_size) override -// { -// int left = piece_size - ph.offset; -// assert(left >= 0); -// if (left > 0) -// { -// std::vector& data = m_file_data[piece]; -// // if there are padding files, those blocks will be considered -// // completed even though they haven't been written to the storage. -// // in this case, just extend the piece buffer to its full size -// // and fill it with zeros. -// if (data.size() < piece_size) data.resize(piece_size, 0); -// ph.h.update(&data[ph.offset], left); -// } -// return ph.h.final(); -// } -// bool release_files() override { return false; } -// bool delete_files() override { return false; } -// -// std::map> m_file_data; -// }; -// -// storage_interface* temp_storage_constructor(storage_params const& params) -// { -// return new temp_storage(*params.files); -// } +// .. include:: ../examples/custom_storage.cpp +// :code: c++ +// :tab-width: 2 +// :start-after: -- example begin +// :end-before: // -- example end namespace libtorrent { namespace aux { struct session_settings; }