Remove torrent-based synchronization

This commit is contained in:
Alexander Bock
2019-07-18 12:10:49 +02:00
parent 66cd0413dd
commit 2fca9a2a2c
9 changed files with 1 additions and 761 deletions

View File

@@ -24,8 +24,6 @@
include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
option(OPENSPACE_MODULE_SYNC_USE_LIBTORRENT "Use libtorrent" OFF)
set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/syncmodule.h
${CMAKE_CURRENT_SOURCE_DIR}/syncs/httpsynchronization.h
@@ -42,48 +40,4 @@ set(SOURCE_FILES
)
source_group("Source Files" FILES ${SOURCE_FILES})
if (OPENSPACE_MODULE_SYNC_USE_LIBTORRENT)
set(HEADER_FILES
${HEADER_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/torrentclient.h
${CMAKE_CURRENT_SOURCE_DIR}/syncs/torrentsynchronization.h
)
set(SOURCE_FILES
${SOURCE_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/torrentclient.cpp
${CMAKE_CURRENT_SOURCE_DIR}/syncs/torrentsynchronization.cpp
)
endif ()
create_new_module("Sync" sync_module ${HEADER_FILES} ${SOURCE_FILES})
#####
# Libtorrent
#####
if (OPENSPACE_MODULE_SYNC_USE_LIBTORRENT)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(LIBTORRENT_encryption OFF CACHE BOOL "Use OpenSSL Encryption" FORCE)
set(LIBTORRENT_shared OFF CACHE BOOL "Use Libtorrent as shared library" FORCE)
include_external_library(
${sync_module}
torrent-rasterbar
${CMAKE_CURRENT_SOURCE_DIR}/ext/libtorrent
)
target_include_directories(
${sync_module}
SYSTEM PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/ext/libtorrent/include
)
target_compile_definitions(openspace-module-sync PUBLIC SYNC_USE_LIBTORRENT)
mark_as_advanced(LIBTORRENT_build_examples LIBTORRENT_build_tests
LIBTORRENT_deprecated-functions LIBTORRENT_dht LIBTORRENT_encryption
LIBTORRENT_exceptions LIBTORRENT_exceptions LIBTORRENT_libiconv
LIBTORRENT_logging LIBTORRENT_shared LIBTORRENT_static_runtime
)
endif () # OPENSPACE_MODULE_SYNC_USE_LIBTORRENT

View File

@@ -25,7 +25,6 @@
#include <modules/sync/syncmodule.h>
#include <modules/sync/syncs/httpsynchronization.h>
#include <modules/sync/syncs/torrentsynchronization.h>
#include <modules/sync/syncs/urlsynchronization.h>
#include <modules/sync/tasks/syncassettask.h>
#include <openspace/documentation/documentation.h>
@@ -87,19 +86,6 @@ void SyncModule::internalInitialize(const ghoul::Dictionary& configuration) {
}
);
#ifdef SYNC_USE_LIBTORRENT
fSynchronization->registerClass(
"TorrentSynchronization",
[this](bool, const ghoul::Dictionary& dictionary) {
return new TorrentSynchronization(
dictionary,
_synchronizationRoot,
_torrentClient
);
}
);
#endif // SYNC_USE_LIBTORRENT
fSynchronization->registerClass(
"UrlSynchronization",
[this](bool, const ghoul::Dictionary& dictionary) {
@@ -113,17 +99,6 @@ void SyncModule::internalInitialize(const ghoul::Dictionary& configuration) {
auto fTask = FactoryManager::ref().factory<Task>();
ghoul_assert(fTask, "No task factory existed");
fTask->registerClass<SyncAssetTask>("SyncAssetTask");
#ifdef SYNC_USE_LIBTORRENT
_torrentClient.initialize();
global::callback::deinitialize.emplace_back([&]() { _torrentClient.deinitialize(); });
#endif // SYNC_USE_LIBTORRENT
}
void SyncModule::internalDeinitialize() {
#ifdef SYNC_USE_LIBTORRENT
_torrentClient.deinitialize();
#endif // SYNC_USE_LIBTORRENT
}
std::string SyncModule::synchronizationRoot() const {
@@ -140,10 +115,7 @@ std::vector<std::string> SyncModule::httpSynchronizationRepositories() const {
std::vector<documentation::Documentation> SyncModule::documentations() const {
return {
HttpSynchronization::Documentation(),
#ifdef SYNC_USE_LIBTORRENT
TorrentSynchronization::Documentation()
#endif // SYNC_USE_LIBTORRENT
HttpSynchronization::Documentation()
};
}

View File

@@ -27,10 +27,6 @@
#include <openspace/util/openspacemodule.h>
#ifdef SYNC_USE_LIBTORRENT
#include <modules/sync/torrentclient.h>
#endif // SYNC_USE_LIBTORRENT
namespace openspace {
class SyncModule : public OpenSpaceModule {
@@ -44,20 +40,12 @@ public:
void addHttpSynchronizationRepository(std::string repository);
std::vector<std::string> httpSynchronizationRepositories() const;
#ifdef SYNC_USE_LIBTORRENT
TorrentClient& torrentClient();
#endif // SYNC_USE_LIBTORRENT
std::vector<documentation::Documentation> documentations() const override;
protected:
void internalInitialize(const ghoul::Dictionary& configuration) override;
void internalDeinitialize() override;
private:
#ifdef SYNC_USE_LIBTORRENT
TorrentClient _torrentClient;
#endif // SYNC_USE_LIBTORRENT
std::vector<std::string> _synchronizationRepositories;
std::string _synchronizationRoot;
};

View File

@@ -1,197 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2019 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/sync/syncs/torrentsynchronization.h>
#include <openspace/documentation/verifier.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/dictionary.h>
#include <fstream>
namespace {
constexpr const char* KeyIdentifier = "Identifier";
constexpr const char* KeyMagnet = "Magnet";
} // namespace
namespace openspace {
documentation::Documentation TorrentSynchronization::Documentation() {
using namespace openspace::documentation;
return {
"TorrentSynchronization",
"torrent_synchronization",
{
{
KeyIdentifier,
new StringVerifier,
Optional::No,
"A unique identifier for this torrent"
},
{
KeyMagnet,
new StringVerifier,
Optional::No,
"A magnet link identifying the torrent"
}
}
};
}
TorrentSynchronization::TorrentSynchronization(const ghoul::Dictionary& dict,
std::string synchronizationRoot,
TorrentClient& torrentClient)
: ResourceSynchronization(dict)
, _synchronizationRoot(std::move(synchronizationRoot))
, _torrentClient(torrentClient)
{
documentation::testSpecificationAndThrow(
Documentation(),
dict,
"TorrentSynchronization"
);
_identifier = dict.value<std::string>(KeyIdentifier);
_magnetLink = dict.value<std::string>(KeyMagnet);
}
TorrentSynchronization::~TorrentSynchronization() {
cancel();
}
std::string TorrentSynchronization::uniformResourceName() const {
const size_t begin = _magnetLink.find("=urn") + 1;
const size_t end = _magnetLink.find('&', begin);
std::string xs = _magnetLink.substr(
begin,
(end == std::string::npos) ? end : (end - begin)
);
std::transform(
xs.begin(),
xs.end(),
xs.begin(),
[](char x) { return (x == ':') ? '.' : x; }
);
return xs;
}
std::string TorrentSynchronization::directory() {
ghoul::filesystem::Directory d(
_synchronizationRoot +
ghoul::filesystem::FileSystem::PathSeparator +
"torrent" +
ghoul::filesystem::FileSystem::PathSeparator +
_identifier +
ghoul::filesystem::FileSystem::PathSeparator +
uniformResourceName()
);
return FileSys.absPath(d);
}
void TorrentSynchronization::start() {
if (_enabled) {
return;
}
begin();
if (hasSyncFile()) {
resolve();
}
_enabled = true;
try {
_torrentId = _torrentClient.addMagnetLink(
_magnetLink,
directory(),
[this](TorrentClient::TorrentProgress p) {
updateTorrentProgress(p);
}
);
} catch (const TorrentError& e) {
LERRORC(name(), e.message);
if (!isResolved()) {
reject();
}
}
}
void TorrentSynchronization::cancel() {
if (_enabled) {
_torrentClient.removeTorrent(_torrentId);
_enabled = false;
reset();
}
}
void TorrentSynchronization::clear() {
cancel();
// TODO: Remove all files from directory.
}
bool TorrentSynchronization::hasSyncFile() {
const std::string& path = directory() + ".ossync";
return FileSys.fileExists(path);
}
void TorrentSynchronization::createSyncFile() {
const std::string& directoryName = directory();
const std::string& filepath = directoryName + ".ossync";
FileSys.createDirectory(directoryName, ghoul::filesystem::FileSystem::Recursive::Yes);
std::ofstream syncFile(filepath, std::ofstream::out);
syncFile << "Synchronized";
syncFile.close();
}
size_t TorrentSynchronization::nSynchronizedBytes() {
std::lock_guard<std::mutex> g(_progressMutex);
return _progress.nDownloadedBytes;
}
size_t TorrentSynchronization::nTotalBytes() {
std::lock_guard<std::mutex> g(_progressMutex);
return _progress.nTotalBytes;
}
bool TorrentSynchronization::nTotalBytesIsKnown() {
std::lock_guard<std::mutex> g(_progressMutex);
return _progress.nTotalBytesKnown;
}
void TorrentSynchronization::updateTorrentProgress(
TorrentClient::TorrentProgress progress)
{
std::lock_guard<std::mutex> g(_progressMutex);
_progress = progress;
if (progress.finished && (state() == State::Syncing)) {
createSyncFile();
resolve();
}
}
} // namespace openspace

View File

@@ -1,77 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2019 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_SYNC___TORRENTSYNCHRONIZATION___H__
#define __OPENSPACE_MODULE_SYNC___TORRENTSYNCHRONIZATION___H__
#ifdef SYNC_USE_LIBTORRENT
#include <openspace/util/resourcesynchronization.h>
#include <modules/sync/torrentclient.h>
namespace openspace {
class TorrentSynchronizationJob;
class TorrentSynchronization : public ResourceSynchronization {
public:
TorrentSynchronization(const ghoul::Dictionary& dict, std::string synchronizationRoot,
TorrentClient& client);
virtual ~TorrentSynchronization();
std::string directory() override;
void start() override;
void cancel() override;
void clear() override;
size_t nSynchronizedBytes() override;
size_t nTotalBytes() override;
bool nTotalBytesIsKnown() override;
static documentation::Documentation Documentation();
private:
void updateTorrentProgress(TorrentClient::TorrentProgress p);
std::string uniformResourceName() const;
bool hasSyncFile();
void createSyncFile();
std::atomic_bool _enabled = false;
TorrentClient::TorrentId _torrentId = 0;
TorrentClient::TorrentProgress _progress;
std::mutex _progressMutex;
std::string _identifier;
std::string _magnetLink;
std::string _synchronizationRoot;
TorrentClient& _torrentClient;
};
} // namespace openspace
#endif // SYNC_USE_LIBTORRENT
#endif // __OPENSPACE_MODULE_SYNC___TORRENTSYNCHRONIZATION___H__

View File

@@ -1,271 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2019 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/sync/torrentclient.h>
#include <openspace/openspace.h>
#include <ghoul/fmt.h>
#include <ghoul/logging/logmanager.h>
#ifdef SYNC_USE_LIBTORRENT
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable : 4265)
#pragma warning (disable : 4996)
#endif // _MSC_VER
#include <libtorrent/entry.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/session.hpp>
#include <libtorrent/alert_types.hpp>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/magnet_uri.hpp>
#ifdef _MSC_VER
#pragma warning (pop)
#endif // _MSC_VER
namespace {
constexpr const char* _loggerCat = "TorrentClient";
constexpr const std::chrono::milliseconds PollInterval(1000);
} // namespace
#endif // SYNC_USE_LIBTORRENT
namespace openspace {
TorrentError::TorrentError(std::string msg)
: RuntimeError(std::move(msg), "TorrentClient")
{}
void TorrentClient::initialize() {
#ifdef SYNC_USE_LIBTORRENT
libtorrent::settings_pack settings;
settings.set_str(
libtorrent::settings_pack::user_agent,
"OpenSpace/" + std::string(OPENSPACE_VERSION_NUMBER)
);
settings.set_str(
libtorrent::settings_pack::listen_interfaces,
"0.0.0.0:6881,0.0.0.0:20280,0.0.0.0:20285,0.0.0.0:20290"
);
settings.set_bool(libtorrent::settings_pack::allow_multiple_connections_per_ip, true);
settings.set_bool(libtorrent::settings_pack::enable_upnp, true);
//settings.set_bool(libtorrent::settings_pack::ignore_limits_on_local_network, true);
settings.set_int(libtorrent::settings_pack::connection_speed, 20);
settings.set_int(libtorrent::settings_pack::active_downloads, -1);
settings.set_int(libtorrent::settings_pack::active_seeds, -1);
settings.set_int(libtorrent::settings_pack::active_limit, 30);
settings.set_str(
libtorrent::settings_pack::dht_bootstrap_nodes,
"router.utorrent.com,dht.transmissionbt.com,router.bittorrent.com,\
router.bitcomet.com"
);
settings.set_int(libtorrent::settings_pack::dht_announce_interval, 15);
_session.apply_settings(settings);
libtorrent::error_code ec;
_isInitialized = true;
_isActive = true;
_torrentThread = std::thread([this]() {
while (_isActive) {
pollAlerts();
std::unique_lock<std::mutex> lock(_abortMutex);
_abortNotifier.wait_for(lock, PollInterval);
}
});
#endif // SYNC_USE_LIBTORRENT
}
void TorrentClient::deinitialize() {
#ifdef SYNC_USE_LIBTORRENT
if (!_isActive) {
return;
}
_isActive = false;
_abortNotifier.notify_all();
if (_torrentThread.joinable()) {
_torrentThread.join();
}
const std::vector<lt::torrent_handle>& handles = _session.get_torrents();
for (const lt::torrent_handle& h : handles) {
_session.remove_torrent(h);
}
_torrents.clear();
_session.abort();
_isInitialized = false;
#endif // SYNC_USE_LIBTORRENT
}
void TorrentClient::pollAlerts() {
#ifdef SYNC_USE_LIBTORRENT
// Libtorrent does not seem to reliably generate alerts for all added torrents.
// To make sure that the program does not keep waiting for already finished
// downsloads, we go through the whole list of torrents when polling.
// However, in theory, the commented code below should be more efficient:
/*
std::vector<libtorrent::alert*> alerts;
{
std::lock_guard<std::mutex> guard(_mutex);
_session->pop_alerts(&alerts);
}
for (lt::alert* a : alerts) {
if (const lt::torrent_alert* alert =
dynamic_cast<lt::torrent_alert*>(a))
{
notify(alert->handle.id());
}
}
*/
std::vector<lt::torrent_handle> handles;
{
std::lock_guard<std::mutex> guard(_mutex);
handles = _session.get_torrents();
}
for (const lt::torrent_handle& h : handles) {
notify(h.id());
}
#endif // SYNC_USE_LIBTORRENT
}
TorrentClient::TorrentId TorrentClient::addTorrentFile(
[[ maybe_unused ]] const std::string& torrentFile,
[[maybe_unused]] const std::string& destination,
[[maybe_unused]] TorrentProgressCallback cb)
{
#ifdef SYNC_USE_LIBTORRENT
std::lock_guard<std::mutex> guard(_mutex);
if (!_isInitialized) {
LERROR("Torrent session not initialized when adding torrent");
return -1;
}
libtorrent::error_code ec;
libtorrent::add_torrent_params p;
p.save_path = destination;
p.ti = std::make_shared<libtorrent::torrent_info>(torrentFile, ec);
if (ec) {
LERROR(fmt::format("{}: {}", torrentFile, ec.message()));
}
const libtorrent::torrent_handle h = _session.add_torrent(p, ec);
if (ec) {
LERROR(fmt::format("{}: {}", torrentFile, ec.message()));
}
TorrentId id = h.id();
_torrents.emplace(id, Torrent{ id, h, std::move(cb) });
return id;
#else // SYNC_USE_LIBTORRENT
throw TorrentError("SyncModule is compiled without libtorrent support");
#endif // SYNC_USE_LIBTORRENT
}
TorrentClient::TorrentId TorrentClient::addMagnetLink(
[[maybe_unused]] const std::string& magnetLink,
[[maybe_unused]] const std::string& destination,
[[maybe_unused]] TorrentProgressCallback cb)
{
#ifdef SYNC_USE_LIBTORRENT
std::lock_guard<std::mutex> guard(_mutex);
// TODO: register callback!
if (!_isInitialized) {
LERROR("Torrent session not initialized when adding torrent");
return -1;
}
libtorrent::error_code ec;
libtorrent::add_torrent_params p = libtorrent::parse_magnet_uri(magnetLink, ec);
if (ec) {
LERROR(fmt::format("{}: {}", magnetLink, ec.message()));
}
p.save_path = destination;
p.storage_mode = libtorrent::storage_mode_allocate;
const libtorrent::torrent_handle h = _session.add_torrent(p, ec);
if (ec) {
LERROR(fmt::format("{}: {}", magnetLink, ec.message()));
}
TorrentId id = h.id();
_torrents.emplace(id, Torrent{ id, h, std::move(cb) });
return id;
#else // SYNC_USE_LIBTORRENT
throw TorrentError("SyncModule is compiled without libtorrent support");
#endif // SYNC_USE_LIBTORRENT
}
void TorrentClient::removeTorrent([[maybe_unused]] TorrentId id) {
#ifdef SYNC_USE_LIBTORRENT
std::lock_guard<std::mutex> guard(_mutex);
const auto it = _torrents.find(id);
if (it == _torrents.end()) {
return;
}
const libtorrent::torrent_handle h = it->second.handle;
_session.remove_torrent(h);
_torrents.erase(it);
#endif // SYNC_USE_LIBTORRENT
}
void TorrentClient::notify([[maybe_unused]] TorrentId id) {
#ifdef SYNC_USE_LIBTORRENT
TorrentProgressCallback callback;
TorrentProgress progress;
{
std::lock_guard<std::mutex> guard(_mutex);
const auto it = _torrents.find(id);
if (it == _torrents.end()) {
return;
}
const libtorrent::torrent_handle h = it->second.handle;
const libtorrent::torrent_status status = h.status();
progress.finished = status.is_finished;
progress.nTotalBytesKnown = status.total_wanted > 0;
progress.nTotalBytes = status.total_wanted;
progress.nDownloadedBytes = status.total_wanted_done;
callback = it->second.callback;
}
callback(progress);
#endif // SYNC_USE_LIBTORRENT
}
} // namespace openspace

View File

@@ -1,125 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2019 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_SYNC___TORRENTCLIENT___H__
#define __OPENSPACE_MODULE_SYNC___TORRENTCLIENT___H__
#ifdef SYNC_USE_LIBTORRENT
#include <ghoul/misc/exception.h>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#ifdef SYNC_USE_LIBTORRENT
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable : 4265)
#pragma warning (disable : 4996)
#endif // _MSC_VER
// libtorrent defines a class with the name 'defer', which messes with out #define of the
// defer macro in ghoul/misc/defer.h
#undef defer
#include <libtorrent/torrent_handle.hpp>
#include <libtorrent/session.hpp>
#ifdef _MSC_VER
#pragma warning (pop)
#endif // _MSC_VER
#else // SYNC_USE_LIBTORRENT
// Dummy definition to make TorrentClient compile, these is not actually used if
// SYNC_USE_LIBTORRENT is FALSE
namespace libtorrent {
using torrent_handle = void*;
using session = void*;
} // namespace libtorrent
#endif // SYNC_USE_LIBTORRENT
namespace openspace {
struct TorrentError : public ghoul::RuntimeError {
explicit TorrentError(std::string msg);
};
class TorrentClient {
public:
struct TorrentProgress {
bool finished = false;
bool nTotalBytesKnown = false;
size_t nTotalBytes = 0;
size_t nDownloadedBytes = 0;
};
using TorrentProgressCallback = std::function<void(TorrentProgress)>;
using TorrentId = int32_t;
void initialize();
void deinitialize();
TorrentId addTorrentFile(const std::string& torrentFile,
const std::string& destination, TorrentProgressCallback cb);
TorrentId addMagnetLink(const std::string& magnetLink, const std::string& destination,
TorrentProgressCallback cb);
void removeTorrent(TorrentId id);
private:
struct Torrent {
TorrentId id;
libtorrent::torrent_handle handle;
TorrentProgressCallback callback;
};
void notify(TorrentId id);
void pollAlerts();
#ifdef SYNC_USE_LIBTORRENT
libtorrent::session _session;
bool _isInitialized = false;
std::atomic_bool _isActive = false;
#endif // SYNC_USE_LIBTORRENT
std::thread _torrentThread;
std::condition_variable _abortNotifier;
std::mutex _abortMutex;
std::mutex _mutex;
std::unordered_map<TorrentId, Torrent> _torrents;
};
} // namespace openspace
#endif // SYNC_USE_LIBTORRENT
#endif // __OPENSPACE_MODULE_SYNC___TORRENTCLIENT___H__