mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-06 02:02:30 +00:00
172 lines
5.0 KiB
C++
172 lines
5.0 KiB
C++
#include "config.h"
|
|
|
|
#include "control.h"
|
|
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <torrent/net/http_stack.h>
|
|
#include <torrent/runtime/network_manager.h>
|
|
#include <torrent/runtime/runtime.h>
|
|
#include <torrent/utils/directory_events.h>
|
|
|
|
#include "core/dht_manager.h"
|
|
#include "core/http_queue.h"
|
|
#include "core/manager.h"
|
|
#include "core/view_manager.h"
|
|
#include "display/canvas.h"
|
|
#include "display/window.h"
|
|
#include "display/window_http_queue.h"
|
|
#include "display/window_input.h"
|
|
#include "display/window_statusbar.h"
|
|
#include "display/window_title.h"
|
|
#include "display/manager.h"
|
|
#include "input/manager.h"
|
|
#include "input/input_event.h"
|
|
#include "rpc/command_scheduler.h"
|
|
#include "rpc/lua.h"
|
|
#include "rpc/parse_commands.h"
|
|
#include "rpc/object_storage.h"
|
|
#include "session/session_manager.h"
|
|
#include "ui/root.h"
|
|
#include "utils/watch_ready_queue.h"
|
|
|
|
Control::Control()
|
|
: m_ui(new ui::Root()),
|
|
m_display(new display::Manager()),
|
|
m_input(new input::Manager()),
|
|
m_inputStdin(new input::InputEvent(STDIN_FILENO)),
|
|
m_commandScheduler(new rpc::CommandScheduler()),
|
|
m_objectStorage(new rpc::object_storage()),
|
|
m_lua_engine(new rpc::LuaEngine()),
|
|
m_directory_events(new torrent::directory_events()),
|
|
m_watch_ready_queue(new utils::WatchReadyQueue()) {
|
|
|
|
m_core = std::make_unique<core::Manager>();
|
|
m_view_manager = std::make_unique<core::ViewManager>();
|
|
m_dht_manager = std::make_unique<core::DhtManager>();
|
|
|
|
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input.get(), std::placeholders::_1));
|
|
|
|
m_task_shutdown.slot() = [this] { handle_shutdown(); };
|
|
m_task_shutdown_clear_requests.slot() = [this] { handle_shutdown_clear_requests(); };
|
|
|
|
m_commandScheduler->set_slot_error_message([this](const std::string& msg) { m_core->push_log_std(msg); });
|
|
}
|
|
|
|
Control::~Control() {
|
|
m_view_manager.reset();
|
|
|
|
m_ui.reset();
|
|
m_display.reset();
|
|
}
|
|
|
|
void
|
|
Control::initialize() {
|
|
session_thread::thread()->start_thread();
|
|
scgi_thread::thread()->start_thread();
|
|
|
|
display::Canvas::initialize();
|
|
display::Window::slot_schedule([this](display::Window* w, std::chrono::microseconds t) { m_display->schedule(w, t); });
|
|
display::Window::slot_unschedule([this](display::Window* w) { m_display->unschedule(w); });
|
|
display::Window::slot_adjust([this]() { m_display->adjust_layout(); });
|
|
|
|
m_core->set_hashing_view(*m_view_manager->find_throw("hashing"));
|
|
|
|
m_ui->init(this);
|
|
|
|
if(!display::Canvas::daemon())
|
|
m_inputStdin->insert();
|
|
}
|
|
|
|
void
|
|
Control::cleanup() {
|
|
rpc::rpc.cleanup();
|
|
|
|
torrent::this_thread::scheduler()->erase(&m_task_shutdown);
|
|
torrent::this_thread::scheduler()->erase(&m_task_shutdown_clear_requests);
|
|
|
|
if(!display::Canvas::daemon())
|
|
m_inputStdin->remove();
|
|
|
|
m_directory_events->close();
|
|
|
|
if (scgi_thread::thread()->is_active())
|
|
scgi_thread::thread()->stop_thread_wait();
|
|
|
|
// Wait for all session files to be written.
|
|
session_thread::manager()->flush_all_pending_builds();
|
|
session_thread::thread()->stop_thread_wait();
|
|
|
|
m_ui->cleanup();
|
|
m_core->cleanup();
|
|
|
|
display::Canvas::erase_std();
|
|
display::Canvas::refresh_std();
|
|
display::Canvas::do_update();
|
|
display::Canvas::cleanup();
|
|
}
|
|
|
|
void
|
|
Control::cleanup_exception() {
|
|
display::Canvas::cleanup();
|
|
}
|
|
|
|
bool
|
|
Control::is_shutdown_completed() {
|
|
if (!m_shutdown_quick)
|
|
return false;
|
|
|
|
// Tracker requests can be disowned, so wait for these to
|
|
// finish. The edge case of torrent http downloads may delay
|
|
// shutdown.
|
|
|
|
// TODO: We keep http requests in the queue for a while after, so improve this check to ignore
|
|
// those.
|
|
if (torrent::net_thread::http_stack()->size() != 0 || !core()->http_queue()->empty())
|
|
return false;
|
|
|
|
return core()->is_download_shutdown_completed();
|
|
}
|
|
|
|
void
|
|
Control::handle_shutdown() {
|
|
m_watch_ready_queue->shutdown();
|
|
|
|
rpc::commands.call_catch("event.system.shutdown", rpc::make_target(), "shutdown", "System shutdown event action failed: ");
|
|
|
|
if (scgi_thread::thread()->is_active())
|
|
scgi_thread::thread()->stop_thread_wait();
|
|
|
|
if (!m_shutdown_quick) {
|
|
torrent::runtime::network_manager()->listen_close();
|
|
torrent::runtime::shutdown();
|
|
|
|
m_directory_events->close();
|
|
m_core->shutdown(false);
|
|
|
|
if (!m_task_shutdown.is_scheduled())
|
|
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown, 5s);
|
|
|
|
} else {
|
|
torrent::runtime::quick_shutdown();
|
|
m_core->shutdown(true);
|
|
}
|
|
|
|
if (!m_task_shutdown_clear_requests.is_scheduled())
|
|
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown_clear_requests, 10s);
|
|
|
|
m_shutdown_quick = true;
|
|
m_shutdown_received = false;
|
|
}
|
|
|
|
void
|
|
Control::handle_shutdown_clear_requests() {
|
|
torrent::net_thread::http_stack()->clear_requests();
|
|
|
|
// Use 5s for the initial wait to ensure trackers get a chance to finish both IPv4 and IPv6 requests.
|
|
if (m_clear_requests_count++ == 0)
|
|
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 5s);
|
|
else
|
|
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 1s);
|
|
}
|