diff --git a/TODO b/TODO index 90e91232..b46adfa7 100644 --- a/TODO +++ b/TODO @@ -8,3 +8,5 @@ Make clear distinction of upload/download throttle. "Caught exception: "Tried to add an existing DownloadMain to DownloadManager"" Properly handle duplicate torrents. + +Add log message for failed http requests. diff --git a/src/core/Makefile.am b/src/core/Makefile.am index ff06e1ec..9a6f56da 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -5,16 +5,18 @@ libsub_core_a_SOURCES = \ curl_get.h \ curl_stack.cc \ curl_stack.h \ - hash_queue.cc \ - hash_queue.h \ - http_queue.cc \ - http_queue.h \ download.cc \ download.h \ download_list.cc \ download_list.h \ download_store.cc \ download_store.h \ + hash_queue.cc \ + hash_queue.h \ + http_queue.cc \ + http_queue.h \ + log.cc \ + log.h \ manager.cc \ manager.h \ poll.cc \ diff --git a/src/core/log.cc b/src/core/log.cc new file mode 100644 index 00000000..a48aed0f --- /dev/null +++ b/src/core/log.cc @@ -0,0 +1,23 @@ +#include "config.h" + +#include + +#include "log.h" +#include "utils/functional.h" + +namespace core { + +void +Log::push_front(const std::string& msg) { + Base::push_front(Type(utils::Timer::cache(), msg)); + + m_signalUpdate.emit(); +} + +Log::iterator +Log::find_older(utils::Timer t) { + return std::find_if(begin(), end(), func::on(func::mem_ptr_ref(&Type::first), + std::bind1st(std::less_equal(), t))); +} + +} diff --git a/src/core/log.h b/src/core/log.h new file mode 100644 index 00000000..ed12777a --- /dev/null +++ b/src/core/log.h @@ -0,0 +1,43 @@ +#ifndef RTORRENT_CORE_LOG_H +#define RTORRENT_CORE_LOG_H + +#include +#include +#include + +#include "utils/timer.h" + +namespace core { + +class Log : private std::deque > { +public: + typedef std::pair Type; + typedef std::deque Base; + typedef sigc::signal0 Signal; + + using Base::iterator; + using Base::const_iterator; + using Base::reverse_iterator; + using Base::const_reverse_iterator; + + using Base::begin; + using Base::end; + using Base::rbegin; + using Base::rend; + + using Base::empty; + using Base::size; + + void push_front(const std::string& msg); + + iterator find_older(utils::Timer t); + + Signal& signal_update() { return m_signalUpdate; } + +private: + Signal m_signalUpdate; +}; + +} + +#endif diff --git a/src/core/manager.cc b/src/core/manager.cc index 021abf0d..2c2b38b9 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -99,9 +99,15 @@ Manager::receive_http_done(CurlGet* http) { } catch (torrent::local_error& e) { // What to do? Keep in list for now. + m_log.push_front(e.what()); } } +void +Manager::receive_http_failed(std::string msg) { + m_log.push_front("Http download error: \"" + msg + "\""); +} + void Manager::create_file(const std::string& uri) { try { @@ -111,6 +117,7 @@ Manager::create_file(const std::string& uri) { } catch (torrent::local_error& e) { // What to do? Keep in list for now. + m_log.push_front(e.what()); } } @@ -119,7 +126,7 @@ Manager::create_http(const std::string& uri) { core::HttpQueue::iterator itr = m_httpQueue.insert(uri); (*itr)->signal_done().slots().push_front(sigc::bind(sigc::mem_fun(*this, &core::Manager::receive_http_done), *itr)); - // Add the failed signal here. + (*itr)->signal_failed().slots().push_front(sigc::mem_fun(*this, &core::Manager::receive_http_failed)); } Manager::iterator diff --git a/src/core/manager.h b/src/core/manager.h index a89aaba2..6744c3dc 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -6,6 +6,7 @@ #include "hash_queue.h" #include "http_queue.h" #include "poll.h" +#include "log.h" namespace core { @@ -23,6 +24,7 @@ public: HttpQueue& get_http_queue() { return m_httpQueue; } Poll& get_poll() { return m_poll; } + Log& get_log() { return m_log; } void initialize(); void cleanup(); @@ -40,6 +42,7 @@ public: private: void receive_http_done(CurlGet* http); + void receive_http_failed(std::string msg); void create_file(const std::string& uri); void create_http(const std::string& uri); @@ -50,7 +53,9 @@ private: DownloadStore m_downloadStore; HashQueue m_hashQueue; HttpQueue m_httpQueue; + Poll m_poll; + Log m_log; std::string m_dns; int m_portFirst; diff --git a/src/display/Makefile.am b/src/display/Makefile.am index a7ca100c..d134aded 100644 --- a/src/display/Makefile.am +++ b/src/display/Makefile.am @@ -17,6 +17,8 @@ libsub_display_a_SOURCES = \ window_http_queue.h \ window_input.cc \ window_input.h \ + window_log.cc \ + window_log.h \ window_peer_info.cc \ window_peer_info.h \ window_peer_list.cc \ diff --git a/src/display/window.cc b/src/display/window.cc index a34536a5..8b37c419 100644 --- a/src/display/window.cc +++ b/src/display/window.cc @@ -7,6 +7,8 @@ namespace display { +Window::Slot Window::m_slotAdjust; + Window::~Window() { delete m_canvas; } diff --git a/src/display/window.h b/src/display/window.h index d1207770..27c2d433 100644 --- a/src/display/window.h +++ b/src/display/window.h @@ -1,6 +1,8 @@ #ifndef RTORRENT_WINDOW_BASE_H #define RTORRENT_WINDOW_BASE_H +#include + #include "utils/timer.h" namespace display { @@ -9,38 +11,44 @@ class Canvas; class Window { public: + typedef sigc::slot0 Slot; + Window(Canvas* c = NULL, bool d = false, int h = 1) : m_canvas(c), m_active(true), m_dynamic(d), m_minHeight(h) {} virtual ~Window(); - bool is_active() { return m_active; } - bool is_dynamic() { return m_dynamic; } - bool is_dirty() { return m_lastDraw == 0; } + bool is_active() { return m_active; } + bool is_dynamic() { return m_dynamic; } + bool is_dirty() { return m_lastDraw == 0; } - int get_min_height() { return m_minHeight; } + int get_min_height() { return m_minHeight; } - bool get_active() { return m_active; } - void set_active(bool a) { m_active = a; } + bool get_active() { return m_active; } + void set_active(bool a) { m_active = a; } void refresh(); void resize(int x, int y, int w, int h); - void mark_dirty() { m_lastDraw = 0; } + void mark_dirty() { m_lastDraw = 0; } virtual void redraw() = 0; + static void slot_adjust(Slot s) { m_slotAdjust = s; } + protected: Window(const Window&); void operator = (const Window&); + static Slot m_slotAdjust; + Canvas* m_canvas; bool m_active; bool m_dynamic; int m_minHeight; - utils::Timer m_lastDraw; + utils::Timer m_lastDraw; }; } diff --git a/src/display/window_http_queue.cc b/src/display/window_http_queue.cc index 4ee571e3..35219239 100644 --- a/src/display/window_http_queue.cc +++ b/src/display/window_http_queue.cc @@ -72,7 +72,9 @@ WindowHttpQueue::cleanup_list() { std::string WindowHttpQueue::create_name(core::CurlGet* h) { - std::string n = h->get_url().substr(h->get_url().rfind('/', h->get_url().size() - std::min((size_t)10, h->get_url().size()))); + size_t p = h->get_url().rfind('/', h->get_url().size() - std::min(10, h->get_url().size())); + + std::string n = p != std::string::npos ? h->get_url().substr(p) : h->get_url(); if (n.empty()) throw std::logic_error("WindowHttpQueue::create_name(...) made a bad string"); diff --git a/src/display/window_http_queue.h b/src/display/window_http_queue.h index bcc2491b..377706dd 100644 --- a/src/display/window_http_queue.h +++ b/src/display/window_http_queue.h @@ -1,7 +1,6 @@ #ifndef RTORRENT_DISPLAY_WINDOW_HTTP_QUEUE_H #define RTORRENT_DISPLAY_WINDOW_HTTP_QUEUE_H -#include #include #include "window.h" @@ -15,13 +14,9 @@ namespace display { class WindowHttpQueue : public Window { public: - typedef sigc::slot0 Slot; - WindowHttpQueue(core::HttpQueue* q); ~WindowHttpQueue() { m_connInsert.disconnect(); m_connErase.disconnect(); } - void slot_adjust(Slot s) { m_slotAdjust = s; } - virtual void redraw(); private: @@ -45,7 +40,6 @@ private: static std::string create_name(core::CurlGet* h); core::HttpQueue* m_queue; - Slot m_slotAdjust; sigc::connection m_connInsert; sigc::connection m_connErase; diff --git a/src/display/window_log.cc b/src/display/window_log.cc new file mode 100644 index 00000000..4076e98d --- /dev/null +++ b/src/display/window_log.cc @@ -0,0 +1,52 @@ +#include "config.h" + +#include "core/log.h" + +#include "canvas.h" +#include "window_log.h" + +namespace display { + +WindowLog::WindowLog(core::Log* l) : + Window(new Canvas, false, 0), + m_log(l) { + + set_active(false); + + m_connUpdate = l->signal_update().connect(sigc::mem_fun(*this, &WindowLog::receive_update)); +} + +WindowLog::~WindowLog() { + m_connUpdate.disconnect(); +} + +void +WindowLog::redraw() { + if (!is_dirty()) + return; + + m_lastDraw = utils::Timer::cache(); + + m_canvas->erase(); + + int pos = 0; + + for (core::Log::iterator itr = m_log->begin(), end = m_log->end(); itr != end; ++itr) + m_canvas->print(0, pos++, "Log: %s", itr->second.c_str()); +} + +void +WindowLog::receive_update() { + int newHeight = std::min(m_log->size(), 5); + + if (newHeight != m_minHeight) { + m_minHeight = newHeight; + + set_active(m_minHeight != 0); + m_slotAdjust(); + } + + mark_dirty(); +} + +} diff --git a/src/display/window_log.h b/src/display/window_log.h new file mode 100644 index 00000000..5529529d --- /dev/null +++ b/src/display/window_log.h @@ -0,0 +1,30 @@ +#ifndef RTORRENT_DISPLAY_WINDOW_LOG_H +#define RTORRENT_DISPLAY_WINDOW_LOG_H + +#include + +#include "window.h" + +namespace core { + class Log; +} + +namespace display { + +class WindowLog : public Window { +public: + WindowLog(core::Log* l); + ~WindowLog(); + + virtual void redraw(); + +private: + void receive_update(); + + core::Log* m_log; + sigc::connection m_connUpdate; +}; + +} + +#endif diff --git a/src/main.cc b/src/main.cc index f69e0893..ace25d66 100644 --- a/src/main.cc +++ b/src/main.cc @@ -15,6 +15,7 @@ #include "core/download.h" #include "display/canvas.h" +#include "display/window.h" #include "ui/control.h" #include "ui/download_list.h" #include "input/bindings.h" @@ -137,6 +138,7 @@ main(int argc, char** argv) { int firstArg = parse_options(&uiControl, argc, argv); display::Canvas::init(); + display::Window::slot_adjust(sigc::mem_fun(uiControl.get_display(), &display::Manager::adjust_layout)); ui::DownloadList uiDownloadList(&uiControl); diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 19b30729..82d30d8f 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -12,6 +12,7 @@ #include "display/window_download_list.h" #include "display/window_http_queue.h" #include "display/window_input.h" +#include "display/window_log.h" #include "display/window_statusbar.h" #include "display/window_title.h" @@ -33,11 +34,11 @@ DownloadList::DownloadList(Control* c) : m_bindings(new input::Bindings) { m_window = new WList(&m_control->get_core().get_download_list(), &m_focus); + m_windowLog = new WLog(&m_control->get_core().get_log()); bind_keys(m_bindings); m_textInput->get_input()->slot_dirty(sigc::mem_fun(*m_textInput, &WInput::mark_dirty)); - m_windowHttpQueue->slot_adjust(sigc::mem_fun(c->get_display(), &display::Manager::adjust_layout)); } DownloadList::~DownloadList() { @@ -46,6 +47,7 @@ DownloadList::~DownloadList() { delete m_status; delete m_bindings; + delete m_windowLog; delete m_textInput->get_input(); delete m_textInput; delete m_windowHttpQueue; @@ -57,6 +59,7 @@ DownloadList::activate() { m_control->get_input().push_front(m_bindings); + m_control->get_display().push_back(m_windowLog); m_control->get_display().push_back(m_windowHttpQueue); m_control->get_display().push_back(m_textInput); m_control->get_display().push_back(m_status); @@ -77,6 +80,7 @@ DownloadList::disable() { m_control->get_display().erase(m_window); m_control->get_display().erase(m_status); m_control->get_display().erase(m_textInput); + m_control->get_display().erase(m_windowLog); m_control->get_display().erase(m_windowHttpQueue); } diff --git a/src/ui/download_list.h b/src/ui/download_list.h index e33ee2c9..af0546d1 100644 --- a/src/ui/download_list.h +++ b/src/ui/download_list.h @@ -7,6 +7,7 @@ namespace display { class WindowDownloadList; class WindowHttpQueue; class WindowInput; + class WindowLog; class WindowStatusbar; class WindowTitle; } @@ -21,6 +22,7 @@ public: typedef display::WindowDownloadList WList; typedef display::WindowHttpQueue WHttp; typedef display::WindowInput WInput; + typedef display::WindowLog WLog; typedef display::WindowStatusbar WStatus; typedef display::WindowTitle WTitle; @@ -65,6 +67,7 @@ private: WList* m_window; WTitle* m_title; WStatus* m_status; + WLog* m_windowLog; WInput* m_textInput; WHttp* m_windowHttpQueue; diff --git a/src/utils/functional.h b/src/utils/functional.h index e44f4f75..1aca1581 100644 --- a/src/utils/functional.h +++ b/src/utils/functional.h @@ -70,6 +70,24 @@ on(Src s, Dest d) { return _on(s, d); } +// Creates a functor for accessing a member. +template +struct _mem_ptr_ref : public std::unary_function { + _mem_ptr_ref(Member Class::*m) : m_member(m) {} + + Member& operator () (Class& c) { + return c.*m_member; + } + + Member Class::*m_member; +}; + +template +inline _mem_ptr_ref +mem_ptr_ref(Member Class::*m) { + return _mem_ptr_ref(m); +} + template struct _if_then { _if_then(Cond c, Then t) : m_cond(c), m_then(t) {}