mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-15 06:32:31 +00:00
* Fixed a regression that threw an exception for torrents with
empty directories. * When receiving zero length pieces, remove them from the request list. * Send the interested state before any requests as some clients, BitTornado 0.7.14 and uTorrent 0.3.0, disconnect if a request has been received while uninterested. * WITH_POSIX_FALLOCATE configure macro should check against "yes", not "no". * The new priority queue would cause arg torrents to load before session torrents in some cases. Fixed to perform the session torrent tasks before loading arg torrents. * Allow '*' wildcard in filenames when loading torrents. * Added load, load_run, stop_tied and remove_tied settings which can be used to scan a directory for new/removed torrents. These torrents are tied to the lifetime of the torrent file. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@616 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
@@ -73,6 +73,9 @@ public:
|
||||
void set_connection_leech(const std::string& name) { m_connectionLeech = string_to_connection_type(name); }
|
||||
void set_connection_seed(const std::string& name) { m_connectionSeed = string_to_connection_type(name); }
|
||||
|
||||
const std::string& tied_to_file() const { return m_tiedToFile; }
|
||||
void set_tied_to_file(const std::string& str) { m_tiedToFile = str; }
|
||||
|
||||
void enable_udp_trackers(bool state);
|
||||
|
||||
// Helper functions for calling functions in torrent::Download
|
||||
@@ -104,6 +107,8 @@ private:
|
||||
ConnType m_connectionLeech;
|
||||
ConnType m_connectionSeed;
|
||||
|
||||
std::string m_tiedToFile;
|
||||
|
||||
sigc::connection m_connTrackerSucceded;
|
||||
sigc::connection m_connTrackerFailed;
|
||||
sigc::connection m_connStorageError;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <torrent/bencode.h>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "curl_get.h"
|
||||
#include "http_queue.h"
|
||||
@@ -58,7 +59,9 @@ DownloadFactory::DownloadFactory(const std::string& uri, Manager* m) :
|
||||
|
||||
m_uri(uri),
|
||||
m_session(false),
|
||||
m_start(false) {
|
||||
m_start(false),
|
||||
m_printLog(true),
|
||||
m_tiedToFile(false) {
|
||||
|
||||
m_taskLoad.set_slot(rak::mem_fn(this, &DownloadFactory::receive_load));
|
||||
m_taskCommit.set_slot(rak::mem_fn(this, &DownloadFactory::receive_commit));
|
||||
@@ -85,7 +88,7 @@ DownloadFactory::commit() {
|
||||
void
|
||||
DownloadFactory::receive_load() {
|
||||
if (m_stream)
|
||||
throw std::logic_error("DownloadFactory::load() called on an object with m_stream != NULL");
|
||||
throw torrent::client_error("DownloadFactory::load() called on an object with m_stream != NULL");
|
||||
|
||||
if (std::strncmp(m_uri.c_str(), "http://", 7) == 0) {
|
||||
// Http handling here.
|
||||
@@ -95,6 +98,8 @@ DownloadFactory::receive_load() {
|
||||
(*itr)->signal_done().slots().push_front(sigc::mem_fun(*this, &DownloadFactory::receive_loaded));
|
||||
(*itr)->signal_failed().slots().push_front(sigc::mem_fun(*this, &DownloadFactory::receive_failed));
|
||||
|
||||
m_tiedToFile = false;
|
||||
|
||||
} else {
|
||||
m_stream = new std::fstream(m_uri.c_str(), std::ios::in);
|
||||
|
||||
@@ -124,9 +129,9 @@ DownloadFactory::receive_commit() {
|
||||
void
|
||||
DownloadFactory::receive_success() {
|
||||
if (m_stream == NULL)
|
||||
throw std::logic_error("DownloadFactory::receive_success() called on an object with m_stream == NULL");
|
||||
throw torrent::client_error("DownloadFactory::receive_success() called on an object with m_stream == NULL");
|
||||
|
||||
Manager::DListItr itr = m_manager->insert(m_stream);
|
||||
Manager::DListItr itr = m_manager->insert(m_stream, m_printLog);
|
||||
|
||||
if (itr == m_manager->get_download_list().end()) {
|
||||
// core::Manager should already have added the error message to
|
||||
@@ -135,15 +140,28 @@ DownloadFactory::receive_success() {
|
||||
return;
|
||||
}
|
||||
|
||||
torrent::Bencode& bencode = (*itr)->get_bencode();
|
||||
|
||||
if (m_session) {
|
||||
torrent::Bencode& bencode = (*itr)->get_bencode();
|
||||
|
||||
// Hmm... this safe?
|
||||
if (bencode.get_key("rtorrent").get_key("state").as_string() == "started")
|
||||
m_manager->start(*itr);
|
||||
m_manager->start(*itr, m_printLog);
|
||||
|
||||
if (bencode.get_key("rtorrent").has_key("tied") &&
|
||||
bencode.get_key("rtorrent").get_key("tied").is_string())
|
||||
(*itr)->set_tied_to_file(bencode.get_key("rtorrent").get_key("tied").as_string());
|
||||
|
||||
} else {
|
||||
// Remove the settings if this isn't a session torrent.
|
||||
//bencode.erase_key("rtorrent");
|
||||
|
||||
if (m_tiedToFile) {
|
||||
(*itr)->set_tied_to_file(m_uri);
|
||||
bencode.get_key("rtorrent").insert_key("tied", m_uri);
|
||||
}
|
||||
|
||||
if (m_start)
|
||||
m_manager->start(*itr);
|
||||
m_manager->start(*itr, m_printLog);
|
||||
|
||||
m_manager->get_download_store().save(*itr);
|
||||
}
|
||||
@@ -154,11 +172,13 @@ DownloadFactory::receive_success() {
|
||||
void
|
||||
DownloadFactory::receive_failed(const std::string& msg) {
|
||||
if (m_stream == NULL)
|
||||
throw std::logic_error("DownloadFactory::receive_success() called on an object with m_stream == NULL");
|
||||
throw torrent::client_error("DownloadFactory::receive_success() called on an object with m_stream == NULL");
|
||||
|
||||
// Add message to log.
|
||||
m_manager->get_log_important().push_front(msg + ": \"" + m_uri + "\"");
|
||||
m_manager->get_log_complete().push_front(msg + ": \"" + m_uri + "\"");
|
||||
if (m_printLog) {
|
||||
m_manager->get_log_important().push_front(msg + ": \"" + m_uri + "\"");
|
||||
m_manager->get_log_complete().push_front(msg + ": \"" + m_uri + "\"");
|
||||
}
|
||||
|
||||
m_slotFinished();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
// The DownloadFactory class assures that loading torrents can be done
|
||||
// anywhere in the code by queueing the task. The user may change
|
||||
// settings while, or even after, the torrent is loading.
|
||||
|
||||
#ifndef RTORRENT_CORE_DOWNLOAD_FACTORY_H
|
||||
#define RTORRENT_CORE_DOWNLOAD_FACTORY_H
|
||||
|
||||
@@ -67,6 +71,12 @@ public:
|
||||
bool get_start() const { return m_start; }
|
||||
void set_start(bool v) { m_start = v; }
|
||||
|
||||
bool print_log() const { return m_printLog; }
|
||||
void set_print_log(bool v) { m_printLog = v; }
|
||||
|
||||
bool tied_to_file() const { return m_tiedToFile; }
|
||||
void set_tied_to_file(bool v) { m_tiedToFile = v; }
|
||||
|
||||
void slot_finished(Slot s) { m_slotFinished = s; }
|
||||
|
||||
private:
|
||||
@@ -85,6 +95,8 @@ private:
|
||||
std::string m_uri;
|
||||
bool m_session;
|
||||
bool m_start;
|
||||
bool m_printLog;
|
||||
bool m_tiedToFile;
|
||||
|
||||
Slot m_slotFinished;
|
||||
rak::priority_item m_taskLoad;
|
||||
|
||||
@@ -46,6 +46,9 @@ namespace core {
|
||||
|
||||
void
|
||||
Log::push_front(const std::string& msg) {
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
Base::push_front(Type(cachedTime, msg));
|
||||
|
||||
if (size() > 50)
|
||||
|
||||
@@ -64,6 +64,13 @@ public:
|
||||
using Base::empty;
|
||||
using Base::size;
|
||||
|
||||
Log() : m_enabled(true) {}
|
||||
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
|
||||
void enable() { m_enabled = true; }
|
||||
void disable() { m_enabled = false; }
|
||||
|
||||
void push_front(const std::string& msg);
|
||||
|
||||
iterator find_older(rak::timer t);
|
||||
@@ -71,6 +78,8 @@ public:
|
||||
Signal& signal_update() { return m_signalUpdate; }
|
||||
|
||||
private:
|
||||
bool m_enabled;
|
||||
|
||||
Signal m_signalUpdate;
|
||||
};
|
||||
|
||||
|
||||
+83
-6
@@ -43,6 +43,8 @@
|
||||
#include <istream>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <rak/regex.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <sigc++/bind.h>
|
||||
#include <sigc++/hide.h>
|
||||
#include <torrent/bencode.h>
|
||||
@@ -50,6 +52,7 @@
|
||||
|
||||
#include "curl_get.h"
|
||||
#include "download.h"
|
||||
#include "download_factory.h"
|
||||
#include "manager.h"
|
||||
#include "poll_manager_epoll.h"
|
||||
#include "poll_manager_select.h"
|
||||
@@ -149,13 +152,15 @@ Manager::shutdown(bool force) {
|
||||
}
|
||||
|
||||
Manager::DListItr
|
||||
Manager::insert(std::istream* s) {
|
||||
Manager::insert(std::istream* s, bool printLog) {
|
||||
try {
|
||||
return m_downloadList.insert(s);
|
||||
|
||||
} catch (torrent::local_error& e) {
|
||||
m_logImportant.push_front(e.what());
|
||||
m_logComplete.push_front(e.what());
|
||||
if (printLog) {
|
||||
m_logImportant.push_front(e.what());
|
||||
m_logComplete.push_front(e.what());
|
||||
}
|
||||
|
||||
return m_downloadList.end();
|
||||
}
|
||||
@@ -173,7 +178,7 @@ Manager::erase(DListItr itr) {
|
||||
}
|
||||
|
||||
void
|
||||
Manager::start(Download* d) {
|
||||
Manager::start(Download* d, bool printLog) {
|
||||
try {
|
||||
d->get_bencode().get_key("rtorrent").get_key("state") = "started";
|
||||
|
||||
@@ -190,8 +195,10 @@ Manager::start(Download* d) {
|
||||
m_hashQueue.insert(d, sigc::bind(sigc::mem_fun(m_downloadList, &DownloadList::start), d));
|
||||
|
||||
} catch (torrent::local_error& e) {
|
||||
m_logImportant.push_front(e.what());
|
||||
m_logComplete.push_front(e.what());
|
||||
if (printLog) {
|
||||
m_logImportant.push_front(e.what());
|
||||
m_logComplete.push_front(e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,4 +309,74 @@ Manager::receive_download_done_hash_checked(Download* d) {
|
||||
d->get_download().tracker_send_completed();
|
||||
}
|
||||
|
||||
void
|
||||
Manager::try_create_download(const std::string& uri, bool start, bool printLog, bool tied) {
|
||||
// Adding download.
|
||||
DownloadFactory* f = new DownloadFactory(uri, this);
|
||||
|
||||
f->set_start(start);
|
||||
f->set_print_log(printLog);
|
||||
f->set_tied_to_file(tied);
|
||||
f->slot_finished(sigc::bind(sigc::ptr_fun(&rak::call_delete_func<core::DownloadFactory>), f));
|
||||
f->load();
|
||||
f->commit();
|
||||
}
|
||||
|
||||
// Move this somewhere better.
|
||||
void
|
||||
path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
std::vector<utils::Directory> currentCache;
|
||||
std::vector<utils::Directory> nextCache;
|
||||
|
||||
rak::split_iterator_t<std::string> first = rak::split_iterator(pattern, '/');
|
||||
rak::split_iterator_t<std::string> last = rak::split_iterator(pattern);
|
||||
|
||||
if (first == last)
|
||||
return;
|
||||
|
||||
// Check for initial '/' that indicates the root.
|
||||
if ((*first).empty()) {
|
||||
currentCache.push_back(utils::Directory("/"));
|
||||
++first;
|
||||
} else {
|
||||
currentCache.push_back(utils::Directory("./"));
|
||||
}
|
||||
|
||||
// Might be an idea to use depth-first search instead.
|
||||
|
||||
for (; first != last; ++first) {
|
||||
rak::regex r(*first);
|
||||
|
||||
if (r.pattern().empty())
|
||||
continue;
|
||||
|
||||
for (std::vector<utils::Directory>::iterator itr = currentCache.begin(); itr != currentCache.end(); ++itr) {
|
||||
itr->update(false);
|
||||
itr->erase(std::remove_if(itr->begin(), itr->end(), std::not1(r)), itr->end());
|
||||
|
||||
std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), std::bind1st(std::plus<std::string>(), itr->get_path() + "/"));
|
||||
}
|
||||
|
||||
currentCache.clear();
|
||||
currentCache.swap(nextCache);
|
||||
}
|
||||
|
||||
std::transform(currentCache.begin(), currentCache.end(), std::back_inserter(*paths), std::mem_fun_ref(&utils::Directory::get_path));
|
||||
}
|
||||
|
||||
void
|
||||
Manager::try_create_download_expand(const std::string& uri, bool start, bool printLog, bool tied) {
|
||||
std::vector<std::string> paths;
|
||||
paths.reserve(32);
|
||||
|
||||
path_expand(&paths, uri);
|
||||
|
||||
if (!paths.empty())
|
||||
for (std::vector<std::string>::iterator itr = paths.begin(); itr != paths.end(); ++itr)
|
||||
try_create_download(*itr, start, printLog, tied);
|
||||
|
||||
else
|
||||
try_create_download(uri, start, printLog, tied);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-2
@@ -83,16 +83,20 @@ public:
|
||||
|
||||
void shutdown(bool force);
|
||||
|
||||
DListItr insert(std::istream* s);
|
||||
DListItr insert(std::istream* s, bool printLog = true);
|
||||
DListItr erase(DListItr itr);
|
||||
|
||||
void start(Download* d);
|
||||
void start(Download* d, bool printLog = true);
|
||||
void stop(Download* d);
|
||||
|
||||
void check_hash(Download* d);
|
||||
|
||||
void push_log(const std::string& msg) { m_logImportant.push_front(msg); m_logComplete.push_front(msg); }
|
||||
|
||||
// Temporary, find a better place for this.
|
||||
void try_create_download(const std::string& uri, bool start, bool printLog = true, bool tied = false);
|
||||
void try_create_download_expand(const std::string& uri, bool start, bool printLog = true, bool tied = false);
|
||||
|
||||
private:
|
||||
void create_http(const std::string& uri);
|
||||
void create_final(std::istream* s);
|
||||
|
||||
Reference in New Issue
Block a user