aria2api.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2013 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 "aria2api.h"
  36. #include <functional>
  37. #include "Platform.h"
  38. #include "Context.h"
  39. #include "DownloadEngine.h"
  40. #include "OptionParser.h"
  41. #include "Option.h"
  42. #include "DlAbortEx.h"
  43. #include "fmt.h"
  44. #include "OptionHandler.h"
  45. #include "RequestGroupMan.h"
  46. #include "RequestGroup.h"
  47. #include "MultiUrlRequestInfo.h"
  48. #include "prefs.h"
  49. #include "download_helper.h"
  50. #include "LogFactory.h"
  51. #include "PieceStorage.h"
  52. #include "DownloadContext.h"
  53. #include "FileEntry.h"
  54. #include "BitfieldMan.h"
  55. #include "DownloadContext.h"
  56. #include "RpcMethodImpl.h"
  57. #include "console.h"
  58. #include "KeepRunningCommand.h"
  59. #include "A2STR.h"
  60. #include "SingletonHolder.h"
  61. #include "Notifier.h"
  62. #include "ApiCallbackDownloadEventListener.h"
  63. #ifdef ENABLE_BITTORRENT
  64. # include "bittorrent_helper.h"
  65. #endif // ENABLE_BITTORRENT
  66. namespace aria2 {
  67. Session::Session(const KeyVals& options)
  68. : context(new Context(false, 0, 0, options))
  69. {}
  70. Session::~Session()
  71. {}
  72. SessionConfig::SessionConfig()
  73. : keepRunning(false),
  74. useSignalHandler(true),
  75. downloadEventCallback(0),
  76. userData(0)
  77. {}
  78. namespace {
  79. Platform* platform = 0;
  80. } // namespace
  81. int libraryInit()
  82. {
  83. global::initConsole(true);
  84. try {
  85. platform = new Platform();
  86. } catch(RecoverableException& e) {
  87. A2_LOG_ERROR_EX(EX_EXCEPTION_CAUGHT, e);
  88. return -1;
  89. }
  90. LogFactory::setConsoleOutput(false);
  91. return 0;
  92. }
  93. int libraryDeinit()
  94. {
  95. delete platform;
  96. return 0;
  97. }
  98. Session* sessionNew(const KeyVals& options, const SessionConfig& config)
  99. {
  100. int rv;
  101. Session* session;
  102. try {
  103. session = new Session(options);
  104. } catch(RecoverableException& e) {
  105. return 0;
  106. }
  107. if(session->context->reqinfo) {
  108. if(!config.useSignalHandler) {
  109. session->context->reqinfo->setUseSignalHandler(false);
  110. }
  111. rv = session->context->reqinfo->prepare();
  112. if(rv != 0) {
  113. delete session;
  114. return 0;
  115. }
  116. const std::shared_ptr<DownloadEngine>& e =
  117. session->context->reqinfo->getDownloadEngine();
  118. if(config.keepRunning) {
  119. e->getRequestGroupMan()->setKeepRunning(true);
  120. // Add command to make aria2 keep event polling
  121. e->addCommand(new KeepRunningCommand(e->newCUID(), e.get()));
  122. }
  123. if(config.downloadEventCallback) {
  124. std::shared_ptr<DownloadEventListener> listener
  125. (new ApiCallbackDownloadEventListener(session,
  126. config.downloadEventCallback,
  127. config.userData));
  128. SingletonHolder<Notifier>::instance()
  129. ->addDownloadEventListener(listener);
  130. }
  131. } else {
  132. delete session;
  133. return 0;
  134. }
  135. return session;
  136. }
  137. int sessionFinal(Session* session)
  138. {
  139. error_code::Value rv = session->context->reqinfo->getResult();
  140. delete session;
  141. return rv;
  142. }
  143. int run(Session* session, RUN_MODE mode)
  144. {
  145. const std::shared_ptr<DownloadEngine>& e =
  146. session->context->reqinfo->getDownloadEngine();
  147. return e->run(mode == RUN_ONCE);
  148. }
  149. int shutdown(Session* session, bool force)
  150. {
  151. const std::shared_ptr<DownloadEngine>& e =
  152. session->context->reqinfo->getDownloadEngine();
  153. if(force) {
  154. e->requestForceHalt();
  155. } else {
  156. e->requestHalt();
  157. }
  158. // Skip next polling timeout. This avoids 1 second delay when there
  159. // is no Command other than KeepRunningCommand in the queue.
  160. e->setNoWait(true);
  161. return 0;
  162. }
  163. std::string gidToHex(A2Gid gid)
  164. {
  165. return GroupId::toHex(gid);
  166. }
  167. A2Gid hexToGid(const std::string& hex)
  168. {
  169. A2Gid gid;
  170. if(GroupId::toNumericId(gid, hex.c_str()) == 0) {
  171. return gid;
  172. } else {
  173. return 0;
  174. }
  175. }
  176. bool isNull(A2Gid gid)
  177. {
  178. return gid == 0;
  179. }
  180. namespace {
  181. template<typename InputIterator, typename Pred>
  182. void apiGatherOption
  183. (InputIterator first, InputIterator last,
  184. Pred pred,
  185. Option* option,
  186. const std::shared_ptr<OptionParser>& optionParser)
  187. {
  188. for(; first != last; ++first) {
  189. const std::string& optionName = (*first).first;
  190. const Pref* pref = option::k2p(optionName);
  191. const OptionHandler* handler = optionParser->find(pref);
  192. if(!handler || !pred(handler)) {
  193. // Just ignore the unacceptable options in this context.
  194. continue;
  195. }
  196. handler->parse(*option, (*first).second);
  197. }
  198. }
  199. } // namespace
  200. namespace {
  201. void apiGatherRequestOption(Option* option, const KeyVals& options,
  202. const std::shared_ptr<OptionParser>& optionParser)
  203. {
  204. apiGatherOption(options.begin(), options.end(),
  205. std::mem_fn(&OptionHandler::getInitialOption),
  206. option, optionParser);
  207. }
  208. } // namespace
  209. namespace {
  210. void apiGatherChangeableOption(Option* option, const KeyVals& options,
  211. const std::shared_ptr<OptionParser>& optionParser)
  212. {
  213. apiGatherOption(options.begin(), options.end(),
  214. std::mem_fn(&OptionHandler::getChangeOption),
  215. option, optionParser);
  216. }
  217. } // namespace
  218. namespace {
  219. void apiGatherChangeableOptionForReserved
  220. (Option* option, const KeyVals& options,
  221. const std::shared_ptr<OptionParser>& optionParser)
  222. {
  223. apiGatherOption(options.begin(), options.end(),
  224. std::mem_fn(&OptionHandler::getChangeOptionForReserved),
  225. option, optionParser);
  226. }
  227. } // namespace
  228. namespace {
  229. void apiGatherChangeableGlobalOption
  230. (Option* option, const KeyVals& options,
  231. const std::shared_ptr<OptionParser>& optionParser)
  232. {
  233. apiGatherOption(options.begin(), options.end(),
  234. std::mem_fn(&OptionHandler::getChangeGlobalOption),
  235. option, optionParser);
  236. }
  237. } // namespace
  238. namespace {
  239. void addRequestGroup(const std::shared_ptr<RequestGroup>& group,
  240. const std::shared_ptr<DownloadEngine>& e,
  241. int position)
  242. {
  243. if(position >= 0) {
  244. e->getRequestGroupMan()->insertReservedGroup(position, group);
  245. } else {
  246. e->getRequestGroupMan()->addReservedGroup(group);
  247. }
  248. }
  249. } // namespace
  250. int addUri(Session* session,
  251. A2Gid* gid,
  252. const std::vector<std::string>& uris,
  253. const KeyVals& options,
  254. int position)
  255. {
  256. const std::shared_ptr<DownloadEngine>& e =
  257. session->context->reqinfo->getDownloadEngine();
  258. std::shared_ptr<Option> requestOption(new Option(*e->getOption()));
  259. try {
  260. apiGatherRequestOption(requestOption.get(), options,
  261. OptionParser::getInstance());
  262. } catch(RecoverableException& e) {
  263. A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e);
  264. return -1;
  265. }
  266. std::vector<std::shared_ptr<RequestGroup> > result;
  267. createRequestGroupForUri(result, requestOption, uris,
  268. /* ignoreForceSeq = */ true,
  269. /* ignoreLocalPath = */ true);
  270. if(!result.empty()) {
  271. addRequestGroup(result.front(), e, position);
  272. if(gid) {
  273. *gid = result.front()->getGID();
  274. }
  275. }
  276. return 0;
  277. }
  278. int addMetalink(Session* session,
  279. std::vector<A2Gid>* gids,
  280. const std::string& metalinkFile,
  281. const KeyVals& options,
  282. int position)
  283. {
  284. #ifdef ENABLE_METALINK
  285. const std::shared_ptr<DownloadEngine>& e =
  286. session->context->reqinfo->getDownloadEngine();
  287. std::shared_ptr<Option> requestOption(new Option(*e->getOption()));
  288. std::vector<std::shared_ptr<RequestGroup> > result;
  289. try {
  290. apiGatherRequestOption(requestOption.get(), options,
  291. OptionParser::getInstance());
  292. requestOption->put(PREF_METALINK_FILE, metalinkFile);
  293. createRequestGroupForMetalink(result, requestOption);
  294. } catch(RecoverableException& e) {
  295. A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e);
  296. return -1;
  297. }
  298. if(!result.empty()) {
  299. if(position >= 0) {
  300. e->getRequestGroupMan()->insertReservedGroup(position, result);
  301. } else {
  302. e->getRequestGroupMan()->addReservedGroup(result);
  303. }
  304. if(gids) {
  305. for(std::vector<std::shared_ptr<RequestGroup> >::const_iterator i =
  306. result.begin(), eoi = result.end(); i != eoi; ++i) {
  307. (*gids).push_back((*i)->getGID());
  308. }
  309. }
  310. }
  311. return 0;
  312. #else // !ENABLE_METALINK
  313. return -1;
  314. #endif // !ENABLE_METALINK
  315. }
  316. int addTorrent(Session* session,
  317. A2Gid* gid,
  318. const std::string& torrentFile,
  319. const std::vector<std::string>& webSeedUris,
  320. const KeyVals& options,
  321. int position)
  322. {
  323. #ifdef ENABLE_BITTORRENT
  324. const std::shared_ptr<DownloadEngine>& e =
  325. session->context->reqinfo->getDownloadEngine();
  326. std::shared_ptr<Option> requestOption(new Option(*e->getOption()));
  327. std::vector<std::shared_ptr<RequestGroup> > result;
  328. try {
  329. apiGatherRequestOption(requestOption.get(), options,
  330. OptionParser::getInstance());
  331. requestOption->put(PREF_TORRENT_FILE, torrentFile);
  332. createRequestGroupForBitTorrent(result, requestOption, webSeedUris,
  333. torrentFile);
  334. } catch(RecoverableException& e) {
  335. A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e);
  336. return -1;
  337. }
  338. if(!result.empty()) {
  339. addRequestGroup(result.front(), e, position);
  340. if(gid) {
  341. *gid = result.front()->getGID();
  342. }
  343. }
  344. return 0;
  345. #else // !ENABLE_BITTORRENT
  346. return -1;
  347. #endif // !ENABLE_BITTORRENT
  348. }
  349. int addTorrent(Session* session,
  350. A2Gid* gid,
  351. const std::string& torrentFile,
  352. const KeyVals& options,
  353. int position)
  354. {
  355. return addTorrent(session, gid, torrentFile, std::vector<std::string>(),
  356. options, position);
  357. }
  358. int removeDownload(Session* session, A2Gid gid, bool force)
  359. {
  360. const std::shared_ptr<DownloadEngine>& e =
  361. session->context->reqinfo->getDownloadEngine();
  362. std::shared_ptr<RequestGroup> group = e->getRequestGroupMan()->findGroup(gid);
  363. if(group) {
  364. if(group->getState() == RequestGroup::STATE_ACTIVE) {
  365. if(force) {
  366. group->setForceHaltRequested(true, RequestGroup::USER_REQUEST);
  367. } else {
  368. group->setHaltRequested(true, RequestGroup::USER_REQUEST);
  369. }
  370. e->setRefreshInterval(0);
  371. } else {
  372. if(group->isDependencyResolved()) {
  373. e->getRequestGroupMan()->removeReservedGroup(gid);
  374. } else {
  375. return -1;
  376. }
  377. }
  378. } else {
  379. return -1;
  380. }
  381. return 0;
  382. }
  383. int pauseDownload(Session* session, A2Gid gid, bool force)
  384. {
  385. const std::shared_ptr<DownloadEngine>& e =
  386. session->context->reqinfo->getDownloadEngine();
  387. std::shared_ptr<RequestGroup> group = e->getRequestGroupMan()->findGroup(gid);
  388. if(group) {
  389. bool reserved = group->getState() == RequestGroup::STATE_WAITING;
  390. if(pauseRequestGroup(group, reserved, force)) {
  391. e->setRefreshInterval(0);
  392. return 0;
  393. }
  394. }
  395. return -1;
  396. }
  397. int unpauseDownload(Session* session, A2Gid gid)
  398. {
  399. const std::shared_ptr<DownloadEngine>& e =
  400. session->context->reqinfo->getDownloadEngine();
  401. std::shared_ptr<RequestGroup> group = e->getRequestGroupMan()->findGroup(gid);
  402. if(!group ||
  403. group->getState() != RequestGroup::STATE_WAITING ||
  404. !group->isPauseRequested()) {
  405. return -1;
  406. } else {
  407. group->setPauseRequested(false);
  408. e->getRequestGroupMan()->requestQueueCheck();
  409. }
  410. return 0;
  411. }
  412. int changePosition(Session* session, A2Gid gid, int pos, OffsetMode how)
  413. {
  414. const std::shared_ptr<DownloadEngine>& e =
  415. session->context->reqinfo->getDownloadEngine();
  416. try {
  417. return e->getRequestGroupMan()->changeReservedGroupPosition(gid, pos, how);
  418. } catch(RecoverableException& e) {
  419. A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e);
  420. return -1;
  421. }
  422. }
  423. int changeOption(Session* session, A2Gid gid, const KeyVals& options)
  424. {
  425. const std::shared_ptr<DownloadEngine>& e =
  426. session->context->reqinfo->getDownloadEngine();
  427. std::shared_ptr<RequestGroup> group = e->getRequestGroupMan()->findGroup(gid);
  428. if(group) {
  429. Option option;
  430. try {
  431. if(group->getState() == RequestGroup::STATE_ACTIVE) {
  432. apiGatherChangeableOption(&option, options,
  433. OptionParser::getInstance());
  434. } else {
  435. apiGatherChangeableOptionForReserved(&option, options,
  436. OptionParser::getInstance());
  437. }
  438. } catch(RecoverableException& err) {
  439. A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, err);
  440. return -1;
  441. }
  442. changeOption(group, option, e.get());
  443. return 0;
  444. } else {
  445. return -1;
  446. }
  447. }
  448. const std::string& getGlobalOption(Session* session, const std::string& name)
  449. {
  450. const std::shared_ptr<DownloadEngine>& e =
  451. session->context->reqinfo->getDownloadEngine();
  452. const Pref* pref = option::k2p(name);
  453. if(OptionParser::getInstance()->find(pref)) {
  454. return e->getOption()->get(pref);
  455. } else {
  456. return A2STR::NIL;
  457. }
  458. }
  459. KeyVals getGlobalOptions(Session* session)
  460. {
  461. const std::shared_ptr<DownloadEngine>& e =
  462. session->context->reqinfo->getDownloadEngine();
  463. const std::shared_ptr<OptionParser>& optionParser = OptionParser::getInstance();
  464. const Option* option = e->getOption();
  465. KeyVals options;
  466. for(size_t i = 1, len = option::countOption(); i < len; ++i) {
  467. const Pref* pref = option::i2p(i);
  468. if(option->defined(pref) && optionParser->find(pref)) {
  469. options.push_back(KeyVals::value_type(pref->k, option->get(pref)));
  470. }
  471. }
  472. return options;
  473. }
  474. int changeGlobalOption(Session* session, const KeyVals& options)
  475. {
  476. const std::shared_ptr<DownloadEngine>& e =
  477. session->context->reqinfo->getDownloadEngine();
  478. Option option;
  479. try {
  480. apiGatherChangeableGlobalOption(&option, options,
  481. OptionParser::getInstance());
  482. } catch(RecoverableException& err) {
  483. A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, err);
  484. return -1;
  485. }
  486. changeGlobalOption(option, e.get());
  487. return 0;
  488. }
  489. GlobalStat getGlobalStat(Session* session)
  490. {
  491. const std::shared_ptr<DownloadEngine>& e =
  492. session->context->reqinfo->getDownloadEngine();
  493. const std::shared_ptr<RequestGroupMan>& rgman = e->getRequestGroupMan();
  494. TransferStat ts = rgman->calculateStat();
  495. GlobalStat res;
  496. res.downloadSpeed = ts.downloadSpeed;
  497. res.uploadSpeed = ts.uploadSpeed;
  498. res.numActive = rgman->getRequestGroups().size();
  499. res.numWaiting = rgman->getReservedGroups().size();
  500. res.numStopped = rgman->getDownloadResults().size();
  501. return res;
  502. }
  503. std::vector<A2Gid> getActiveDownload(Session* session)
  504. {
  505. const std::shared_ptr<DownloadEngine>& e =
  506. session->context->reqinfo->getDownloadEngine();
  507. const RequestGroupList& groups = e->getRequestGroupMan()->getRequestGroups();
  508. std::vector<A2Gid> res;
  509. for(RequestGroupList::const_iterator i = groups.begin(),
  510. eoi = groups.end(); i != eoi; ++i) {
  511. res.push_back((*i)->getGID());
  512. }
  513. return res;
  514. }
  515. namespace {
  516. template<typename OutputIterator, typename InputIterator>
  517. void createUriEntry
  518. (OutputIterator out,
  519. InputIterator first, InputIterator last,
  520. UriStatus status)
  521. {
  522. for(; first != last; ++first) {
  523. UriData uriData;
  524. uriData.uri = *first;
  525. uriData.status = status;
  526. out++ = uriData;
  527. }
  528. }
  529. } // namespace
  530. namespace {
  531. template<typename OutputIterator>
  532. void createUriEntry
  533. (OutputIterator out, const std::shared_ptr<FileEntry>& file)
  534. {
  535. createUriEntry(out,
  536. file->getSpentUris().begin(),
  537. file->getSpentUris().end(),
  538. URI_USED);
  539. createUriEntry(out,
  540. file->getRemainingUris().begin(),
  541. file->getRemainingUris().end(),
  542. URI_WAITING);
  543. }
  544. } // namespace
  545. namespace {
  546. FileData createFileData
  547. (const std::shared_ptr<FileEntry>& fe, int index, const BitfieldMan* bf)
  548. {
  549. FileData file;
  550. file.index = index;
  551. file.path = fe->getPath();
  552. file.length = fe->getLength();
  553. file.completedLength = bf->getOffsetCompletedLength
  554. (fe->getOffset(), fe->getLength());
  555. file.selected = fe->isRequested();
  556. createUriEntry(std::back_inserter(file.uris), fe);
  557. return file;
  558. }
  559. } // namespace
  560. namespace {
  561. template<typename OutputIterator, typename InputIterator>
  562. void createFileEntry
  563. (OutputIterator out,
  564. InputIterator first, InputIterator last,
  565. const BitfieldMan* bf)
  566. {
  567. size_t index = 1;
  568. for(; first != last; ++first) {
  569. out++ = createFileData(*first, index++, bf);
  570. }
  571. }
  572. } // namespace
  573. namespace {
  574. template<typename OutputIterator, typename InputIterator>
  575. void createFileEntry
  576. (OutputIterator out,
  577. InputIterator first, InputIterator last,
  578. int64_t totalLength,
  579. int32_t pieceLength,
  580. const std::string& bitfield)
  581. {
  582. BitfieldMan bf(pieceLength, totalLength);
  583. bf.setBitfield(reinterpret_cast<const unsigned char*>(bitfield.data()),
  584. bitfield.size());
  585. createFileEntry(out, first, last, &bf);
  586. }
  587. } // namespace
  588. namespace {
  589. template<typename OutputIterator, typename InputIterator>
  590. void createFileEntry
  591. (OutputIterator out,
  592. InputIterator first, InputIterator last,
  593. int64_t totalLength,
  594. int32_t pieceLength,
  595. const std::shared_ptr<PieceStorage>& ps)
  596. {
  597. BitfieldMan bf(pieceLength, totalLength);
  598. if(ps) {
  599. bf.setBitfield(ps->getBitfield(), ps->getBitfieldLength());
  600. }
  601. createFileEntry(out, first, last, &bf);
  602. }
  603. } // namespace
  604. namespace {
  605. template<typename OutputIterator>
  606. void pushRequestOption
  607. (OutputIterator out,
  608. const std::shared_ptr<Option>& option,
  609. const std::shared_ptr<OptionParser>& oparser)
  610. {
  611. for(size_t i = 1, len = option::countOption(); i < len; ++i) {
  612. const Pref* pref = option::i2p(i);
  613. const OptionHandler* h = oparser->find(pref);
  614. if(h && h->getInitialOption() && option->defined(pref)) {
  615. out++ = KeyVals::value_type(pref->k, option->get(pref));
  616. }
  617. }
  618. }
  619. } // namespace
  620. namespace {
  621. const std::string& getRequestOption(const std::shared_ptr<Option>& option,
  622. const std::string& name)
  623. {
  624. const Pref* pref = option::k2p(name);
  625. if(OptionParser::getInstance()->find(pref)) {
  626. return option->get(pref);
  627. } else {
  628. return A2STR::NIL;
  629. }
  630. }
  631. } // namespace
  632. namespace {
  633. KeyVals getRequestOptions(const std::shared_ptr<Option>& option)
  634. {
  635. KeyVals res;
  636. pushRequestOption(std::back_inserter(res), option,
  637. OptionParser::getInstance());
  638. return res;
  639. }
  640. } // namespace
  641. namespace {
  642. struct RequestGroupDH : public DownloadHandle {
  643. RequestGroupDH(const std::shared_ptr<RequestGroup>& group)
  644. : group(group),
  645. ts(group->calculateStat())
  646. {}
  647. virtual ~RequestGroupDH() {}
  648. virtual DownloadStatus getStatus()
  649. {
  650. if(group->getState() == RequestGroup::STATE_ACTIVE) {
  651. return DOWNLOAD_ACTIVE;
  652. } else {
  653. if(group->isPauseRequested()) {
  654. return DOWNLOAD_PAUSED;
  655. } else {
  656. return DOWNLOAD_WAITING;
  657. }
  658. }
  659. }
  660. virtual int64_t getTotalLength()
  661. {
  662. return group->getTotalLength();
  663. }
  664. virtual int64_t getCompletedLength()
  665. {
  666. return group->getCompletedLength();
  667. }
  668. virtual int64_t getUploadLength()
  669. {
  670. return ts.allTimeUploadLength;
  671. }
  672. virtual std::string getBitfield()
  673. {
  674. const std::shared_ptr<PieceStorage>& ps = group->getPieceStorage();
  675. if(ps) {
  676. return std::string(reinterpret_cast<const char*>(ps->getBitfield()),
  677. ps->getBitfieldLength());
  678. } else {
  679. return "";
  680. }
  681. }
  682. virtual int getDownloadSpeed()
  683. {
  684. return ts.downloadSpeed;
  685. }
  686. virtual int getUploadSpeed()
  687. {
  688. return ts.uploadSpeed;
  689. }
  690. virtual const std::string& getInfoHash()
  691. {
  692. #ifdef ENABLE_BITTORRENT
  693. if(group->getDownloadContext()->hasAttribute(CTX_ATTR_BT)) {
  694. return bittorrent::getTorrentAttrs(group->getDownloadContext())
  695. ->infoHash;
  696. }
  697. #endif // ENABLE_BITTORRENT
  698. return A2STR::NIL;
  699. }
  700. virtual size_t getPieceLength()
  701. {
  702. const std::shared_ptr<DownloadContext>& dctx = group->getDownloadContext();
  703. return dctx->getPieceLength();
  704. }
  705. virtual int getNumPieces()
  706. {
  707. return group->getDownloadContext()->getNumPieces();
  708. }
  709. virtual int getConnections()
  710. {
  711. return group->getNumConnection();
  712. }
  713. virtual int getErrorCode()
  714. {
  715. return 0;
  716. }
  717. virtual const std::vector<A2Gid>& getFollowedBy()
  718. {
  719. return group->followedBy();
  720. }
  721. virtual A2Gid getBelongsTo()
  722. {
  723. return group->belongsTo();
  724. }
  725. virtual const std::string& getDir()
  726. {
  727. return group->getOption()->get(PREF_DIR);
  728. }
  729. virtual std::vector<FileData> getFiles()
  730. {
  731. std::vector<FileData> res;
  732. const std::shared_ptr<DownloadContext>& dctx = group->getDownloadContext();
  733. createFileEntry(std::back_inserter(res),
  734. dctx->getFileEntries().begin(),
  735. dctx->getFileEntries().end(),
  736. dctx->getTotalLength(), dctx->getPieceLength(),
  737. group->getPieceStorage());
  738. return res;
  739. }
  740. virtual int getNumFiles()
  741. {
  742. const std::shared_ptr<DownloadContext>& dctx = group->getDownloadContext();
  743. return dctx->getFileEntries().size();
  744. }
  745. virtual FileData getFile(int index)
  746. {
  747. const std::shared_ptr<DownloadContext>& dctx = group->getDownloadContext();
  748. BitfieldMan bf(dctx->getPieceLength(), dctx->getTotalLength());
  749. const std::shared_ptr<PieceStorage>& ps = group->getPieceStorage();
  750. if(ps) {
  751. bf.setBitfield(ps->getBitfield(), ps->getBitfieldLength());
  752. }
  753. return createFileData(dctx->getFileEntries()[index-1], index, &bf);
  754. }
  755. virtual BtMetaInfoData getBtMetaInfo()
  756. {
  757. BtMetaInfoData res;
  758. #ifdef ENABLE_BITTORRENT
  759. if(group->getDownloadContext()->hasAttribute(CTX_ATTR_BT)) {
  760. auto torrentAttrs =
  761. bittorrent::getTorrentAttrs(group->getDownloadContext());
  762. res.announceList = torrentAttrs->announceList;
  763. res.comment = torrentAttrs->comment;
  764. res.creationDate = torrentAttrs->creationDate;
  765. res.mode = torrentAttrs->mode;
  766. if(!torrentAttrs->metadata.empty()) {
  767. res.name = torrentAttrs->name;
  768. }
  769. } else
  770. #endif // ENABLE_BITTORRENT
  771. {
  772. res.creationDate = 0;
  773. res.mode = BT_FILE_MODE_NONE;
  774. }
  775. return res;
  776. }
  777. virtual const std::string& getOption(const std::string& name)
  778. {
  779. return getRequestOption(group->getOption(), name);
  780. }
  781. virtual KeyVals getOptions()
  782. {
  783. return getRequestOptions(group->getOption());
  784. }
  785. std::shared_ptr<RequestGroup> group;
  786. TransferStat ts;
  787. };
  788. } // namespace
  789. namespace {
  790. struct DownloadResultDH : public DownloadHandle {
  791. DownloadResultDH(const std::shared_ptr<DownloadResult>& dr)
  792. : dr(dr)
  793. {}
  794. virtual ~DownloadResultDH() {}
  795. virtual DownloadStatus getStatus()
  796. {
  797. switch(dr->result) {
  798. case error_code::FINISHED:
  799. return DOWNLOAD_COMPLETE;
  800. case error_code::REMOVED:
  801. return DOWNLOAD_REMOVED;
  802. default:
  803. return DOWNLOAD_ERROR;
  804. }
  805. }
  806. virtual int64_t getTotalLength()
  807. {
  808. return dr->totalLength;
  809. }
  810. virtual int64_t getCompletedLength()
  811. {
  812. return dr->completedLength;
  813. }
  814. virtual int64_t getUploadLength()
  815. {
  816. return dr->uploadLength;
  817. }
  818. virtual std::string getBitfield()
  819. {
  820. return dr->bitfield;
  821. }
  822. virtual int getDownloadSpeed()
  823. {
  824. return 0;
  825. }
  826. virtual int getUploadSpeed()
  827. {
  828. return 0;
  829. }
  830. virtual const std::string& getInfoHash()
  831. {
  832. return dr->infoHash;
  833. }
  834. virtual size_t getPieceLength()
  835. {
  836. return dr->pieceLength;
  837. }
  838. virtual int getNumPieces()
  839. {
  840. return dr->numPieces;
  841. }
  842. virtual int getConnections()
  843. {
  844. return 0;
  845. }
  846. virtual int getErrorCode()
  847. {
  848. return dr->result;
  849. }
  850. virtual const std::vector<A2Gid>& getFollowedBy()
  851. {
  852. return dr->followedBy;
  853. }
  854. virtual A2Gid getBelongsTo()
  855. {
  856. return dr->belongsTo;
  857. }
  858. virtual const std::string& getDir()
  859. {
  860. return dr->dir;
  861. }
  862. virtual std::vector<FileData> getFiles()
  863. {
  864. std::vector<FileData> res;
  865. createFileEntry(std::back_inserter(res),
  866. dr->fileEntries.begin(), dr->fileEntries.end(),
  867. dr->totalLength, dr->pieceLength, dr->bitfield);
  868. return res;
  869. }
  870. virtual int getNumFiles()
  871. {
  872. return dr->fileEntries.size();
  873. }
  874. virtual FileData getFile(int index)
  875. {
  876. BitfieldMan bf(dr->pieceLength, dr->totalLength);
  877. bf.setBitfield(reinterpret_cast<const unsigned char*>(dr->bitfield.data()),
  878. dr->bitfield.size());
  879. return createFileData(dr->fileEntries[index-1], index, &bf);
  880. }
  881. virtual BtMetaInfoData getBtMetaInfo()
  882. {
  883. return BtMetaInfoData();
  884. }
  885. virtual const std::string& getOption(const std::string& name)
  886. {
  887. return getRequestOption(dr->option, name);
  888. }
  889. virtual KeyVals getOptions()
  890. {
  891. return getRequestOptions(dr->option);
  892. }
  893. std::shared_ptr<DownloadResult> dr;
  894. };
  895. } // namespace
  896. DownloadHandle* getDownloadHandle(Session* session, A2Gid gid)
  897. {
  898. const std::shared_ptr<DownloadEngine>& e =
  899. session->context->reqinfo->getDownloadEngine();
  900. const std::shared_ptr<RequestGroupMan>& rgman = e->getRequestGroupMan();
  901. std::shared_ptr<RequestGroup> group = rgman->findGroup(gid);
  902. if(group) {
  903. return new RequestGroupDH(group);
  904. } else {
  905. std::shared_ptr<DownloadResult> ds = rgman->findDownloadResult(gid);
  906. if(ds) {
  907. return new DownloadResultDH(ds);
  908. }
  909. }
  910. return 0;
  911. }
  912. void deleteDownloadHandle(DownloadHandle* dh)
  913. {
  914. delete dh;
  915. }
  916. } // namespace aria2