📄 console.cpp
字号:
{ 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); } char checked[14] = ""; if( BTCONTENT.CheckedPieces() < BTCONTENT.GetNPieces() ){ sprintf( checked, "Checking: %d%%", 100 * BTCONTENT.CheckedPieces() / BTCONTENT.GetNPieces() ); } char complete[8]; if( BTCONTENT.IsFull() ) sprintf(complete, "seeding"); else if( BTCONTENT.Seeding() ) sprintf(complete, "seed%d%%", 100 * BTCONTENT.pBF->Count() / BTCONTENT.GetNPieces()); else{ int have, avail, all; BitField tmpBitfield = *BTCONTENT.pBF; tmpBitfield.Except(*BTCONTENT.pBMasterFilter); have = tmpBitfield.Count(); WORLD.Pieces_I_Can_Get(&tmpBitfield); tmpBitfield.Except(*BTCONTENT.pBMasterFilter); avail = tmpBitfield.Count(); all = BTCONTENT.GetNPieces() - BTCONTENT.pBMasterFilter->Count(); sprintf(complete, "%d/%d%%", 100 * have / all, 100 * avail / all); } long remain = -1; char timeleft[20]; size_t rate; if( !BTCONTENT.Seeding() || BTCONTENT.FlushFailed() ){ // downloading if( rate = Self.RateDL() ){ // don't overflow remain if( BTCONTENT.GetLeftBytes() < (uint64_t)rate << 22 ) remain = BTCONTENT.GetLeftBytes() / rate / 60; else remain = 99999; } }else{ //seeding if( cfg_seed_hours ) remain = cfg_seed_hours * 60 - (now - BTCONTENT.GetSeedTime()) / 60; else if( rate = Self.RateUL() ){ // don't overflow remain if( cfg_seed_ratio * (Self.TotalDL() ? Self.TotalDL() : BTCONTENT.GetTotalFilesLength()) - Self.TotalUL() < (uint64_t)rate << 22 ) remain = (long)( cfg_seed_ratio * (Self.TotalDL() ? Self.TotalDL() : BTCONTENT.GetTotalFilesLength()) - Self.TotalUL() ) / rate / 60; else remain = 99999; } } if( remain >= 0 ){ if( remain < 60000 ) // 1000 hours snprintf(timeleft, sizeof(timeleft), "%d:%2.2d", (int)(remain / 60), (int)(remain % 60)); else strcpy(timeleft, ">999hr"); }else if( BTCONTENT.CheckedPieces() < BTCONTENT.GetNPieces() ){ // Don't say stalled if still checking and nothing to download yet. BitField tmpBitfield = *BTCONTENT.pBChecked; tmpBitfield.Except(BTCONTENT.pBF); if(tmpBitfield.IsEmpty()) strcpy(timeleft, "unknown"); else strcpy(timeleft, "stalled"); }else strcpy(timeleft, "stalled"); snprintf(buffer, length, "%c S:%d/%d L:%d/%d C:%d R=%.2f D=%d U=%d K/s %s %s %s%s", LIVE_CHAR[m_live_idx++], (int)(WORLD.GetSeedsCount()), (int)(Tracker.GetSeedsCount()) - (BTCONTENT.IsFull() ? 1 : 0), (int)(WORLD.GetPeersCount()) - WORLD.GetSeedsCount() - WORLD.GetConnCount(), (int)(Tracker.GetPeersCount()) - Tracker.GetSeedsCount() - (!BTCONTENT.IsFull() ? 1 : 0), (int)(WORLD.GetConnCount()), (double)(Self.TotalUL()) / ( Self.TotalDL() ? Self.TotalDL() : BTCONTENT.GetTotalFilesLength() ), (int)(Self.RateDL() >> 10), (int)(Self.RateUL() >> 10), complete, timeleft, partial, (Tracker.GetStatus()==T_CONNECTING) ? "Connecting" : ( (Tracker.GetStatus()==T_READY) ? "Connected" : (Tracker.IsRestarting() ? "Restarting" : (Tracker.IsQuitting() ? "Quitting" : (WORLD.IsPaused() ? "Paused" : checked))) ) );}void Console::Print(const char *message, ...){ va_list ap; if( K_LINES != m_streams[O_INPUT]->GetInputMode() || m_streams[O_INPUT]->IsSuspended() || (!m_streams[O_NORMAL]->SameDev(m_streams[O_INTERACT]) && !m_streams[O_NORMAL]->SameDev(m_streams[O_INPUT])) ){ va_start(ap, message); if( m_streams[O_NORMAL]->Output(message, ap) ) SyncNewlines(O_NORMAL); va_end(ap); } if( arg_verbose && !m_streams[O_DEBUG]->SameDev(m_streams[O_NORMAL]) ){ va_start(ap, message); if( m_streams[O_DEBUG]->Output(message, ap) ) SyncNewlines(O_DEBUG); va_end(ap); }}/* Print message without a terminating newline With a null message, start/insure a new line*/void Console::Print_n(const char *message, ...){ va_list ap; if( m_status_last && message && *message ) Print_n(""); m_status_last = 0; if( K_LINES != m_streams[O_INPUT]->GetInputMode() || m_streams[O_INPUT]->IsSuspended() || (!m_streams[O_NORMAL]->SameDev(m_streams[O_INTERACT]) && !m_streams[O_NORMAL]->SameDev(m_streams[O_INPUT])) ){ va_start(ap, message); if( m_streams[O_NORMAL]->Output_n(message, ap) ) SyncNewlines(O_NORMAL); va_end(ap); } if( arg_verbose && !m_streams[O_DEBUG]->SameDev(m_streams[O_NORMAL]) ){ va_start(ap, message); if( m_streams[O_DEBUG]->Output_n(message, ap) ) SyncNewlines(O_DEBUG); va_end(ap); }}/* Update (replace) the current line (no terminating newline)*/void Console::Update(const char *message, ...){ va_list ap; m_status_last = 0; if( K_LINES != m_streams[O_INPUT]->GetInputMode() || m_streams[O_INPUT]->IsSuspended() || (!m_streams[O_NORMAL]->SameDev(m_streams[O_INTERACT]) && !m_streams[O_NORMAL]->SameDev(m_streams[O_INPUT])) ){ va_start(ap, message); if( m_streams[O_NORMAL]->Update(message, ap) ) SyncNewlines(O_NORMAL); va_end(ap); } if( arg_verbose && !m_streams[O_DEBUG]->SameDev(m_streams[O_NORMAL]) ){ va_start(ap, message); if( m_streams[O_DEBUG]->Update(message, ap) ) SyncNewlines(O_DEBUG); va_end(ap); }}/* "sev" indicates the severity of the message. 0: will be printed but not sent to CTCS 1: extremely urgent/important 2: less important 3: no problem*/void Console::Warning(int sev, const char *message, ...){ va_list ap; va_start(ap, message); if( m_streams[O_WARNING]->Output(message, ap) ) SyncNewlines(O_WARNING); va_end(ap); if( arg_verbose && !m_streams[O_DEBUG]->SameDev(m_streams[O_WARNING]) ){ va_start(ap, message); if( m_streams[O_DEBUG]->Output(message, ap) ) SyncNewlines(O_DEBUG); va_end(ap); } if(sev && arg_ctcs){ char cmsg[CTCS_BUFSIZE]; va_start(ap, message); vsnprintf(cmsg, CTCS_BUFSIZE, message, ap); CTCS.Send_Info(sev, cmsg); va_end(ap); }}void Console::Debug(const char *message, ...){ static char buffer[80]; if( !arg_verbose ) return; char *format = (char *)0; size_t buflen; va_list ap; if( K_LINES != m_streams[O_INPUT]->GetInputMode() || m_streams[O_INPUT]->IsSuspended() || (!m_streams[O_DEBUG]->SameDev(m_streams[O_INTERACT]) && !m_streams[O_DEBUG]->SameDev(m_streams[O_INPUT])) ){ size_t need = strlen(message)+1 + 10*sizeof(unsigned long)/4; if( need > sizeof(buffer) && (format = new char[need]) ) buflen = need; else{ format = buffer; buflen = sizeof(buffer); } snprintf(format, buflen, "%lu %s", (unsigned long)now, message); va_start(ap, message); if( m_streams[O_DEBUG]->Output(format, ap) ) SyncNewlines(O_DEBUG); va_end(ap); if( format && format != buffer ) delete []format; }}/* Print debug message without a terminating newline With a null message, start/insure a new line*/void Console::Debug_n(const char *message, ...){ static char buffer[80]; static int f_new_line = 1; if( !arg_verbose ) return; va_list ap; if( K_LINES != m_streams[O_INPUT]->GetInputMode() || m_streams[O_INPUT]->IsSuspended() || (!m_streams[O_DEBUG]->SameDev(m_streams[O_INTERACT]) && !m_streams[O_DEBUG]->SameDev(m_streams[O_INPUT])) ){ if( m_streams[O_DEBUG]->SameDev(m_streams[O_NORMAL]) ){ if( m_status_last && message && *message ) Debug_n(""); m_status_last = 0; } if( f_new_line && message && *message ){ char *format = (char *)0; size_t buflen; size_t need = strlen(message)+1 + 10*sizeof(unsigned long)/4; if( need > sizeof(buffer) && (format = new char[need]) ) buflen = need; else{ format = buffer; buflen = sizeof(buffer); } snprintf(format, buflen, "%lu %s", (unsigned long)now, message); va_start(ap, message); if( m_streams[O_DEBUG]->Output_n(format, ap) ) SyncNewlines(O_DEBUG); va_end(ap); if( format && format != buffer ) delete []format; }else{ va_start(ap, message); if( m_streams[O_DEBUG]->Output_n(message, ap) ) SyncNewlines(O_DEBUG); va_end(ap); } if( message && *message ) f_new_line = 0; else f_new_line = 1; }}void Console::Interact(const char *message, ...){ va_list ap; va_start(ap, message); if( m_streams[O_INTERACT]->Output(message, ap) ) SyncNewlines(O_INTERACT); va_end(ap);}/* Print interactive message without a terminating newline With a null message, start/insure a new line*/void Console::Interact_n(const char *message, ...){ va_list ap; if( m_streams[O_INTERACT]->SameDev(m_streams[O_NORMAL]) ){ if( m_status_last && message && *message ) Interact_n(""); m_status_last = 0; } va_start(ap, message); if( m_streams[O_INTERACT]->Output_n(message, ap) ) SyncNewlines(O_INTERACT); va_end(ap);}/* Update (replace) the current interactive line (no terminating newline)*/void Console::InteractU(const char *message, ...){ va_list ap; if( m_streams[O_INTERACT]->SameDev(m_streams[O_NORMAL]) ){ if( m_status_last ) Interact_n(""); m_status_last = 0; } va_start(ap, message); if( m_streams[O_INTERACT]->Update(message, ap) ) SyncNewlines(O_INTERACT); va_end(ap);}// Avoid using this during normal operation, as it blocks for input!char *Console::Input(const char *prompt, char *field, size_t length){ char *retval; Interact_n(""); Interact_n("%s", prompt); m_streams[O_INPUT]->SetInputMode(K_LINES); retval = m_streams[O_INPUT]->Input(field, length); m_streams[O_INPUT]->SetInputMode(K_CHARS); return retval;}void Console::SyncNewlines(int master){ for( int i=0; i < O_NCHANNELS; i++ ){ if( i != master && m_streams[i]->SameDev(m_streams[master]) ) m_streams[i]->SyncNewline(m_streams[master]); }}void Console::cpu(){ if(arg_verbose) Debug( "%.2f CPU seconds used; %lu seconds elapsed (%.2f%% usage)", clock() / (double)CLOCKS_PER_SEC, (unsigned long)(time((time_t *)0) - BTCONTENT.GetStartTime()), clock() / (double)CLOCKS_PER_SEC / (time((time_t *)0) - BTCONTENT.GetStartTime()) * 100 );}RETSIGTYPE Console::Signal(int sig_no){ switch( sig_no ){ case SIGTTOU: for( int i=0; i < O_NCHANNELS; i++ ) if( m_streams[i]->IsTTY() ) m_streams[i]->Suspend(); m_conmode = m_streams[O_INPUT]->GetInputMode(); break; case SIGTTIN: if( m_streams[O_INPUT]->IsTTY() ) m_streams[O_INPUT]->Suspend(); m_conmode = m_streams[O_INPUT]->GetInputMode(); break; case SIGCONT: for( int i=0; i <= O_NCHANNELS; i++ ) if( m_streams[i]->IsTTY() ) m_streams[i]->Resume(); m_streams[O_INPUT]->SetInputMode(m_conmode); // restore my handler signal(SIGTSTP, signals); break; case SIGTSTP: m_conmode = m_streams[O_INPUT]->GetInputMode(); m_streams[O_INPUT]->RestoreMode(); // let the system default action proceed signal(sig_no, SIG_DFL); raise(sig_no); break; default: break; }}void Console::Daemonize(){#ifdef HAVE_WORKING_FORK size_t orig_cache_size = 0; pid_t r; int nullfd = -1; if( cfg_cache_size && BTCONTENT.CacheUsed() ){ orig_cache_size = cfg_cache_size; cfg_cache_size /= 2; BTCONTENT.CacheConfigure(); } if( (r = fork()) < 0 ){ Warning(2, "warn, fork to background failed: %s", strerror(errno)); arg_daemon = 0; goto restorecache; }else if(r) exit(EXIT_SUCCESS); if( !arg_daemon ) arg_daemon = 1; for( int i=0; i <= O_NCHANNELS; i++ ){ if( m_streams[i]->IsTTY() && ChangeChannel(i, "off", 0) < 0 ) m_streams[i]->Suspend(); } nullfd = OpenNull(nullfd, &m_stdin, 0); nullfd = OpenNull(nullfd, &m_stdout, 1); nullfd = OpenNull(nullfd, &m_stderr, 2); if( setsid() < 0 ){ Warning(2, "warn, failed to create new session (continuing in background): %s", strerror(errno)); goto restorecache; } if( (r = fork()) < 0 ){ Warning(2, "warn, final fork failed (continuing in background): %s", strerror(errno)); goto restorecache; }else if(r) exit(EXIT_SUCCESS); else if(arg_verbose) Debug("Running in daemon (background) mode."); restorecache: if( orig_cache_size ){ cfg_cache_size = orig_cache_size; BTCONTENT.CacheConfigure(); }#endif}int Console::OpenNull(int nullfd, ConStream *stream, int sfd){ if( stream->IsTTY() || arg_daemon == 1 ){ int mfd = stream->Fileno(); if( mfd < 0 ) mfd = sfd; stream->Close(); if( nullfd < 0 ) nullfd = open("/dev/null", O_RDWR); if( nullfd >= 0 && nullfd != mfd ) dup2(nullfd, mfd); } return nullfd;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -