ConsoleStatCalc.cc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2006 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "ConsoleStatCalc.h"
  36. #include "RequestGroupMan.h"
  37. #include "RequestGroup.h"
  38. #include "FileAllocationMan.h"
  39. #include "FileAllocationEntry.h"
  40. #include "CheckIntegrityMan.h"
  41. #include "CheckIntegrityEntry.h"
  42. #include "Util.h"
  43. #ifdef ENABLE_BITTORRENT
  44. # include "BtContext.h"
  45. #endif // ENABLE_BITTORRENT
  46. #include <termios.h>
  47. #include <sys/ioctl.h>
  48. #include <unistd.h>
  49. #include <iomanip>
  50. #include <iostream>
  51. #include <algorithm>
  52. #include <cstring>
  53. #include <sstream>
  54. #include <iterator>
  55. namespace aria2 {
  56. static void printProgress(std::ostream& o, const SharedHandle<RequestGroup>& rg)
  57. {
  58. TransferStat stat = rg->calculateStat();
  59. unsigned int eta = 0;
  60. if(rg->getTotalLength() > 0 && stat.getDownloadSpeed() > 0) {
  61. eta = (rg->getTotalLength()-rg->getCompletedLength())/stat.getDownloadSpeed();
  62. }
  63. o << "["
  64. << "#" << rg->getGID() << " ";
  65. #ifdef ENABLE_BITTORRENT
  66. if(rg->downloadFinished() &&
  67. !dynamic_pointer_cast<BtContext>(rg->getDownloadContext()).isNull()) {
  68. o << "SEEDING" << "(" << "ratio:"
  69. << std::fixed << std::setprecision(1)
  70. << ((stat.getAllTimeUploadLength()*10)/rg->getCompletedLength())/10.0
  71. << ")";
  72. } else
  73. #endif // ENABLE_BITTORRENT
  74. {
  75. o << "SIZE:"
  76. << Util::abbrevSize(rg->getCompletedLength())
  77. << "B"
  78. << "/"
  79. << Util::abbrevSize(rg->getTotalLength())
  80. << "B";
  81. if(rg->getTotalLength() > 0) {
  82. o << "("
  83. << 100*rg->getCompletedLength()/rg->getTotalLength()
  84. << "%)";
  85. }
  86. }
  87. o << " "
  88. << "CN:"
  89. << rg->getNumConnection();
  90. if(!rg->downloadFinished()) {
  91. o << " "
  92. << "SPD:"
  93. << std::fixed << std::setprecision(2) << stat.getDownloadSpeed()/1024.0 << "KiB/s";
  94. }
  95. if(stat.getSessionUploadLength() > 0) {
  96. o << " "
  97. << "UP:"
  98. << std::fixed << std::setprecision(2) << stat.getUploadSpeed()/1024.0 << "KiB/s"
  99. << "(" << Util::abbrevSize(stat.getAllTimeUploadLength()) << "B)";
  100. }
  101. if(eta > 0) {
  102. o << " "
  103. << "ETA:"
  104. << Util::secfmt(eta);
  105. }
  106. o << "]";
  107. }
  108. class PrintSummary
  109. {
  110. private:
  111. size_t _cols;
  112. public:
  113. PrintSummary(size_t cols):_cols(cols) {}
  114. void operator()(const SharedHandle<RequestGroup>& rg)
  115. {
  116. const char SEP_CHAR = '-';
  117. printProgress(std::cout, rg);
  118. std::cout << "\n"
  119. << "FILE: " << rg->getFilePath() << "\n"
  120. << std::setfill(SEP_CHAR) << std::setw(_cols) << SEP_CHAR << "\n";
  121. }
  122. };
  123. static void printProgressSummary(const std::deque<SharedHandle<RequestGroup> >& groups, size_t cols)
  124. {
  125. const char SEP_CHAR = '=';
  126. time_t now;
  127. time(&now);
  128. std::cout << " *** Download Progress Summary";
  129. {
  130. time_t now;
  131. struct tm* staticNowtmPtr;
  132. char buf[26];
  133. if(time(&now) != (time_t)-1 && (staticNowtmPtr = localtime(&now)) != 0 &&
  134. asctime_r(staticNowtmPtr, buf) != 0) {
  135. char* lfptr = strchr(buf, '\n');
  136. if(lfptr) {
  137. *lfptr = '\0';
  138. }
  139. std::cout << " as of " << buf;
  140. }
  141. }
  142. std::cout << " *** " << "\n"
  143. << std::setfill(SEP_CHAR) << std::setw(cols) << SEP_CHAR << "\n";
  144. std::for_each(groups.begin(), groups.end(), PrintSummary(cols));
  145. }
  146. ConsoleStatCalc::ConsoleStatCalc(time_t summaryInterval):
  147. _summaryInterval(summaryInterval),
  148. _summaryIntervalCount(0)
  149. {}
  150. void
  151. ConsoleStatCalc::calculateStat(const RequestGroupManHandle& requestGroupMan,
  152. const FileAllocationManHandle& fileAllocationMan,
  153. const CheckIntegrityManHandle& checkIntegrityMan)
  154. {
  155. if(!_cp.elapsed(1)) {
  156. return;
  157. }
  158. _cp.reset();
  159. ++_summaryIntervalCount;
  160. bool isTTY = isatty(STDOUT_FILENO) == 1;
  161. unsigned short int cols = 80;
  162. if(isTTY) {
  163. struct winsize size;
  164. if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) == 0) {
  165. cols = size.ws_col;
  166. }
  167. std::cout << '\r' << std::setfill(' ') << std::setw(cols) << ' ' << '\r';
  168. }
  169. std::ostringstream o;
  170. if(requestGroupMan->countRequestGroup() > 0) {
  171. if(_summaryInterval > 0 && _summaryIntervalCount%_summaryInterval == 0) {
  172. printProgressSummary(requestGroupMan->getRequestGroups(), cols);
  173. _summaryIntervalCount = 0;
  174. std::cout << "\n";
  175. }
  176. RequestGroupHandle firstRequestGroup = requestGroupMan->getRequestGroup(0);
  177. printProgress(o, firstRequestGroup);
  178. if(requestGroupMan->countRequestGroup() > 1) {
  179. o << "("
  180. << requestGroupMan->countRequestGroup()-1
  181. << "more...)";
  182. }
  183. }
  184. if(requestGroupMan->countRequestGroup() > 1 &&
  185. !requestGroupMan->downloadFinished()) {
  186. TransferStat stat = requestGroupMan->calculateStat();
  187. o << " "
  188. << "[TOTAL SPD:"
  189. << std::fixed << std::setprecision(2) << stat.getDownloadSpeed()/1024.0 << "KiB/s" << "]";
  190. }
  191. {
  192. FileAllocationEntryHandle entry = fileAllocationMan->getCurrentFileAllocationEntry();
  193. if(!entry.isNull()) {
  194. o << " "
  195. << "[FileAlloc:"
  196. << "#" << entry->getRequestGroup()->getGID() << " "
  197. << Util::abbrevSize(entry->getCurrentLength())
  198. << "B"
  199. << "/"
  200. << Util::abbrevSize(entry->getTotalLength())
  201. << "B"
  202. << "(";
  203. if(entry->getTotalLength() > 0) {
  204. o << 100*entry->getCurrentLength()/entry->getTotalLength();
  205. } else {
  206. o << "--";
  207. }
  208. o << "%)"
  209. << "]";
  210. if(fileAllocationMan->countFileAllocationEntryInQueue() > 0) {
  211. o << "("
  212. << fileAllocationMan->countFileAllocationEntryInQueue()
  213. << "waiting...)";
  214. }
  215. }
  216. }
  217. #ifdef ENABLE_MESSAGE_DIGEST
  218. {
  219. CheckIntegrityEntryHandle entry = checkIntegrityMan->getFirstCheckIntegrityEntry();
  220. if(!entry.isNull()) {
  221. o << " "
  222. << "[Checksum:"
  223. << "#" << entry->getRequestGroup()->getGID() << " "
  224. << Util::abbrevSize(entry->getCurrentLength())
  225. << "B"
  226. << "/"
  227. << Util::abbrevSize(entry->getTotalLength())
  228. << "B"
  229. << "("
  230. << 100*entry->getCurrentLength()/entry->getTotalLength()
  231. << "%)"
  232. << "]";
  233. if(checkIntegrityMan->countCheckIntegrityEntry() > 1) {
  234. o << "("
  235. << checkIntegrityMan->countCheckIntegrityEntry()-1
  236. << "more...)";
  237. }
  238. }
  239. }
  240. #endif // ENABLE_MESSAGE_DIGEST
  241. std::string readout = o.str();
  242. if(isTTY) {
  243. std::string::iterator last = readout.begin();
  244. if(readout.size() > cols) {
  245. std::advance(last, cols);
  246. } else {
  247. last = readout.end();
  248. }
  249. std::copy(readout.begin(), last, std::ostream_iterator<char>(std::cout));
  250. std::cout << std::flush;
  251. } else {
  252. std::copy(readout.begin(), readout.end(), std::ostream_iterator<char>(std::cout));
  253. std::cout << std::endl;
  254. }
  255. }
  256. } // namespace aria2