aria2api.cc 26 KB

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