console.cpp
来自「最经典的bittorrent协议的实现的源码」· C++ 代码 · 共 1,273 行 · 第 1/3 页
CPP
1,273 行
Interact("Enter 0 or * for all files (normal behavior)."); if( arg_file_to_download ) Interact_n("Get file number/list (currently %s): ", arg_file_to_download); else Interact_n("Get file number/list: "); break; case 'S': // CTCS server m_streams[O_INPUT]->SetInputMode(K_LINES); Interact_n(""); if( arg_ctcs ) Interact_n("CTCS server:port (currently %s): ", arg_ctcs); else Interact_n("CTCS server:port: "); break; case 'X': // completion command (user exit) m_streams[O_INPUT]->SetInputMode(K_LINES); Interact("Enter a command to run upon download completion."); if( arg_completion_exit ) Interact("Currently: %s", arg_completion_exit); Interact_n(">"); break; case 'v': // verbose if( arg_verbose && !m_streams[O_INPUT]->SameDev(m_streams[O_DEBUG]) ) Debug("Verbose output off"); arg_verbose = !arg_verbose; Interact("Verbose output %s", arg_verbose ? "on" : "off"); break; case 'Q': // quit if( !Tracker.IsQuitting() ){ m_streams[O_INPUT]->SetInputMode(K_LINES); Interact_n(""); Interact_n("Quit: Are you sure? "); } break; case '+': // increase value case '-': // decrease value if( ('+'==c && inc<0) || ('-'==c && inc>0) ) inc *= -1; switch( pending ){ int value; case 'd': cfg_max_bandwidth_down += ( (cfg_max_bandwidth_down * (abs(inc)/100.0) < 1) ? inc : (int)(cfg_max_bandwidth_down * (inc/100.0)) ); if( cfg_max_bandwidth_down < 0 ) cfg_max_bandwidth_down = 0; break; case 'u': cfg_max_bandwidth_up += ( (cfg_max_bandwidth_up * (abs(inc)/100.0) < 1) ? inc : (int)(cfg_max_bandwidth_up * (inc/100.0)) ); if( cfg_max_bandwidth_up < 0 ) cfg_max_bandwidth_up = 0; break; case 'e': cfg_seed_hours += inc; if( cfg_seed_hours < 0 ) cfg_seed_hours = 0; break; case 'E': cfg_seed_ratio += inc / 10.0; if( cfg_seed_ratio < 0 ) cfg_seed_ratio = 0; break; case 'm': value = (int)cfg_min_peers; value += inc; cfg_min_peers = (value < 1) ? 1 : (size_t)value; if( cfg_min_peers > cfg_max_peers ) cfg_min_peers = cfg_max_peers; break; case 'M': value = (int)cfg_max_peers; value += inc; cfg_max_peers = (value < (int)cfg_min_peers) ? cfg_min_peers : (size_t)value; if( cfg_max_peers > 1000 ) cfg_max_peers = 1000; break; case 'C': value = (int)cfg_cache_size; value += inc; cfg_cache_size = (value < 0) ? 0 : (size_t)value; BTCONTENT.CacheConfigure(); break; default: Status(1); break; } if( 10==++count ) inc *= 2; else if( 5==count ) inc *= 5; if( arg_ctcs ){ if( 'd'==pending || 'u'==pending ) CTCS.Send_bw(); else CTCS.Send_Config(); } break; case '0': // operator menu case 0x1b: // Escape key pending = '0'; OperatorMenu(""); break; default: Status(1); break; } switch( pending ){ case 'd': InteractU("DL Limit: %d B/s ", (int)cfg_max_bandwidth_down); break; case 'u': InteractU("UL Limit: %d B/s ", (int)cfg_max_bandwidth_up); break; case 'e': InteractU("Seed time: %.1f hours ", BTCONTENT.GetSeedTime() ? (cfg_seed_hours - (now - BTCONTENT.GetSeedTime())/(double)3600) : (double)cfg_seed_hours); break; case 'E': InteractU("Seed ratio: %.2f ", (double)cfg_seed_ratio); break; case 'm': InteractU("Minimum peers: %d ", (int)cfg_min_peers); break; case 'M': InteractU("Maximum peers: %d ", (int)cfg_max_peers); break; case 'C': InteractU("Maximum cache: %d MB ", (int)cfg_cache_size); break; default: break; } } }}// Return non-zero to exit operator menu mode.int Console::OperatorMenu(const char *param){ static int oper_mode = 0; static int channel, n_opt; if( 0==oper_mode ){ Interact("Operator Menu"); n_opt = 0; Interact(" Console Channels:"); Interact(" %2d) Normal/status: %s", ++n_opt, m_streams[O_NORMAL]->GetName()); Interact(" %2d) Interactive: %s", ++n_opt, m_streams[O_INTERACT]->GetName()); Interact(" %2d) Error/warning: %s", ++n_opt, m_streams[O_WARNING]->GetName()); Interact(" %2d) Debug/verbose: %s", ++n_opt, m_streams[O_DEBUG]->GetName()); Interact(" %2d) Input: %s", ++n_opt, m_streams[O_INPUT]->GetName()); char buffer[80]; Interact(" Status Line Formats:"); for( int i=0; i < STATUSLINES; i++ ){ (CONSOLE.*m_statusline[i])(buffer, sizeof(buffer)); Interact(" %c%d) %s", (i==m_status_format) ? '*' : ' ', ++n_opt, buffer); } Interact(" Other options:"); Interact(" %2d) View detailed status", ++n_opt); if( WORLD.IsPaused() ) Interact(" %2d) Resume (continue upload/download)", ++n_opt); else Interact(" %2d) Pause (suspend upload/download)", ++n_opt); if( !arg_daemon ) Interact(" %2d) Become daemon (fork to background)", ++n_opt); Interact_n("Enter selection: "); m_streams[O_INPUT]->SetInputMode(K_LINES); oper_mode = 1; return 0; } else if( 1==oper_mode ){ if( !*param ){ oper_mode = 0; Interact("Exiting menu"); return 1; } int sel = atoi(param); if( sel < 1 || sel > n_opt ){ Interact_n("Enter selection: "); return 0; } if( sel <= O_NCHANNELS+1 ){ // change i/o channel channel = sel - 1; Interact("Possible values are:"); Interact(" %s", m_stdout.GetName()); Interact(" %s", m_stderr.GetName()); Interact(" %s", m_off.GetName()); Interact(" a filename"); Interact_n("Enter a destination: "); m_streams[O_INPUT]->SetInputMode(K_LINES); oper_mode = 2; return 0; }else if( sel <= O_NCHANNELS+1 + STATUSLINES ){ m_status_format = sel - (O_NCHANNELS+1) - 1; oper_mode = 0; return OperatorMenu(""); }else if( sel == 1 + O_NCHANNELS+1 + STATUSLINES ){ // detailed status Interact(""); Interact("Torrent: %s", arg_metainfo_file); ShowFiles(); if( arg_file_to_download && !BTCONTENT.Seeding() ) Interact("Downloading: %s", arg_file_to_download); Interact(""); Interact("Download rate: %dB/s Limit: %dB/s Total: %llu", (int)(Self.RateDL()), (int)cfg_max_bandwidth_down, (unsigned long long)(Self.TotalDL())); Interact(" Upload rate: %dB/s Limit: %dB/s Total: %llu", (int)(Self.RateUL()), (int)cfg_max_bandwidth_up, (unsigned long long)(Self.TotalUL())); Interact("Peers: %d Min: %d Max: %d", (int)(WORLD.GetPeersCount()), (int)cfg_min_peers, (int)cfg_max_peers); Interact("Listening on: %s", WORLD.GetListen()); Interact(""); Interact("Ratio: %.2f Seed time: %luh Seed ratio: %.2f", (double)(Self.TotalUL()) / ( Self.TotalDL() ? Self.TotalDL() : BTCONTENT.GetTotalFilesLength() ), (unsigned long)cfg_seed_hours, cfg_seed_ratio); Interact("Cache in use: %dKB Wants: %dKB Max: %dMB", (int)(BTCONTENT.CacheUsed()/1024), (int)(BTCONTENT.CacheSize()/1024), (int)cfg_cache_size); if(arg_ctcs) Interact("CTCS Server: %s", arg_ctcs); oper_mode = 0; return 1; }else if( sel == 2 + O_NCHANNELS+1 + STATUSLINES ){ // pause/resume if( WORLD.IsPaused() ) WORLD.Resume(); else WORLD.Pause(); oper_mode = 0; return 1; }else if( sel == 3 + O_NCHANNELS+1 + STATUSLINES ){ // daemon Daemonize(); oper_mode = 0; return 1; } } else if( 2==oper_mode ){ if( !*param ){ oper_mode = 0; return OperatorMenu(""); } ChangeChannel(channel, param); oper_mode = 0; return OperatorMenu(""); } Interact("Exiting menu"); return 1;}int Console::ChangeChannel(int channel, const char *param){ ConStream *dest = (ConStream *)0; if( 0==strcmp(param, m_stdout.GetName()) ) dest = &m_stdout; else if( 0==strcmp(param, m_stderr.GetName()) ) dest = &m_stderr; else if( 0==strcmp(param, m_stdin.GetName()) ) dest = &m_stdin; else if( 0==strcmp(param, m_off.GetName()) ) dest = &m_off; else{ for( int i=0; i <= O_NCHANNELS; i++ ){ if( channel != i && 0==strcmp(param, m_streams[i]->GetName()) && m_streams[i]->GetMode() == ((channel==O_INPUT) ? 0 : 1) ){ dest = m_streams[i]; break; } } if( !dest ){ FILE *stream; if( dest = new ConStream ){ if( 0==strcmp(param, m_streams[channel]->GetName()) ){ delete m_streams[channel]; m_streams[channel] = &m_off; } if( stream = fopen(param, (channel==O_INPUT) ? "r" : "a") ) dest->Associate(stream, param, (channel==O_INPUT) ? 0 : 1); else{ Interact("Error opening file: %s", strerror(errno)); delete dest; dest = (ConStream *)0; } }else Interact("Failed to allocate memory."); } } if( dest ){ if( O_INPUT==channel ) m_oldfd = m_streams[channel]->Fileno(); if( m_streams[channel] != &m_stdout && m_streams[channel] != &m_stderr && m_streams[channel] != &m_stdin && m_streams[channel] != &m_off ){ int in_use = 0; for( int i=0; i <= O_NCHANNELS; i++ ){ if( channel != i && m_streams[channel] == m_streams[i] ) in_use = 1; } if( !in_use ) delete m_streams[channel]; else if( O_INPUT==channel ) m_streams[O_INPUT]->RestoreMode(); } if( !arg_daemon || !m_streams[channel]->IsTTY() ){ switch(channel){ case O_NORMAL: Print("Output channel is now %s", dest->GetName()); break; case O_DEBUG: Debug("Debug channel is now %s", dest->GetName()); break; case O_INTERACT: Interact("Interactive output channel is now %s", dest->GetName()); break; case O_INPUT: Interact("Input channel is now %s", dest->GetName()); break; default: break; } } m_streams[channel] = dest; if( O_INPUT==channel ){ m_streams[O_INPUT]->PreserveMode(); m_streams[O_INPUT]->SetInputMode(K_CHARS); } return 0; }else return -1;}void Console::ShowFiles(){ BTFILE *file = 0; BitField tmpFilter; int n = 0; Interact("Files in this torrent:"); while( ++n <= BTCONTENT.GetNFiles() ){ BTCONTENT.SetTmpFilter(n, &tmpFilter); BitField tmpBitField = *BTCONTENT.pBF; tmpBitField.Except(tmpFilter); Interact("%d) %s [%llu] %d%%", n, BTCONTENT.GetFileName(n), (unsigned long long)(BTCONTENT.GetFileSize(n)), BTCONTENT.GetFilePieces(n) ? (int)(100 * tmpBitField.Count() / BTCONTENT.GetFilePieces(n)) : 0); }}void Console::Status(int immediate){ static char buffer[80]; if( immediate ) m_skip_status = 0; if( m_pre_dlrate.TimeUsed() || immediate ){ if( m_skip_status ) m_skip_status = 0; else if( !m_streams[O_NORMAL]->IsSuspended() || (arg_verbose && !m_streams[O_DEBUG]->IsSuspended()) ){ // optimized to generate the status line only if it will be output (CONSOLE.*m_statusline[m_status_format])(buffer, sizeof(buffer)); if( !m_status_last ) Print_n(""); Update("%*s", -(int)sizeof(buffer)+1, buffer); m_status_last = 1; if(arg_verbose) Debug("Cache: %dK/%dM Hits: %d Miss: %d %d%% Pre: %d/%d", (int)(BTCONTENT.CacheUsed()/1024), (int)cfg_cache_size, (int)(BTCONTENT.CacheHits()), (int)(BTCONTENT.CacheMiss()), BTCONTENT.CacheHits() ? (int)(100 * BTCONTENT.CacheHits() / (BTCONTENT.CacheHits()+BTCONTENT.CacheMiss())) : 0, BTCONTENT.CachePre(), (int)(Self.TotalUL() / DEFAULT_SLICE_SIZE)); } m_pre_dlrate = Self.GetDLRate(); m_pre_ulrate = Self.GetULRate(); }}void Console::StatusLine0(char buffer[], size_t length){ char partial[30] = ""; if( BTCONTENT.GetFilter() && !BTCONTENT.GetFilter()->IsEmpty() ){ BitField tmpBitField = *BTCONTENT.pBF; tmpBitField.Except(BTCONTENT.GetFilter()); sprintf( partial, "P:%d/%d ", (int)(tmpBitField.Count()), (int)(BTCONTENT.GetNPieces() - BTCONTENT.GetFilter()->Count()) ); } char checked[14] = ""; if( BTCONTENT.CheckedPieces() < BTCONTENT.GetNPieces() ){ sprintf( checked, "Checking: %d%%", 100 * BTCONTENT.CheckedPieces() / BTCONTENT.GetNPieces() ); } snprintf(buffer, length, "%c %d/%d/%d [%d/%d/%d] %lluMB,%lluMB | %d,%dK/s | %d,%dK E:%d,%d %s%s", LIVE_CHAR[m_live_idx++], (int)(WORLD.GetSeedsCount()), (int)(WORLD.GetPeersCount()) - WORLD.GetSeedsCount(), (int)(Tracker.GetPeersCount()), (int)(BTCONTENT.pBF->Count()), (int)(BTCONTENT.GetNPieces()), (int)(WORLD.Pieces_I_Can_Get()), (unsigned long long)(Self.TotalDL() >> 20), (unsigned long long)(Self.TotalUL() >> 20), (int)(Self.RateDL() >> 10), (int)(Self.RateUL() >> 10), (int)(m_pre_dlrate.RateMeasure(Self.GetDLRate()) >> 10), (int)(m_pre_ulrate.RateMeasure(Self.GetULRate()) >> 10), (int)(Tracker.GetRefuseClick()), (int)(Tracker.GetOkClick()), partial, (Tracker.GetStatus()==T_CONNECTING) ? "Connecting" : ( (Tracker.GetStatus()==T_READY) ? "Connected" : (Tracker.IsQuitting() ? "Quitting" : (WORLD.IsPaused() ? "Paused" : checked)) ) );}void Console::StatusLine1(char buffer[], size_t length){ char partial[30] = ""; if( BTCONTENT.GetFilter() && !BTCONTENT.GetFilter()->IsEmpty() ){ int have, avail, all; long premain = -1; char ptime[20] = ""; size_t rate; BitField tmpBitfield = *BTCONTENT.pBF; tmpBitfield.Except(BTCONTENT.GetFilter()); have = tmpBitfield.Count(); WORLD.Pieces_I_Can_Get(&tmpBitfield); tmpBitfield.Except(BTCONTENT.GetFilter()); avail = tmpBitfield.Count(); all = BTCONTENT.GetNPieces() - BTCONTENT.GetFilter()->Count(); if( rate = Self.RateDL() ){ premain = (all - have) * BTCONTENT.GetPieceLength() / rate / 60; if( premain < 60000 ) // 1000 hours snprintf(ptime, sizeof(ptime), " %d:%2.2d", (int)(premain / 60), (int)(premain % 60)); } sprintf(partial, "P:%d/%d%%%s ", 100 * have / all, 100 * avail / all, ptime); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?