#include "config.h" #include "display/window_peer_list.h" #include #include #include #include #include #include #include #include "core/download.h" #include "display/canvas.h" #include "display/utils.h" namespace display { namespace { char connection_type_char(const torrent::Peer* p) { if (p->is_encrypted()) return p->is_incoming() ? 'R' : 'L'; if (p->is_obfuscated()) return p->is_incoming() ? 'H' : 'h'; return p->is_incoming() ? 'r' : 'l'; } } // namespace WindowPeerList::WindowPeerList(core::Download* d, PList* l, PList::iterator* f) : Window(new Canvas, 0, 0, 0, extent_full, extent_full), m_download(d), m_list(l), m_focus(f) { } void WindowPeerList::redraw() { schedule_update(); m_canvas->erase(); int x = 2; int y = 0; m_canvas->print(x, y, "IP"); x += 25; m_canvas->print(x, y, "UP"); x += 7; m_canvas->print(x, y, "DOWN"); x += 7; m_canvas->print(x, y, "PEER"); x += 7; // CT: R/H/r or L/h/l (RC4 / handshake-only / plain) + peer type (u/p/ ) m_canvas->print(x, y, "CT/RE/LO"); x += 10; m_canvas->print(x, y, "QS"); x += 6; m_canvas->print(x, y, "DONE"); x += 6; m_canvas->print(x, y, "REQ"); x += 6; m_canvas->print(x, y, "SNUB"); x += 6; m_canvas->print(x, y, "FAILED"); ++y; if (m_list->empty()) return; typedef std::pair Range; Range range = advance_bidirectional(m_list->begin(), *m_focus != m_list->end() ? *m_focus : m_list->begin(), m_list->end(), m_canvas->height() - y); if (m_download->download()->file_list()->size_chunks() <= 0) throw std::logic_error("WindowPeerList::redraw() m_slotChunksTotal() returned invalid value"); while (range.first != range.second) { torrent::Peer* p = *range.first; x = 0; auto ip_address = torrent::sa_addr_str(p->address()); if (ip_address.size() >= 24) { ip_address.replace(ip_address.begin() + 21, ip_address.end(), "..."); } m_canvas->print(x, y, "%c %s", range.first == *m_focus ? '*' : ' ', ip_address.c_str()); x += 27; m_canvas->print(x, y, "%.1f", (double)p->up_rate()->rate() / 1024); x += 7; m_canvas->print(x, y, "%.1f", (double)p->down_rate()->rate() / 1024); x += 7; m_canvas->print(x, y, "%.1f", (double)p->peer_rate()->rate() / 1024); x += 7; char remoteChoked; char peerType; if (!p->is_down_choked_limited()) remoteChoked = 'U'; else if (p->is_down_queued()) remoteChoked = 'Q'; else remoteChoked = 'C'; if (p->peer_info()->is_blocked()) peerType = 'u'; else if (p->peer_info()->is_preferred()) peerType = 'p'; else peerType = ' '; m_canvas->print(x, y, "%c%c/%c%c/%c%c", connection_type_char(p), peerType, p->is_down_choked() ? std::tolower(remoteChoked) : remoteChoked, p->is_down_interested() ? 'i' : 'n', p->is_up_choked() ? 'c' : 'u', p->is_up_interested() ? 'i' : 'n'); x += 10; m_canvas->print(x, y, "%i/%i", p->outgoing_queue_size(), p->incoming_queue_size()); x += 6; m_canvas->print(x, y, "%3i", done_percentage(*range.first)); x += 6; const torrent::BlockTransfer* transfer = p->transfer(); if (transfer != NULL) m_canvas->print(x, y, "%i", transfer->index()); x += 6; if (p->is_snubbed()) m_canvas->print(x, y, "*"); x += 6; if (p->failed_counter() != 0) m_canvas->print(x, y, "%u", p->failed_counter()); x += 7; char buf[128]; print_client_version(buf, buf + 128, p->peer_info()->client_info()); m_canvas->print(x, y, "%s", buf); ++y; ++range.first; } } int WindowPeerList::done_percentage(torrent::Peer* p) { int chunks = m_download->download()->file_list()->size_chunks(); return chunks ? (100 * p->chunks_done()) / chunks : 0; } }