diff --git a/src/command_peer.cc b/src/command_peer.cc index 4b1a3933..deff3e89 100644 --- a/src/command_peer.cc +++ b/src/command_peer.cc @@ -38,51 +38,61 @@ #include #include +#include +#include +#include +#include #include +#include #include "core/manager.h" +#include "display/utils.h" #include "globals.h" #include "control.h" #include "command_helpers.h" -// void -// apply_f_set_priority(torrent::File* file, uint32_t value) { -// if (value > torrent::PRIORITY_HIGH) -// throw torrent::input_error("Invalid value."); +torrent::Object +retrieve_p_id(torrent::Peer* peer) { + const torrent::HashString* hashString = &peer->id(); -// file->set_priority((torrent::priority_t)value); -// } + return rak::transform_hex(hashString->begin(), hashString->end()); +} -// torrent::Object -// apply_f_path(torrent::File* file) { -// if (file->path()->empty()) -// return std::string(); +torrent::Object +retrieve_p_id_html(torrent::Peer* peer) { + const torrent::HashString* hashString = &peer->id(); -// torrent::Object resultRaw(*file->path()->begin()); -// torrent::Object::string_type& result = resultRaw.as_string(); + return rak::copy_escape_html(hashString->begin(), hashString->end()); +} -// for (torrent::Path::const_iterator itr = ++file->path()->begin(), last = file->path()->end(); itr != last; itr++) -// result += '/' + *itr; +torrent::Object +retrieve_p_address(torrent::Peer* peer) { + return rak::socket_address::cast_from(peer->info()->socket_address())->address_str(); +} -// return resultRaw; -// } +torrent::Object +retrieve_p_port(torrent::Peer* peer) { + return rak::socket_address::cast_from(peer->info()->socket_address())->port(); +} -// torrent::Object -// apply_f_path_components(torrent::File* file) { -// torrent::Object resultRaw(torrent::Object::TYPE_LIST); -// torrent::Object::list_type& result = resultRaw.as_list(); +torrent::Object +retrieve_p_client_version(torrent::Peer* peer) { + char buf[128]; + display::print_client_version(buf, buf + 128, peer->info()->client_info()); -// for (torrent::Path::const_iterator itr = file->path()->begin(), last = file->path()->end(); itr != last; itr++) -// result.push_back(*itr); + return std::string(buf); +} -// return resultRaw; -// } +torrent::Object +retrieve_p_options_str(torrent::Peer* peer) { + return rak::transform_hex(peer->info()->options(), peer->info()->options() + 8); +} -// torrent::Object -// apply_f_path_depth(torrent::File* file) { -// return (int64_t)file->path()->size(); -// } +torrent::Object +retrieve_p_completed_percent(torrent::Peer* peer) { + return (100 * peer->bitfield()->size_set()) / peer->bitfield()->size_bits(); +} #define ADD_CP_SLOT(key, function, slot, parm, doc) \ commandPeerSlotsItr->set_slot(slot); \ @@ -95,6 +105,9 @@ #define ADD_CP_VOID(key, slot) \ ADD_CP_SLOT_PUBLIC("p.get_" key, call_unknown, rpc::object_fn(slot), "i:", "") +#define ADD_CP_VALUE(key, get) \ + ADD_CP_SLOT_PUBLIC("p." key, call_unknown, rpc::object_void_fn(get), "i:", "") + #define ADD_CP_VALUE_UNI(key, get) \ ADD_CP_SLOT_PUBLIC("p.get_" key, call_unknown, rpc::object_void_fn(get), "i:", "") @@ -102,31 +115,34 @@ ADD_CP_SLOT_PUBLIC("p.set_" key, call_value, rpc::object_value_fn(set), "i:i", "") \ ADD_CP_SLOT_PUBLIC("p.get_" key, call_unknown, rpc::object_void_fn(get), "i:", "") +#define ADD_CP_VALUE_MEM_UNI(key, target, get) \ + ADD_CP_SLOT_PUBLIC("p.get_" key, call_unknown, rpc::object_void_fn(rak::on(std::mem_fun(target), std::mem_fun(get))), "i:", ""); + #define ADD_CP_STRING_UNI(key, get) \ ADD_CP_SLOT_PUBLIC("p.get_" key, call_unknown, rpc::object_void_fn(get), "s:", "") void initialize_command_peer() { -// ADD_CP_VALUE_UNI("is_created", std::mem_fun(&torrent::Peer::is_created)); -// ADD_CP_VALUE_UNI("is_open", std::mem_fun(&torrent::Peer::is_open)); + ADD_CP_STRING_UNI("id", std::ptr_fun(&retrieve_p_id)); + ADD_CP_STRING_UNI("id_html", std::ptr_fun(&retrieve_p_id_html)); + ADD_CP_STRING_UNI("client_version", std::ptr_fun(&retrieve_p_client_version)); -// ADD_CP_VALUE_UNI("size_bytes", std::mem_fun(&torrent::Peer::size_bytes)); -// ADD_CP_VALUE_UNI("size_chunks", std::mem_fun(&torrent::Peer::size_chunks)); -// ADD_CP_VALUE_UNI("completed_chunks", std::mem_fun(&torrent::Peer::completed_chunks)); + ADD_CP_STRING_UNI("options_str", std::ptr_fun(&retrieve_p_options_str)); -// ADD_CP_VALUE_UNI("offset", std::mem_fun(&torrent::Peer::offset)); -// ADD_CP_VALUE_UNI("range_first", std::mem_fun(&torrent::Peer::range_first)); -// ADD_CP_VALUE_UNI("range_second", std::mem_fun(&torrent::Peer::range_second)); + ADD_CP_VALUE("is_encrypted", std::mem_fun(&torrent::Peer::is_encrypted)); + ADD_CP_VALUE("is_incoming", std::mem_fun(&torrent::Peer::is_incoming)); + ADD_CP_VALUE("is_obfuscated", std::mem_fun(&torrent::Peer::is_obfuscated)); + ADD_CP_VALUE("is_snubbed", std::mem_fun(&torrent::Peer::is_snubbed)); -// ADD_CP_VALUE_BI("priority", std::ptr_fun(&apply_f_set_priority), std::mem_fun(&torrent::Peer::priority)); + ADD_CP_STRING_UNI("address", std::ptr_fun(&retrieve_p_address)); + ADD_CP_VALUE_UNI("port", std::ptr_fun(&retrieve_p_port)); -// ADD_CP_STRING_UNI("path", std::ptr_fun(&apply_f_path)); -// ADD_CP_STRING_UNI("path_components", std::ptr_fun(&apply_f_path_components)); -// ADD_CP_STRING_UNI("path_depth", std::ptr_fun(&apply_f_path_depth)); -// ADD_CP_STRING_UNI("frozen_path", std::mem_fun(&torrent::Peer::frozen_path)); + ADD_CP_VALUE_UNI("completed_percent", std::ptr_fun(&retrieve_p_completed_percent)); -// ADD_CP_VALUE_UNI("match_depth_prev", std::mem_fun(&torrent::Peer::match_depth_prev)); -// ADD_CP_VALUE_UNI("match_depth_next", std::mem_fun(&torrent::Peer::match_depth_next)); - -// ADD_CP_VALUE_UNI("last_touched", std::mem_fun(&torrent::Peer::last_touched)); + ADD_CP_VALUE_MEM_UNI("up_rate", &torrent::Peer::up_rate, &torrent::Rate::rate); + ADD_CP_VALUE_MEM_UNI("up_total", &torrent::Peer::up_rate, &torrent::Rate::total); + ADD_CP_VALUE_MEM_UNI("down_rate", &torrent::Peer::down_rate, &torrent::Rate::rate); + ADD_CP_VALUE_MEM_UNI("down_total", &torrent::Peer::down_rate, &torrent::Rate::total); + ADD_CP_VALUE_MEM_UNI("peer_rate", &torrent::Peer::peer_rate, &torrent::Rate::rate); + ADD_CP_VALUE_MEM_UNI("peer_total", &torrent::Peer::peer_rate, &torrent::Rate::total); } diff --git a/src/display/text_element_helpers.h b/src/display/text_element_helpers.h index 9d3dacb7..ab74a5c7 100644 --- a/src/display/text_element_helpers.h +++ b/src/display/text_element_helpers.h @@ -61,141 +61,6 @@ te_command(const char* command, int flags = TextElementCommand::flag_normal, int // End All we're ever going to need. -typedef TextElementStringBase string_base; -typedef TextElementValueBase value_base; - -// String stuff: - -inline TextElementStringBase* -te_string(const char* str) { - return new TextElementCString(str); -} - -// template -// inline TextElementStringBase* -// te_string(Return (Object::*fptr)() const, const Object* object, int attributes = Attributes::a_invalid) { -// return text_element_string_void(rak::make_mem_fun(object, fptr), attributes); -// } - -template -inline TextElementStringBase* -te_string(Return (*fptr)(Arg1), int flags = TextElementStringBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_string_slot(std::ptr_fun(fptr), flags, attributes); -} - -template -inline TextElementStringBase* -te_string(Return (core::Download::*fptr)() const, int flags = TextElementStringBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_string_slot(std::mem_fun(fptr), flags, attributes); -} - -template -inline TextElementStringBase* -te_string(Return (torrent::Download::*fptr)() const, int flags = TextElementStringBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_string_slot(rak::on(std::mem_fun(&core::Download::c_download), std::mem_fun(fptr)), flags, attributes); -} - -template -inline TextElementStringBase* -te_string(Return (torrent::FileList::*fptr)() const, int flags = TextElementStringBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_string_slot(rak::on(std::mem_fun(&core::Download::file_list), std::mem_fun(fptr)), flags, attributes); -} - -// TMP HACK -inline std::string te_call_command_d_string(const char* key, core::Download* download) { return rpc::commands.call_command(key, torrent::Object(), rpc::make_target(download)).as_string(); } -inline int64_t te_call_command_d_value(const char* key, core::Download* download) { return rpc::commands.call_command(key, torrent::Object(), rpc::make_target(download)).as_value(); } - -inline TextElementStringBase* -te_variable_string(const char* variable, int flags = TextElementStringBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_string_slot(rak::bind1st(std::ptr_fun(&te_call_command_d_string), variable), flags, attributes); -} - -// Value stuff: - -template -inline TextElementValueBase* -te_value(Return (torrent::Download::*fptr)() const, int flags = TextElementValueBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_value_slot(rak::on(std::mem_fun(&core::Download::c_download), std::mem_fun(fptr)), flags, attributes); -} - -template -inline TextElementValueBase* -te_value(Return (torrent::FileList::*fptr)() const, int flags = TextElementValueBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_value_slot(rak::on(std::mem_fun(&core::Download::c_file_list), std::mem_fun(fptr)), flags, attributes); -} - -template -inline TextElementValueBase* -te_value(Return (torrent::File::*fptr)() const, int flags = TextElementValueBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_value_slot(rak::on(std::mem_fun(&torrent::FileListIterator::file), std::mem_fun(fptr)), flags, attributes); -} - -inline TextElementValueBase* -te_variable_value(const char* variable, int flags = TextElementValueBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_value_slot(rak::bind1st(std::ptr_fun(&te_call_command_d_value), variable), flags, attributes); -} - -template -inline TextElementValueBase* -te_value(Return (torrent::ChunkManager::*fptr)() const, int flags = TextElementValueBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_value_void(rak::make_mem_fun(torrent::chunk_manager(), fptr), flags, attributes); -} - -template -inline TextElementValueBase* -te_value(Return (torrent::ConnectionManager::*fptr)() const, int flags = TextElementValueBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_value_void(rak::make_mem_fun(torrent::connection_manager(), fptr), flags, attributes); -} - -// Various: - -inline unsigned int -te_bitfield_percentage(const torrent::Bitfield* bitfield) { - return bitfield != NULL ? (100 * bitfield->size_set()) / bitfield->size_bits() : 0; -} - -inline std::string -te_address(const ::sockaddr* address) { - return rak::socket_address::cast_from(address)->address_str(); -} - -inline unsigned int -te_port(const ::sockaddr* address) { - return rak::socket_address::cast_from(address)->port(); -} - -// Lambda - -template -inline TextElement* -te_branch(Return (*fptr)(), TextElement* branch1, TextElement* branch2) { - return text_element_branch_void(std::mem_fun(fptr), branch1, branch2); -} - -template -inline TextElement* -te_branch(Return (*fptr)(Arg1), TextElement* branch1, TextElement* branch2) { - return text_element_branch(std::mem_fun(fptr), branch1, branch2); -} - -template -inline TextElement* -te_branch(Return (Object::*fptr)() const, TextElement* branch1, TextElement* branch2) { - return text_element_branch(std::mem_fun(fptr), branch1, branch2); -} - -template -inline TextElement* -te_branch(Return (Object::*fptr)() const, const Object* object, TextElement* branch1, TextElement* branch2) { - return text_element_branch_void(rak::make_mem_fun(object, fptr), branch1, branch2); -} - -template -inline TextElement* -te_branch(Return1 (Object1::*fptr1)() const, Return2 (Object2::*fptr2)() const, TextElement* branch1, TextElement* branch2) { - return text_element_branch(rak::on(std::mem_fun(fptr1), std::mem_fun(fptr2)), branch1, branch2); -} - } } #endif diff --git a/src/display/window_text.cc b/src/display/window_text.cc index a7712aa9..39ca9515 100644 --- a/src/display/window_text.cc +++ b/src/display/window_text.cc @@ -48,6 +48,7 @@ namespace display { WindowText::WindowText(rpc::target_type target, extent_type margin) : Window(new Canvas, 0, 0, 0, extent_static, extent_static), m_target(target), + m_errorHandler(NULL), m_margin(margin), m_interval(0) { } @@ -56,6 +57,9 @@ void WindowText::clear() { std::for_each(begin(), end(), rak::call_delete()); base_type::clear(); + + delete m_errorHandler; + m_errorHandler = NULL; } void @@ -86,6 +90,21 @@ WindowText::redraw() { unsigned int position = 0; + if (m_canvas->height() == 0) + return; + + if (m_errorHandler != NULL && m_target.second == NULL) { + char buffer[m_canvas->width() + 1]; + + Canvas::attributes_list attributes; + attributes.push_back(Attributes(buffer, Attributes::a_normal, Attributes::color_default)); + + char* last = m_errorHandler->print(buffer, buffer + m_canvas->width(), &attributes, m_target); + + m_canvas->print_attributes(0, position, buffer, last, &attributes); + return; + } + for (iterator itr = begin(); itr != end() && position < m_canvas->height(); ++itr, ++position) { if (*itr == NULL) continue; diff --git a/src/display/window_text.h b/src/display/window_text.h index 49079a38..cadcc988 100644 --- a/src/display/window_text.h +++ b/src/display/window_text.h @@ -75,10 +75,15 @@ public: void push_back(TextElement* element); + // Set an error handler if targets pointing to NULL elements should + // be handled separately to avoid throwing errors. + void set_error_handler(TextElement* element) { m_errorHandler = element; } + virtual void redraw(); private: rpc::target_type m_target; + TextElement* m_errorHandler; extent_type m_margin; uint32_t m_interval; diff --git a/src/ui/element_peer_list.cc b/src/ui/element_peer_list.cc index c42a0980..b7691e22 100644 --- a/src/ui/element_peer_list.cc +++ b/src/ui/element_peer_list.cc @@ -89,14 +89,6 @@ ElementPeerList::~ElementPeerList() { delete m_elementInfo; } -std::string -te_client_version(const torrent::PeerInfo* info) { - char buf[128]; - display::print_client_version(buf, buf + 128, info->client_info()); - - return buf; -} - inline ElementText* ElementPeerList::create_info() { using namespace display::helpers; @@ -106,33 +98,24 @@ ElementPeerList::create_info() { element->set_column(1); element->set_interval(1); - // Get these bindings with some kind of string map. - element->push_back("Peer info:"); element->push_back(""); - element->push_column("Address:", - display::text_element_string_slot(rak::on(std::mem_fun(&torrent::Peer::address), std::ptr_fun(&te_address))), ":", - display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::address), std::ptr_fun(&te_port)))); - - element->push_column("Id:", display::text_element_string_slot(std::mem_fun(&torrent::Peer::id), string_base::flag_escape_html)); -// element->push_column("Client:", display::text_element_string_slot(rak::on(std::mem_fun(&torrent::Peer::id), rak::make_mem_fun(control->client_info(), &display::ClientInfo::hash_str)))); - element->push_column("Client:", display::text_element_string_slot(rak::on(std::mem_fun(&torrent::Peer::info), std::ptr_fun(&te_client_version)))); - element->push_column("Options:", display::text_element_string_slot(std::mem_fun(&torrent::Peer::options), string_base::flag_escape_hex | string_base::flag_fixed_width, 0, 8)); - element->push_column("Connected:", display::text_element_branch(std::mem_fun(&torrent::Peer::is_incoming), te_string("incoming"), te_string("outgoing"))); - element->push_column("Encrypted:", display::text_element_branch3(std::mem_fun(&torrent::Peer::is_encrypted), te_string("yes"), std::mem_fun(&torrent::Peer::is_obfuscated), te_string("handshake"), te_string("no"))); + element->push_column("Address:", te_command("cat=$p.get_address=,:,$p.get_port=")); + element->push_column("Id:", te_command("p.get_id_html=")); + element->push_column("Client:", te_command("p.get_client_version=")); + element->push_column("Options:", te_command("p.get_options_str=")); + element->push_column("Connected:", te_command("if=$p.is_incoming=,incoming,outgoing")); + element->push_column("Encrypted:", te_command("if=$p.is_encrypted=,yes,$p.is_obfuscated=,handshake,no")); element->push_back(""); - element->push_column("Snubbed:", display::text_element_branch(std::mem_fun(&torrent::Peer::is_snubbed), te_string("yes"), te_string("no"))); - element->push_column("Done:", display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::bitfield), std::ptr_fun(&te_bitfield_percentage)))); - element->push_column("Rate:", - display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::up_rate), std::mem_fun(&torrent::Rate::rate)), value_base::flag_kb), " KB / ", - display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::down_rate), std::mem_fun(&torrent::Rate::rate)), value_base::flag_kb), " KB"); - element->push_column("Total:", - display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::up_rate), std::mem_fun(&torrent::Rate::total)), value_base::flag_xb), " / ", - display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::down_rate), std::mem_fun(&torrent::Rate::total)), value_base::flag_xb)); + element->push_column("Snubbed:", te_command("if=$p.is_snubbed=,yes,no")); + element->push_column("Done:", te_command("p.get_completed_percent=")); + element->push_column("Rate:", te_command("cat=$to_kb=$p.get_up_rate=,\\ KB\\ ,$to_kb=$p.get_down_rate=,\\ KB")); + element->push_column("Total:", te_command("cat=$to_kb=$p.get_up_total=,\\ KB\\ ,$to_kb=$p.get_down_total=,\\ KB")); element->set_column_width(element->column_width() + 1); + element->set_error_handler(new display::TextElementCString("No peer selected.")); return element; } diff --git a/src/ui/element_text.h b/src/ui/element_text.h index 3d009b74..4f4af86e 100644 --- a/src/ui/element_text.h +++ b/src/ui/element_text.h @@ -95,10 +95,11 @@ public: text_element_wrapper entry3, text_element_wrapper entry4, text_element_wrapper entry5, text_element_wrapper entry6); - void set_column(unsigned int column) { m_column = column; } + void set_column(unsigned int column) { m_column = column; } + void set_error_handler(display::TextElement* t) { m_window->set_error_handler(t); } - extent_type column_width() const { return m_columnWidth; } - void set_column_width(extent_type width) { m_columnWidth = width; } + extent_type column_width() const { return m_columnWidth; } + void set_column_width(extent_type width) { m_columnWidth = width; } private: WindowText* m_window;