* 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:
rakshasa
2006-01-03 21:43:01 +00:00
parent 5a8a402745
commit 4431fd1652
20 changed files with 519 additions and 58 deletions
+5
View File
@@ -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;
+31 -11
View File
@@ -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();
}
+12
View File
@@ -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;
+3
View File
@@ -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)
+9
View File
@@ -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
View File
@@ -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
View File
@@ -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);