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 + -
显示快捷键?