diff --git a/README b/README index 11b40a65..659d05aa 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ All: - Ctrl-C - Quit + Ctrl-Q - Quit A - Increase Throttle by 1 KiB Z - Decrease Throttle by 1 KiB @@ -11,23 +11,27 @@ All: D - Increase Throttle by 50 KiB C - Decrease Throttle by 50 KiB + In main window: Backspace - Activate text input for inserting urls/file paths. Arrows/C^f/C^b for navigation, enter/C^m. - Up/Down - Select torrent. + Up/Down - Select torrent - Right - View torrent. + Right - View torrent + + Ctrl-S - Start torrent + Ctrl-D - Stop/delete torrent In torrent view: - Up/Down - Select peer. + Up/Down - Select peer - Left - Back to main. + Left - Back to main - Right - View peer. + Right - View peer 1 - Decrease max uploads 2 - Increase max uploads @@ -38,3 +42,4 @@ In torrent view: 5 - Decrease max peers connected 6 - Increase max peers connected + T - Query tracker \ No newline at end of file diff --git a/TODO b/TODO new file mode 100644 index 00000000..c39e608b --- /dev/null +++ b/TODO @@ -0,0 +1,8 @@ +core::Manager::stop() should make sure ongoing hash checks get cleaned +up. + +Polling during last phase of shutdown should be very quick, don't use +normal timeout. + +Seperate out, and write code for a nice one liner status report, +tracker, stopped/started etc info about a torrent. \ No newline at end of file diff --git a/src/core/hash_queue.cc b/src/core/hash_queue.cc index cb01173c..ef99486e 100644 --- a/src/core/hash_queue.cc +++ b/src/core/hash_queue.cc @@ -12,6 +12,9 @@ namespace core { void HashQueue::insert(Download* d, Slot s) { + if (d->get_download().is_hash_checking()) + return; + if (std::find_if(begin(), end(), func::equal(d, std::mem_fun(&HashQueueNode::get_download))) != end()) throw std::logic_error("core::HashQueue::insert(...) received a Download that is already queued"); @@ -52,6 +55,8 @@ HashQueue::receive_hash_done(Base::iterator itr) { Base::erase(itr); s(); + + fill_queue(); } void diff --git a/src/core/manager.cc b/src/core/manager.cc index 7baaf891..dcfe0524 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -6,11 +6,29 @@ #include #include #include +#include #include "manager.h" namespace core { +void +Manager::initialize() { + torrent::Http::set_factory(m_poll.get_http_factory()); + m_httpQueue.slot_factory(m_poll.get_http_factory()); + + CurlStack::init(); + + torrent::initialize(); + torrent::listen_open(10000, 20000); +} + +void +Manager::cleanup() { + torrent::cleanup(); + core::CurlStack::cleanup(); +} + void Manager::insert(const std::string& uri) { if (std::strncmp(uri.c_str(), "http://", 7)) @@ -24,14 +42,20 @@ Manager::start(Download* d) { if (d->get_download().is_active()) return; - if (d->get_download().is_open()) { - d->start(); - - } else { + if (!d->get_download().is_open()) d->open(); + if (d->get_download().is_hash_checked()) + d->start(); + else m_hashQueue.insert(d, sigc::mem_fun(*d, &Download::start)); - } +} + +void +Manager::stop(Download* d) { + m_hashQueue.remove(d); + + d->stop(); } void diff --git a/src/core/manager.h b/src/core/manager.h index b856de51..5145b179 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -4,6 +4,7 @@ #include "download_list.h" #include "hash_queue.h" #include "http_queue.h" +#include "poll.h" namespace core { @@ -16,9 +17,15 @@ public: HashQueue& get_hash_queue() { return m_hashQueue; } HttpQueue& get_http_queue() { return m_httpQueue; } + Poll& get_poll() { return m_poll; } + + void initialize(); + void cleanup(); + void insert(const std::string& uri); void start(Download* d); + void stop(Download* d); private: void receive_http_done(torrent::Http* http); @@ -29,6 +36,7 @@ private: DownloadList m_downloadList; HashQueue m_hashQueue; HttpQueue m_httpQueue; + Poll m_poll; }; } diff --git a/src/display/Makefile.am b/src/display/Makefile.am index 5ae5ce03..233f8bc4 100644 --- a/src/display/Makefile.am +++ b/src/display/Makefile.am @@ -5,6 +5,8 @@ libsub_display_a_SOURCES = \ canvas.h \ manager.cc \ manager.h \ + utils.cc \ + utils.h \ window.cc \ window.h \ window_download_statusbar.cc \ diff --git a/src/display/canvas.cc b/src/display/canvas.cc index 498d493d..7bcd870a 100644 --- a/src/display/canvas.cc +++ b/src/display/canvas.cc @@ -13,7 +13,7 @@ Canvas::resize(int x, int y, int w, int h) { void Canvas::init() { initscr(); - cbreak(); + raw(); noecho(); nodelay(stdscr, TRUE); keypad(stdscr, TRUE); @@ -22,6 +22,7 @@ Canvas::init() { void Canvas::cleanup() { + noraw(); endwin(); } diff --git a/src/display/utils.cc b/src/display/utils.cc new file mode 100644 index 00000000..4564def2 --- /dev/null +++ b/src/display/utils.cc @@ -0,0 +1,31 @@ +#include "config.h" + +#include + +#include "core/download.h" + +#include "utils.h" + +namespace display { + +std::string +print_download_status(core::Download* d) { + std::stringstream str; + + if (d->get_download().is_hash_checking()) { + str << "Checking hash"; + + } else if (d->get_download().is_tracker_busy()) { + str << "Tracker: Connecting"; + + } else if (!d->get_download().is_active()) { + str << "Inactive"; + + } else { + str << "Tracker: " << d->get_tracker_msg(); + } + + return str.str(); +} + +} diff --git a/src/display/utils.h b/src/display/utils.h new file mode 100644 index 00000000..6ec3c111 --- /dev/null +++ b/src/display/utils.h @@ -0,0 +1,16 @@ +#ifndef RTORRENT_DISPLAY_UTILS_H +#define RTORRENT_DISPLAY_UTILS_H + +#include + +namespace core { + class Download; +} + +namespace display { + +std::string print_download_status(core::Download* d); + +} + +#endif diff --git a/src/display/window_download_list.cc b/src/display/window_download_list.cc index b2896eab..eda2edb5 100644 --- a/src/display/window_download_list.cc +++ b/src/display/window_download_list.cc @@ -1,6 +1,7 @@ #include "config.h" #include "canvas.h" +#include "utils.h" #include "window_download_list.h" namespace display { @@ -70,9 +71,7 @@ WindowDownloadList::redraw() { (double)itr->get_download().get_rate_down() / 1024.0, (double)itr->get_download().get_bytes_up() / (double)(1 << 20)); - m_canvas->print(0, pos++, "%c Tracker: %s", - itr == *m_focus ? '*' : ' ', - itr->get_download().is_tracker_busy() ? "Connecting" : itr->get_tracker_msg().c_str()); + m_canvas->print(0, pos++, "%c %s", itr == *m_focus ? '*' : ' ', print_download_status(&*itr).c_str()); ++itr; } diff --git a/src/display/window_download_statusbar.cc b/src/display/window_download_statusbar.cc index 66b85ce4..247dbe04 100644 --- a/src/display/window_download_statusbar.cc +++ b/src/display/window_download_statusbar.cc @@ -1,6 +1,7 @@ #include "config.h" #include "canvas.h" +#include "utils.h" #include "window_download_statusbar.h" #include "core/download.h" @@ -43,10 +44,10 @@ WindowDownloadStatusbar::redraw() { (int)m_download->get_download().get_peers_max(), (int)m_download->get_download().get_uploads_max()); - m_canvas->print(0, 2, "Tracker: [%c:%i] %s", + m_canvas->print(0, 2, "[%c:%i] %s", m_download->get_download().is_tracker_busy() ? 'C' : ' ', (int)(m_download->get_download().get_tracker_timeout() / 1000000), - m_download->get_tracker_msg().c_str()); + print_download_status(m_download).c_str()); } } diff --git a/src/input/text_input.cc b/src/input/text_input.cc index 8e0f2ad3..e4a51729 100644 --- a/src/input/text_input.cc +++ b/src/input/text_input.cc @@ -9,7 +9,7 @@ namespace input { bool TextInput::pressed(int key) { - //std::stringstream str; + std::stringstream str; if (m_alt) { m_alt = false; @@ -64,19 +64,19 @@ TextInput::pressed(int key) { break; default: - return false; + //return false; // Testcode. -// if (key == KEY_ENTER || key == '\n') -// return false; + if (key == KEY_ENTER || key == '\n') + return false; -// str << "\\x" << std::hex << key; + str << "\\x" << std::hex << key; -// Base::insert(m_pos, str.str()); + Base::insert(m_pos, str.str()); -// m_pos += str.str().length(); + m_pos += str.str().length(); -// return true; + return true; } } diff --git a/src/main.cc b/src/main.cc index 72fe0cc0..9bc602cc 100644 --- a/src/main.cc +++ b/src/main.cc @@ -14,14 +14,8 @@ #endif #include "display/canvas.h" - -#include "core/poll.h" -#include "core/curl_stack.h" -#include "core/manager.h" - #include "ui/control.h" #include "ui/download_list.h" - #include "input/bindings.h" #include "timer.h" @@ -32,9 +26,6 @@ int64_t Timer::m_cache; bool start_shutdown = false; bool is_shutting_down = false; -core::Poll poll; -core::Manager coreManager; - bool is_resized() { static int x = 0; @@ -54,7 +45,7 @@ set_shutdown() { } void -do_shutdown() { +do_shutdown(ui::Control* c) { if (is_shutting_down) // Be quick about it... return; @@ -65,7 +56,7 @@ do_shutdown() { // TODO: Set display to a safe mode. - std::for_each(coreManager.get_download_list().begin(), coreManager.get_download_list().end(), + std::for_each(c->get_core().get_download_list().begin(), c->get_core().get_download_list().end(), std::mem_fun_ref(&core::Download::stop)); } @@ -97,6 +88,8 @@ do_panic(int signum) { int main(int argc, char** argv) { + ui::Control uiControl; + try { SignalHandler::set_handler(SIGINT, sigc::ptr_fun(&set_shutdown)); @@ -104,43 +97,38 @@ main(int argc, char** argv) { SignalHandler::set_handler(SIGBUS, sigc::bind(sigc::ptr_fun(&do_panic), SIGBUS)); display::Canvas::init(); - core::CurlStack::init(); - ui::Control uiControl; - ui::DownloadList uiDownloadList(&coreManager.get_download_list(), &uiControl); + ui::DownloadList uiDownloadList(&uiControl); uiDownloadList.activate(); - uiDownloadList.slot_open_uri(sigc::mem_fun(coreManager, &core::Manager::insert)); + uiDownloadList.slot_open_uri(sigc::mem_fun(uiControl.get_core(), &core::Manager::insert)); // Register main key events. input::Bindings inputMain; uiControl.get_input().push_back(&inputMain); inputMain[KEY_RESIZE] = sigc::mem_fun(uiControl.get_display(), &display::Manager::adjust_layout); + inputMain['\x11'] = sigc::ptr_fun(&set_shutdown); - poll.slot_read_stdin(sigc::mem_fun(uiControl.get_input(), &input::Manager::pressed)); - poll.slot_select_interrupted(sigc::ptr_fun(display::Canvas::do_update)); + uiControl.get_core().get_poll().slot_read_stdin(sigc::mem_fun(uiControl.get_input(), &input::Manager::pressed)); + uiControl.get_core().get_poll().slot_select_interrupted(sigc::ptr_fun(display::Canvas::do_update)); - torrent::Http::set_factory(poll.get_http_factory()); - coreManager.get_http_queue().slot_factory(poll.get_http_factory()); - - torrent::initialize(); - torrent::listen_open(10000, 20000); + uiControl.get_core().initialize(); for (int i = 1; i < argc; ++i) - coreManager.insert(argv[i]); + uiControl.get_core().insert(argv[i]); uiControl.get_display().adjust_layout(); while (!is_shutting_down || !torrent::get(torrent::SHUTDOWN_DONE)) { if (start_shutdown && !is_shutting_down) - do_shutdown(); + do_shutdown(&uiControl); Timer::update(); uiControl.get_display().do_update(); - poll.poll(); + uiControl.get_core().get_poll().poll(); } display::Canvas::cleanup(); @@ -151,8 +139,7 @@ main(int argc, char** argv) { std::cout << "Caught exception: \"" << e.what() << '"' << std::endl; } - torrent::cleanup(); - core::CurlStack::cleanup(); + uiControl.get_core().cleanup(); return 0; } diff --git a/src/ui/control.h b/src/ui/control.h index d959b07a..0c183e47 100644 --- a/src/ui/control.h +++ b/src/ui/control.h @@ -1,6 +1,7 @@ #ifndef RTORRENT_UI_CONTROL_H #define RTORRENT_UI_CONTROL_H +#include "core/manager.h" #include "display/manager.h" #include "input/manager.h" @@ -10,6 +11,7 @@ class Control { public: Control() {} + core::Manager& get_core() { return m_core; } display::Manager& get_display() { return m_display; } input::Manager& get_input() { return m_input; } @@ -17,6 +19,7 @@ private: Control(const Control&); void operator = (const Control&); + core::Manager m_core; display::Manager m_display; input::Manager m_input; }; diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 35c6430e..193ff2c5 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -17,17 +17,16 @@ namespace ui { -DownloadList::DownloadList(core::DownloadList* l, Control* c) : +DownloadList::DownloadList(Control* c) : m_title(new WTitle("rtorrent " VERSION " - " + torrent::get(torrent::LIBRARY_NAME))), m_status(new WStatus), m_download(NULL), - m_list(l), - m_focus(l->end()), + m_focus(c->get_core().get_download_list().end()), m_control(c), m_bindings(new input::Bindings), m_windowInput(new WInput(new input::TextInput)) { - m_window = new WList(m_list, &m_focus); + m_window = new WList(&m_control->get_core().get_download_list(), &m_focus); bind_keys(m_bindings); @@ -64,27 +63,50 @@ DownloadList::disable() { void DownloadList::receive_next() { - if (m_focus != m_list->end()) + if (m_focus != m_control->get_core().get_download_list().end()) ++m_focus; else - m_focus = m_list->begin(); + m_focus = m_control->get_core().get_download_list().begin(); mark_dirty(); } void DownloadList::receive_prev() { - if (m_focus != m_list->begin()) + if (m_focus != m_control->get_core().get_download_list().begin()) --m_focus; else - m_focus = m_list->end(); + m_focus = m_control->get_core().get_download_list().end(); mark_dirty(); } +void +DownloadList::receive_throttle(int t) { + m_status->mark_dirty(); + + torrent::set(torrent::THROTTLE_ROOT_CONST_RATE, torrent::get(torrent::THROTTLE_ROOT_CONST_RATE) + t * 1024); +} + +void +DownloadList::receive_start_download() { + if (m_focus == m_control->get_core().get_download_list().end()) + return; + + m_control->get_core().start(&*m_focus); +} + +void +DownloadList::receive_stop_download() { + if (m_focus == m_control->get_core().get_download_list().end()) + return; + + m_control->get_core().stop(&*m_focus); +} + void DownloadList::receive_view_download() { - if (m_focus == m_list->end()) + if (m_focus == m_control->get_core().get_download_list().end()) return; if (m_download != NULL) @@ -112,13 +134,6 @@ DownloadList::receive_exit_download() { m_control->get_display().adjust_layout(); } -void -DownloadList::receive_throttle(int t) { - m_status->mark_dirty(); - - torrent::set(torrent::THROTTLE_ROOT_CONST_RATE, torrent::get(torrent::THROTTLE_ROOT_CONST_RATE) + t * 1024); -} - void DownloadList::receive_view_input() { m_control->get_input().set_text_input(m_windowInput->get_input()); @@ -151,6 +166,9 @@ DownloadList::bind_keys(input::Bindings* b) { (*b)['d'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::receive_throttle), 50); (*b)['c'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::receive_throttle), -50); + (*b)['\x13'] = sigc::mem_fun(*this, &DownloadList::receive_start_download); + (*b)['\x04'] = sigc::mem_fun(*this, &DownloadList::receive_stop_download); + (*b)[KEY_UP] = sigc::mem_fun(*this, &DownloadList::receive_prev); (*b)[KEY_DOWN] = sigc::mem_fun(*this, &DownloadList::receive_next); (*b)[KEY_RIGHT] = sigc::mem_fun(*this, &DownloadList::receive_view_download); diff --git a/src/ui/download_list.h b/src/ui/download_list.h index d4e22e1a..7a55c0c9 100644 --- a/src/ui/download_list.h +++ b/src/ui/download_list.h @@ -26,7 +26,7 @@ public: typedef sigc::slot1 SlotOpenUri; // We own 'window'. - DownloadList(DList* l, Control* c); + DownloadList(Control* c); ~DownloadList(); WList& get_window() { return *m_window; } @@ -44,11 +44,14 @@ private: void receive_next(); void receive_prev(); + void receive_throttle(int t); + + void receive_start_download(); + void receive_stop_download(); + void receive_view_download(); void receive_exit_download(); - void receive_throttle(int t); - void receive_view_input(); void receive_exit_input();