RpcMethodImpl.cc 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2009 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 "RpcMethodImpl.h"
  36. #include <cassert>
  37. #include <algorithm>
  38. #include <sstream>
  39. #include "Logger.h"
  40. #include "LogFactory.h"
  41. #include "DlAbortEx.h"
  42. #include "Option.h"
  43. #include "OptionParser.h"
  44. #include "OptionHandler.h"
  45. #include "DownloadEngine.h"
  46. #include "RequestGroup.h"
  47. #include "download_helper.h"
  48. #include "util.h"
  49. #include "fmt.h"
  50. #include "RpcRequest.h"
  51. #include "PieceStorage.h"
  52. #include "DownloadContext.h"
  53. #include "DiskAdaptor.h"
  54. #include "FileEntry.h"
  55. #include "prefs.h"
  56. #include "message.h"
  57. #include "FeatureConfig.h"
  58. #include "array_fun.h"
  59. #include "RpcMethodFactory.h"
  60. #include "RpcResponse.h"
  61. #include "SegmentMan.h"
  62. #include "TimedHaltCommand.h"
  63. #include "PeerStat.h"
  64. #include "base64.h"
  65. #include "BitfieldMan.h"
  66. #include "SessionSerializer.h"
  67. #include "MessageDigest.h"
  68. #include "message_digest_helper.h"
  69. #include "OpenedFileCounter.h"
  70. #ifdef ENABLE_BITTORRENT
  71. #include "bittorrent_helper.h"
  72. #include "BtRegistry.h"
  73. #include "PeerStorage.h"
  74. #include "Peer.h"
  75. #include "BtRuntime.h"
  76. #include "BtAnnounce.h"
  77. #endif // ENABLE_BITTORRENT
  78. namespace aria2 {
  79. namespace rpc {
  80. namespace {
  81. const char VLB_TRUE[] = "true";
  82. const char VLB_FALSE[] = "false";
  83. const char VLB_ACTIVE[] = "active";
  84. const char VLB_WAITING[] = "waiting";
  85. const char VLB_PAUSED[] = "paused";
  86. const char VLB_REMOVED[] = "removed";
  87. const char VLB_ERROR[] = "error";
  88. const char VLB_COMPLETE[] = "complete";
  89. const char VLB_USED[] = "used";
  90. const char VLB_ZERO[] = "0";
  91. const char KEY_GID[] = "gid";
  92. const char KEY_ERROR_CODE[] = "errorCode";
  93. const char KEY_ERROR_MESSAGE[] = "errorMessage";
  94. const char KEY_STATUS[] = "status";
  95. const char KEY_TOTAL_LENGTH[] = "totalLength";
  96. const char KEY_COMPLETED_LENGTH[] = "completedLength";
  97. const char KEY_DOWNLOAD_SPEED[] = "downloadSpeed";
  98. const char KEY_UPLOAD_SPEED[] = "uploadSpeed";
  99. const char KEY_UPLOAD_LENGTH[] = "uploadLength";
  100. const char KEY_CONNECTIONS[] = "connections";
  101. const char KEY_BITFIELD[] = "bitfield";
  102. const char KEY_PIECE_LENGTH[] = "pieceLength";
  103. const char KEY_NUM_PIECES[] = "numPieces";
  104. const char KEY_FOLLOWED_BY[] = "followedBy";
  105. const char KEY_FOLLOWING[] = "following";
  106. const char KEY_BELONGS_TO[] = "belongsTo";
  107. const char KEY_INFO_HASH[] = "infoHash";
  108. const char KEY_NUM_SEEDERS[] = "numSeeders";
  109. const char KEY_PEER_ID[] = "peerId";
  110. const char KEY_IP[] = "ip";
  111. const char KEY_PORT[] = "port";
  112. const char KEY_AM_CHOKING[] = "amChoking";
  113. const char KEY_PEER_CHOKING[] = "peerChoking";
  114. const char KEY_SEEDER[] = "seeder";
  115. const char KEY_INDEX[] = "index";
  116. const char KEY_PATH[] = "path";
  117. const char KEY_SELECTED[] = "selected";
  118. const char KEY_LENGTH[] = "length";
  119. const char KEY_URI[] = "uri";
  120. const char KEY_CURRENT_URI[] = "currentUri";
  121. const char KEY_VERSION[] = "version";
  122. const char KEY_ENABLED_FEATURES[] = "enabledFeatures";
  123. const char KEY_METHOD_NAME[] = "methodName";
  124. const char KEY_PARAMS[] = "params";
  125. const char KEY_SESSION_ID[] = "sessionId";
  126. const char KEY_FILES[] = "files";
  127. const char KEY_DIR[] = "dir";
  128. const char KEY_URIS[] = "uris";
  129. const char KEY_BITTORRENT[] = "bittorrent";
  130. const char KEY_INFO[] = "info";
  131. const char KEY_NAME[] = "name";
  132. const char KEY_ANNOUNCE_LIST[] = "announceList";
  133. const char KEY_COMMENT[] = "comment";
  134. const char KEY_CREATION_DATE[] = "creationDate";
  135. const char KEY_MODE[] = "mode";
  136. const char KEY_SERVERS[] = "servers";
  137. const char KEY_NUM_WAITING[] = "numWaiting";
  138. const char KEY_NUM_STOPPED[] = "numStopped";
  139. const char KEY_NUM_ACTIVE[] = "numActive";
  140. const char KEY_NUM_STOPPED_TOTAL[] = "numStoppedTotal";
  141. } // namespace
  142. namespace {
  143. std::unique_ptr<ValueBase> createGIDResponse(a2_gid_t gid)
  144. {
  145. return String::g(GroupId::toHex(gid));
  146. }
  147. } // namespace
  148. namespace {
  149. std::unique_ptr<ValueBase> createOKResponse() { return String::g("OK"); }
  150. } // namespace
  151. namespace {
  152. std::unique_ptr<ValueBase>
  153. addRequestGroup(const std::shared_ptr<RequestGroup>& group, DownloadEngine* e,
  154. bool posGiven, int pos)
  155. {
  156. if (posGiven) {
  157. e->getRequestGroupMan()->insertReservedGroup(pos, group);
  158. }
  159. else {
  160. e->getRequestGroupMan()->addReservedGroup(group);
  161. }
  162. return createGIDResponse(group->getGID());
  163. }
  164. } // namespace
  165. namespace {
  166. bool checkPosParam(const Integer* posParam)
  167. {
  168. if (posParam) {
  169. if (posParam->i() >= 0) {
  170. return true;
  171. }
  172. else {
  173. throw DL_ABORT_EX("Position must be greater than or equal to 0.");
  174. }
  175. }
  176. return false;
  177. }
  178. } // namespace
  179. namespace {
  180. a2_gid_t str2Gid(const String* str)
  181. {
  182. assert(str);
  183. if (str->s().size() > sizeof(a2_gid_t) * 2) {
  184. throw DL_ABORT_EX(fmt("Invalid GID %s", str->s().c_str()));
  185. }
  186. a2_gid_t n;
  187. switch (GroupId::expandUnique(n, str->s().c_str())) {
  188. case GroupId::ERR_NOT_UNIQUE:
  189. throw DL_ABORT_EX(fmt("GID %s is not unique", str->s().c_str()));
  190. case GroupId::ERR_NOT_FOUND:
  191. throw DL_ABORT_EX(fmt("GID %s is not found", str->s().c_str()));
  192. case GroupId::ERR_INVALID:
  193. throw DL_ABORT_EX(fmt("Invalid GID %s", str->s().c_str()));
  194. }
  195. return n;
  196. }
  197. } // namespace
  198. namespace {
  199. template <typename OutputIterator>
  200. void extractUris(OutputIterator out, const List* src)
  201. {
  202. if (src) {
  203. for (auto& elem : *src) {
  204. const String* uri = downcast<String>(elem);
  205. if (uri) {
  206. out++ = uri->s();
  207. }
  208. }
  209. }
  210. }
  211. } // namespace
  212. std::unique_ptr<ValueBase> AddUriRpcMethod::process(const RpcRequest& req,
  213. DownloadEngine* e)
  214. {
  215. const List* urisParam = checkRequiredParam<List>(req, 0);
  216. const Dict* optsParam = checkParam<Dict>(req, 1);
  217. const Integer* posParam = checkParam<Integer>(req, 2);
  218. std::vector<std::string> uris;
  219. extractUris(std::back_inserter(uris), urisParam);
  220. if (uris.empty()) {
  221. throw DL_ABORT_EX("URI is not provided.");
  222. }
  223. auto requestOption = std::make_shared<Option>(*e->getOption());
  224. gatherRequestOption(requestOption.get(), optsParam);
  225. bool posGiven = checkPosParam(posParam);
  226. size_t pos = posGiven ? posParam->i() : 0;
  227. std::vector<std::shared_ptr<RequestGroup>> result;
  228. createRequestGroupForUri(result, requestOption, uris,
  229. /* ignoreForceSeq = */ true,
  230. /* ignoreLocalPath = */ true);
  231. if (!result.empty()) {
  232. return addRequestGroup(result.front(), e, posGiven, pos);
  233. }
  234. else {
  235. throw DL_ABORT_EX("No URI to download.");
  236. }
  237. }
  238. namespace {
  239. std::string getHexSha1(const std::string& s)
  240. {
  241. unsigned char hash[20];
  242. message_digest::digest(hash, sizeof(hash), MessageDigest::sha1().get(),
  243. s.data(), s.size());
  244. return util::toHex(hash, sizeof(hash));
  245. }
  246. } // namespace
  247. #ifdef ENABLE_BITTORRENT
  248. std::unique_ptr<ValueBase> AddTorrentRpcMethod::process(const RpcRequest& req,
  249. DownloadEngine* e)
  250. {
  251. const String* torrentParam = checkRequiredParam<String>(req, 0);
  252. const List* urisParam = checkParam<List>(req, 1);
  253. const Dict* optsParam = checkParam<Dict>(req, 2);
  254. const Integer* posParam = checkParam<Integer>(req, 3);
  255. std::unique_ptr<String> tempTorrentParam;
  256. if (req.jsonRpc) {
  257. tempTorrentParam = String::g(
  258. base64::decode(torrentParam->s().begin(), torrentParam->s().end()));
  259. torrentParam = tempTorrentParam.get();
  260. }
  261. std::vector<std::string> uris;
  262. extractUris(std::back_inserter(uris), urisParam);
  263. auto requestOption = std::make_shared<Option>(*e->getOption());
  264. gatherRequestOption(requestOption.get(), optsParam);
  265. bool posGiven = checkPosParam(posParam);
  266. size_t pos = posGiven ? posParam->i() : 0;
  267. std::string filename;
  268. if (requestOption->getAsBool(PREF_RPC_SAVE_UPLOAD_METADATA)) {
  269. filename = util::applyDir(requestOption->get(PREF_DIR),
  270. getHexSha1(torrentParam->s()) + ".torrent");
  271. // Save uploaded data in order to save this download in
  272. // --save-session file.
  273. if (util::saveAs(filename, torrentParam->s(), true)) {
  274. A2_LOG_INFO(
  275. fmt("Uploaded torrent data was saved as %s", filename.c_str()));
  276. requestOption->put(PREF_TORRENT_FILE, filename);
  277. }
  278. else {
  279. A2_LOG_INFO(fmt("Uploaded torrent data was not saved."
  280. " Failed to write file %s",
  281. filename.c_str()));
  282. filename.clear();
  283. }
  284. }
  285. std::vector<std::shared_ptr<RequestGroup>> result;
  286. createRequestGroupForBitTorrent(result, requestOption, uris, filename,
  287. torrentParam->s());
  288. if (!result.empty()) {
  289. return addRequestGroup(result.front(), e, posGiven, pos);
  290. }
  291. else {
  292. throw DL_ABORT_EX("No Torrent to download.");
  293. }
  294. }
  295. #endif // ENABLE_BITTORRENT
  296. #ifdef ENABLE_METALINK
  297. std::unique_ptr<ValueBase> AddMetalinkRpcMethod::process(const RpcRequest& req,
  298. DownloadEngine* e)
  299. {
  300. const String* metalinkParam = checkRequiredParam<String>(req, 0);
  301. const Dict* optsParam = checkParam<Dict>(req, 1);
  302. const Integer* posParam = checkParam<Integer>(req, 2);
  303. std::unique_ptr<String> tempMetalinkParam;
  304. if (req.jsonRpc) {
  305. tempMetalinkParam = String::g(
  306. base64::decode(metalinkParam->s().begin(), metalinkParam->s().end()));
  307. metalinkParam = tempMetalinkParam.get();
  308. }
  309. auto requestOption = std::make_shared<Option>(*e->getOption());
  310. gatherRequestOption(requestOption.get(), optsParam);
  311. bool posGiven = checkPosParam(posParam);
  312. size_t pos = posGiven ? posParam->i() : 0;
  313. std::vector<std::shared_ptr<RequestGroup>> result;
  314. std::string filename;
  315. if (requestOption->getAsBool(PREF_RPC_SAVE_UPLOAD_METADATA)) {
  316. // TODO RFC5854 Metalink has the extension .meta4 and Metalink
  317. // Version 3 uses .metalink extension. We use .meta4 for both
  318. // RFC5854 Metalink and Version 3. aria2 can detect which of which
  319. // by reading content rather than extension.
  320. filename = util::applyDir(requestOption->get(PREF_DIR),
  321. getHexSha1(metalinkParam->s()) + ".meta4");
  322. // Save uploaded data in order to save this download in
  323. // --save-session file.
  324. if (util::saveAs(filename, metalinkParam->s(), true)) {
  325. A2_LOG_INFO(
  326. fmt("Uploaded metalink data was saved as %s", filename.c_str()));
  327. requestOption->put(PREF_METALINK_FILE, filename);
  328. createRequestGroupForMetalink(result, requestOption);
  329. }
  330. else {
  331. A2_LOG_INFO(fmt("Uploaded metalink data was not saved."
  332. " Failed to write file %s",
  333. filename.c_str()));
  334. createRequestGroupForMetalink(result, requestOption, metalinkParam->s());
  335. }
  336. }
  337. else {
  338. createRequestGroupForMetalink(result, requestOption, metalinkParam->s());
  339. }
  340. auto gids = List::g();
  341. if (!result.empty()) {
  342. if (posGiven) {
  343. e->getRequestGroupMan()->insertReservedGroup(pos, result);
  344. }
  345. else {
  346. e->getRequestGroupMan()->addReservedGroup(result);
  347. }
  348. for (auto& i : result) {
  349. gids->append(GroupId::toHex(i->getGID()));
  350. }
  351. }
  352. return std::move(gids);
  353. }
  354. #endif // ENABLE_METALINK
  355. namespace {
  356. std::unique_ptr<ValueBase> removeDownload(const RpcRequest& req,
  357. DownloadEngine* e, bool forceRemove)
  358. {
  359. const String* gidParam = checkRequiredParam<String>(req, 0);
  360. a2_gid_t gid = str2Gid(gidParam);
  361. auto group = e->getRequestGroupMan()->findGroup(gid);
  362. if (group) {
  363. if (group->getState() == RequestGroup::STATE_ACTIVE) {
  364. if (forceRemove) {
  365. group->setForceHaltRequested(true, RequestGroup::USER_REQUEST);
  366. }
  367. else {
  368. group->setHaltRequested(true, RequestGroup::USER_REQUEST);
  369. }
  370. e->setRefreshInterval(std::chrono::milliseconds(0));
  371. }
  372. else {
  373. if (group->isDependencyResolved()) {
  374. e->getRequestGroupMan()->removeReservedGroup(gid);
  375. }
  376. else {
  377. throw DL_ABORT_EX(
  378. fmt("GID#%s cannot be removed now", GroupId::toHex(gid).c_str()));
  379. }
  380. }
  381. }
  382. else {
  383. throw DL_ABORT_EX(fmt("Active Download not found for GID#%s",
  384. GroupId::toHex(gid).c_str()));
  385. }
  386. return createGIDResponse(gid);
  387. }
  388. } // namespace
  389. std::unique_ptr<ValueBase> RemoveRpcMethod::process(const RpcRequest& req,
  390. DownloadEngine* e)
  391. {
  392. return removeDownload(req, e, false);
  393. }
  394. std::unique_ptr<ValueBase> ForceRemoveRpcMethod::process(const RpcRequest& req,
  395. DownloadEngine* e)
  396. {
  397. return removeDownload(req, e, true);
  398. }
  399. namespace {
  400. std::unique_ptr<ValueBase> pauseDownload(const RpcRequest& req,
  401. DownloadEngine* e, bool forcePause)
  402. {
  403. const String* gidParam = checkRequiredParam<String>(req, 0);
  404. a2_gid_t gid = str2Gid(gidParam);
  405. auto group = e->getRequestGroupMan()->findGroup(gid);
  406. if (group) {
  407. bool reserved = group->getState() == RequestGroup::STATE_WAITING;
  408. if (pauseRequestGroup(group, reserved, forcePause)) {
  409. e->setRefreshInterval(std::chrono::milliseconds(0));
  410. return createGIDResponse(gid);
  411. }
  412. }
  413. throw DL_ABORT_EX(
  414. fmt("GID#%s cannot be paused now", GroupId::toHex(gid).c_str()));
  415. }
  416. } // namespace
  417. std::unique_ptr<ValueBase> PauseRpcMethod::process(const RpcRequest& req,
  418. DownloadEngine* e)
  419. {
  420. return pauseDownload(req, e, false);
  421. }
  422. std::unique_ptr<ValueBase> ForcePauseRpcMethod::process(const RpcRequest& req,
  423. DownloadEngine* e)
  424. {
  425. return pauseDownload(req, e, true);
  426. }
  427. namespace {
  428. template <typename InputIterator>
  429. void pauseRequestGroups(InputIterator first, InputIterator last, bool reserved,
  430. bool forcePause)
  431. {
  432. for (; first != last; ++first) {
  433. pauseRequestGroup(*first, reserved, forcePause);
  434. }
  435. }
  436. } // namespace
  437. namespace {
  438. std::unique_ptr<ValueBase> pauseAllDownloads(const RpcRequest& req,
  439. DownloadEngine* e, bool forcePause)
  440. {
  441. auto& groups = e->getRequestGroupMan()->getRequestGroups();
  442. pauseRequestGroups(groups.begin(), groups.end(), false, forcePause);
  443. auto& reservedGroups = e->getRequestGroupMan()->getReservedGroups();
  444. pauseRequestGroups(reservedGroups.begin(), reservedGroups.end(), true,
  445. forcePause);
  446. return createOKResponse();
  447. }
  448. } // namespace
  449. std::unique_ptr<ValueBase> PauseAllRpcMethod::process(const RpcRequest& req,
  450. DownloadEngine* e)
  451. {
  452. return pauseAllDownloads(req, e, false);
  453. }
  454. std::unique_ptr<ValueBase>
  455. ForcePauseAllRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  456. {
  457. return pauseAllDownloads(req, e, true);
  458. }
  459. std::unique_ptr<ValueBase> UnpauseRpcMethod::process(const RpcRequest& req,
  460. DownloadEngine* e)
  461. {
  462. const String* gidParam = checkRequiredParam<String>(req, 0);
  463. a2_gid_t gid = str2Gid(gidParam);
  464. auto group = e->getRequestGroupMan()->findGroup(gid);
  465. if (!group || group->getState() != RequestGroup::STATE_WAITING ||
  466. !group->isPauseRequested()) {
  467. throw DL_ABORT_EX(
  468. fmt("GID#%s cannot be unpaused now", GroupId::toHex(gid).c_str()));
  469. }
  470. else {
  471. group->setPauseRequested(false);
  472. e->getRequestGroupMan()->requestQueueCheck();
  473. }
  474. return createGIDResponse(gid);
  475. }
  476. std::unique_ptr<ValueBase> UnpauseAllRpcMethod::process(const RpcRequest& req,
  477. DownloadEngine* e)
  478. {
  479. auto& groups = e->getRequestGroupMan()->getReservedGroups();
  480. for (auto& group : groups) {
  481. group->setPauseRequested(false);
  482. }
  483. e->getRequestGroupMan()->requestQueueCheck();
  484. return createOKResponse();
  485. }
  486. namespace {
  487. template <typename InputIterator>
  488. void createUriEntry(List* uriList, InputIterator first, InputIterator last,
  489. const std::string& status)
  490. {
  491. for (; first != last; ++first) {
  492. auto entry = Dict::g();
  493. entry->put(KEY_URI, *first);
  494. entry->put(KEY_STATUS, status);
  495. uriList->append(std::move(entry));
  496. }
  497. }
  498. } // namespace
  499. namespace {
  500. void createUriEntry(List* uriList, const std::shared_ptr<FileEntry>& file)
  501. {
  502. createUriEntry(uriList, std::begin(file->getSpentUris()),
  503. std::end(file->getSpentUris()), VLB_USED);
  504. createUriEntry(uriList, std::begin(file->getRemainingUris()),
  505. std::end(file->getRemainingUris()), VLB_WAITING);
  506. }
  507. } // namespace
  508. namespace {
  509. template <typename InputIterator>
  510. void createFileEntry(List* files, InputIterator first, InputIterator last,
  511. const BitfieldMan* bf)
  512. {
  513. size_t index = 1;
  514. for (; first != last; ++first, ++index) {
  515. auto entry = Dict::g();
  516. entry->put(KEY_INDEX, util::uitos(index));
  517. entry->put(KEY_PATH, (*first)->getPath());
  518. entry->put(KEY_SELECTED, (*first)->isRequested() ? VLB_TRUE : VLB_FALSE);
  519. entry->put(KEY_LENGTH, util::itos((*first)->getLength()));
  520. int64_t completedLength = bf->getOffsetCompletedLength(
  521. (*first)->getOffset(), (*first)->getLength());
  522. entry->put(KEY_COMPLETED_LENGTH, util::itos(completedLength));
  523. auto uriList = List::g();
  524. createUriEntry(uriList.get(), *first);
  525. entry->put(KEY_URIS, std::move(uriList));
  526. files->append(std::move(entry));
  527. }
  528. }
  529. } // namespace
  530. namespace {
  531. template <typename InputIterator>
  532. void createFileEntry(List* files, InputIterator first, InputIterator last,
  533. int64_t totalLength, int32_t pieceLength,
  534. const std::string& bitfield)
  535. {
  536. BitfieldMan bf(pieceLength, totalLength);
  537. bf.setBitfield(reinterpret_cast<const unsigned char*>(bitfield.data()),
  538. bitfield.size());
  539. createFileEntry(files, first, last, &bf);
  540. }
  541. } // namespace
  542. namespace {
  543. template <typename InputIterator>
  544. void createFileEntry(List* files, InputIterator first, InputIterator last,
  545. int64_t totalLength, int32_t pieceLength,
  546. const std::shared_ptr<PieceStorage>& ps)
  547. {
  548. BitfieldMan bf(pieceLength, totalLength);
  549. if (ps) {
  550. bf.setBitfield(ps->getBitfield(), ps->getBitfieldLength());
  551. }
  552. createFileEntry(files, first, last, &bf);
  553. }
  554. } // namespace
  555. namespace {
  556. bool requested_key(const std::vector<std::string>& keys, const std::string& k)
  557. {
  558. return keys.empty() || std::find(keys.begin(), keys.end(), k) != keys.end();
  559. }
  560. } // namespace
  561. void gatherProgressCommon(Dict* entryDict,
  562. const std::shared_ptr<RequestGroup>& group,
  563. const std::vector<std::string>& keys)
  564. {
  565. auto& ps = group->getPieceStorage();
  566. if (requested_key(keys, KEY_GID)) {
  567. entryDict->put(KEY_GID, GroupId::toHex(group->getGID()).c_str());
  568. }
  569. if (requested_key(keys, KEY_TOTAL_LENGTH)) {
  570. // This is "filtered" total length if --select-file is used.
  571. entryDict->put(KEY_TOTAL_LENGTH, util::itos(group->getTotalLength()));
  572. }
  573. if (requested_key(keys, KEY_COMPLETED_LENGTH)) {
  574. // This is "filtered" total length if --select-file is used.
  575. entryDict->put(KEY_COMPLETED_LENGTH,
  576. util::itos(group->getCompletedLength()));
  577. }
  578. TransferStat stat = group->calculateStat();
  579. if (requested_key(keys, KEY_DOWNLOAD_SPEED)) {
  580. entryDict->put(KEY_DOWNLOAD_SPEED, util::itos(stat.downloadSpeed));
  581. }
  582. if (requested_key(keys, KEY_UPLOAD_SPEED)) {
  583. entryDict->put(KEY_UPLOAD_SPEED, util::itos(stat.uploadSpeed));
  584. }
  585. if (requested_key(keys, KEY_UPLOAD_LENGTH)) {
  586. entryDict->put(KEY_UPLOAD_LENGTH, util::itos(stat.allTimeUploadLength));
  587. }
  588. if (requested_key(keys, KEY_CONNECTIONS)) {
  589. entryDict->put(KEY_CONNECTIONS, util::itos(group->getNumConnection()));
  590. }
  591. if (requested_key(keys, KEY_BITFIELD)) {
  592. if (ps) {
  593. if (ps->getBitfieldLength() > 0) {
  594. entryDict->put(KEY_BITFIELD,
  595. util::toHex(ps->getBitfield(), ps->getBitfieldLength()));
  596. }
  597. }
  598. }
  599. auto& dctx = group->getDownloadContext();
  600. if (requested_key(keys, KEY_PIECE_LENGTH)) {
  601. entryDict->put(KEY_PIECE_LENGTH, util::itos(dctx->getPieceLength()));
  602. }
  603. if (requested_key(keys, KEY_NUM_PIECES)) {
  604. entryDict->put(KEY_NUM_PIECES, util::uitos(dctx->getNumPieces()));
  605. }
  606. if (requested_key(keys, KEY_FOLLOWED_BY)) {
  607. if (!group->followedBy().empty()) {
  608. auto list = List::g();
  609. // The element is GID.
  610. for (auto& gid : group->followedBy()) {
  611. list->append(GroupId::toHex(gid));
  612. }
  613. entryDict->put(KEY_FOLLOWED_BY, std::move(list));
  614. }
  615. }
  616. if (requested_key(keys, KEY_FOLLOWING)) {
  617. if (group->following()) {
  618. entryDict->put(KEY_FOLLOWING, GroupId::toHex(group->following()));
  619. }
  620. }
  621. if (requested_key(keys, KEY_BELONGS_TO)) {
  622. if (group->belongsTo()) {
  623. entryDict->put(KEY_BELONGS_TO, GroupId::toHex(group->belongsTo()));
  624. }
  625. }
  626. if (requested_key(keys, KEY_FILES)) {
  627. auto files = List::g();
  628. createFileEntry(files.get(), std::begin(dctx->getFileEntries()),
  629. std::end(dctx->getFileEntries()), dctx->getTotalLength(),
  630. dctx->getPieceLength(), ps);
  631. entryDict->put(KEY_FILES, std::move(files));
  632. }
  633. if (requested_key(keys, KEY_DIR)) {
  634. entryDict->put(KEY_DIR, group->getOption()->get(PREF_DIR));
  635. }
  636. }
  637. #ifdef ENABLE_BITTORRENT
  638. void gatherBitTorrentMetadata(Dict* btDict, TorrentAttribute* torrentAttrs)
  639. {
  640. if (!torrentAttrs->comment.empty()) {
  641. btDict->put(KEY_COMMENT, torrentAttrs->comment);
  642. }
  643. if (torrentAttrs->creationDate) {
  644. btDict->put(KEY_CREATION_DATE, Integer::g(torrentAttrs->creationDate));
  645. }
  646. if (torrentAttrs->mode) {
  647. btDict->put(KEY_MODE, bittorrent::getModeString(torrentAttrs->mode));
  648. }
  649. auto destAnnounceList = List::g();
  650. for (auto& annlist : torrentAttrs->announceList) {
  651. auto destAnnounceTier = List::g();
  652. for (auto& ann : annlist) {
  653. destAnnounceTier->append(ann);
  654. }
  655. destAnnounceList->append(std::move(destAnnounceTier));
  656. }
  657. btDict->put(KEY_ANNOUNCE_LIST, std::move(destAnnounceList));
  658. if (!torrentAttrs->metadata.empty()) {
  659. auto infoDict = Dict::g();
  660. infoDict->put(KEY_NAME, torrentAttrs->name);
  661. btDict->put(KEY_INFO, std::move(infoDict));
  662. }
  663. }
  664. namespace {
  665. void gatherProgressBitTorrent(Dict* entryDict,
  666. const std::shared_ptr<RequestGroup>& group,
  667. TorrentAttribute* torrentAttrs,
  668. BtObject* btObject,
  669. const std::vector<std::string>& keys)
  670. {
  671. if (requested_key(keys, KEY_INFO_HASH)) {
  672. entryDict->put(KEY_INFO_HASH, util::toHex(torrentAttrs->infoHash));
  673. }
  674. if (requested_key(keys, KEY_BITTORRENT)) {
  675. auto btDict = Dict::g();
  676. gatherBitTorrentMetadata(btDict.get(), torrentAttrs);
  677. entryDict->put(KEY_BITTORRENT, std::move(btDict));
  678. }
  679. if (requested_key(keys, KEY_NUM_SEEDERS)) {
  680. if (!btObject) {
  681. entryDict->put(KEY_NUM_SEEDERS, VLB_ZERO);
  682. }
  683. else {
  684. auto& peerStorage = btObject->peerStorage;
  685. assert(peerStorage);
  686. auto& peers = peerStorage->getUsedPeers();
  687. entryDict->put(KEY_NUM_SEEDERS,
  688. util::uitos(countSeeder(peers.begin(), peers.end())));
  689. }
  690. }
  691. if (requested_key(keys, KEY_SEEDER)) {
  692. entryDict->put(KEY_SEEDER, group->isSeeder() ? VLB_TRUE : VLB_FALSE);
  693. }
  694. }
  695. } // namespace
  696. namespace {
  697. void gatherPeer(List* peers, const std::shared_ptr<PeerStorage>& ps)
  698. {
  699. auto& usedPeers = ps->getUsedPeers();
  700. for (auto& peer : usedPeers) {
  701. if (!peer->isActive()) {
  702. continue;
  703. }
  704. auto peerEntry = Dict::g();
  705. peerEntry->put(KEY_PEER_ID, util::torrentPercentEncode(peer->getPeerId(),
  706. PEER_ID_LENGTH));
  707. peerEntry->put(KEY_IP, peer->getIPAddress());
  708. if (peer->isIncomingPeer()) {
  709. peerEntry->put(KEY_PORT, VLB_ZERO);
  710. }
  711. else {
  712. peerEntry->put(KEY_PORT, util::uitos(peer->getPort()));
  713. }
  714. peerEntry->put(KEY_BITFIELD,
  715. util::toHex(peer->getBitfield(), peer->getBitfieldLength()));
  716. peerEntry->put(KEY_AM_CHOKING, peer->amChoking() ? VLB_TRUE : VLB_FALSE);
  717. peerEntry->put(KEY_PEER_CHOKING,
  718. peer->peerChoking() ? VLB_TRUE : VLB_FALSE);
  719. peerEntry->put(KEY_DOWNLOAD_SPEED,
  720. util::itos(peer->calculateDownloadSpeed()));
  721. peerEntry->put(KEY_UPLOAD_SPEED, util::itos(peer->calculateUploadSpeed()));
  722. peerEntry->put(KEY_SEEDER, peer->isSeeder() ? VLB_TRUE : VLB_FALSE);
  723. peers->append(std::move(peerEntry));
  724. }
  725. }
  726. } // namespace
  727. #endif // ENABLE_BITTORRENT
  728. namespace {
  729. void gatherProgress(Dict* entryDict, const std::shared_ptr<RequestGroup>& group,
  730. DownloadEngine* e, const std::vector<std::string>& keys)
  731. {
  732. gatherProgressCommon(entryDict, group, keys);
  733. #ifdef ENABLE_BITTORRENT
  734. if (group->getDownloadContext()->hasAttribute(CTX_ATTR_BT)) {
  735. gatherProgressBitTorrent(entryDict, group, bittorrent::getTorrentAttrs(
  736. group->getDownloadContext()),
  737. e->getBtRegistry()->get(group->getGID()), keys);
  738. }
  739. #endif // ENABLE_BITTORRENT
  740. }
  741. } // namespace
  742. void gatherStoppedDownload(Dict* entryDict,
  743. const std::shared_ptr<DownloadResult>& ds,
  744. const std::vector<std::string>& keys)
  745. {
  746. if (requested_key(keys, KEY_GID)) {
  747. entryDict->put(KEY_GID, ds->gid->toHex());
  748. }
  749. if (requested_key(keys, KEY_ERROR_CODE)) {
  750. entryDict->put(KEY_ERROR_CODE, util::itos(static_cast<int>(ds->result)));
  751. }
  752. if (requested_key(keys, KEY_ERROR_MESSAGE)) {
  753. entryDict->put(KEY_ERROR_MESSAGE, ds->resultMessage);
  754. }
  755. if (requested_key(keys, KEY_STATUS)) {
  756. if (ds->result == error_code::REMOVED) {
  757. entryDict->put(KEY_STATUS, VLB_REMOVED);
  758. }
  759. else if (ds->result == error_code::FINISHED) {
  760. entryDict->put(KEY_STATUS, VLB_COMPLETE);
  761. }
  762. else {
  763. entryDict->put(KEY_STATUS, VLB_ERROR);
  764. }
  765. }
  766. if (requested_key(keys, KEY_FOLLOWED_BY)) {
  767. if (!ds->followedBy.empty()) {
  768. auto list = List::g();
  769. // The element is GID.
  770. for (auto gid : ds->followedBy) {
  771. list->append(GroupId::toHex(gid));
  772. }
  773. entryDict->put(KEY_FOLLOWED_BY, std::move(list));
  774. }
  775. }
  776. if (requested_key(keys, KEY_FOLLOWING)) {
  777. if (ds->following) {
  778. entryDict->put(KEY_FOLLOWING, GroupId::toHex(ds->following));
  779. }
  780. }
  781. if (requested_key(keys, KEY_BELONGS_TO)) {
  782. if (ds->belongsTo) {
  783. entryDict->put(KEY_BELONGS_TO, GroupId::toHex(ds->belongsTo));
  784. }
  785. }
  786. if (requested_key(keys, KEY_FILES)) {
  787. auto files = List::g();
  788. createFileEntry(files.get(), std::begin(ds->fileEntries),
  789. std::end(ds->fileEntries), ds->totalLength, ds->pieceLength,
  790. ds->bitfield);
  791. entryDict->put(KEY_FILES, std::move(files));
  792. }
  793. if (requested_key(keys, KEY_TOTAL_LENGTH)) {
  794. entryDict->put(KEY_TOTAL_LENGTH, util::itos(ds->totalLength));
  795. }
  796. if (requested_key(keys, KEY_COMPLETED_LENGTH)) {
  797. entryDict->put(KEY_COMPLETED_LENGTH, util::itos(ds->completedLength));
  798. }
  799. if (requested_key(keys, KEY_UPLOAD_LENGTH)) {
  800. entryDict->put(KEY_UPLOAD_LENGTH, util::itos(ds->uploadLength));
  801. }
  802. if (requested_key(keys, KEY_BITFIELD)) {
  803. if (!ds->bitfield.empty()) {
  804. entryDict->put(KEY_BITFIELD, util::toHex(ds->bitfield));
  805. }
  806. }
  807. if (requested_key(keys, KEY_DOWNLOAD_SPEED)) {
  808. entryDict->put(KEY_DOWNLOAD_SPEED, VLB_ZERO);
  809. }
  810. if (requested_key(keys, KEY_UPLOAD_SPEED)) {
  811. entryDict->put(KEY_UPLOAD_SPEED, VLB_ZERO);
  812. }
  813. if (!ds->infoHash.empty()) {
  814. if (requested_key(keys, KEY_INFO_HASH)) {
  815. entryDict->put(KEY_INFO_HASH, util::toHex(ds->infoHash));
  816. }
  817. if (requested_key(keys, KEY_NUM_SEEDERS)) {
  818. entryDict->put(KEY_NUM_SEEDERS, VLB_ZERO);
  819. }
  820. }
  821. if (requested_key(keys, KEY_PIECE_LENGTH)) {
  822. entryDict->put(KEY_PIECE_LENGTH, util::itos(ds->pieceLength));
  823. }
  824. if (requested_key(keys, KEY_NUM_PIECES)) {
  825. entryDict->put(KEY_NUM_PIECES, util::uitos(ds->numPieces));
  826. }
  827. if (requested_key(keys, KEY_CONNECTIONS)) {
  828. entryDict->put(KEY_CONNECTIONS, VLB_ZERO);
  829. }
  830. if (requested_key(keys, KEY_DIR)) {
  831. entryDict->put(KEY_DIR, ds->dir);
  832. }
  833. }
  834. std::unique_ptr<ValueBase> GetFilesRpcMethod::process(const RpcRequest& req,
  835. DownloadEngine* e)
  836. {
  837. const String* gidParam = checkRequiredParam<String>(req, 0);
  838. a2_gid_t gid = str2Gid(gidParam);
  839. auto files = List::g();
  840. auto group = e->getRequestGroupMan()->findGroup(gid);
  841. if (!group) {
  842. auto dr = e->getRequestGroupMan()->findDownloadResult(gid);
  843. if (!dr) {
  844. throw DL_ABORT_EX(fmt("No file data is available for GID#%s",
  845. GroupId::toHex(gid).c_str()));
  846. }
  847. else {
  848. createFileEntry(files.get(), std::begin(dr->fileEntries),
  849. std::end(dr->fileEntries), dr->totalLength,
  850. dr->pieceLength, dr->bitfield);
  851. }
  852. }
  853. else {
  854. auto& dctx = group->getDownloadContext();
  855. createFileEntry(files.get(),
  856. std::begin(group->getDownloadContext()->getFileEntries()),
  857. std::end(group->getDownloadContext()->getFileEntries()),
  858. dctx->getTotalLength(), dctx->getPieceLength(),
  859. group->getPieceStorage());
  860. }
  861. return std::move(files);
  862. }
  863. std::unique_ptr<ValueBase> GetUrisRpcMethod::process(const RpcRequest& req,
  864. DownloadEngine* e)
  865. {
  866. const String* gidParam = checkRequiredParam<String>(req, 0);
  867. a2_gid_t gid = str2Gid(gidParam);
  868. auto group = e->getRequestGroupMan()->findGroup(gid);
  869. if (!group) {
  870. throw DL_ABORT_EX(fmt("No URI data is available for GID#%s",
  871. GroupId::toHex(gid).c_str()));
  872. }
  873. auto uriList = List::g();
  874. // TODO Current implementation just returns first FileEntry's URIs.
  875. if (!group->getDownloadContext()->getFileEntries().empty()) {
  876. createUriEntry(uriList.get(),
  877. group->getDownloadContext()->getFirstFileEntry());
  878. }
  879. return std::move(uriList);
  880. }
  881. #ifdef ENABLE_BITTORRENT
  882. std::unique_ptr<ValueBase> GetPeersRpcMethod::process(const RpcRequest& req,
  883. DownloadEngine* e)
  884. {
  885. const String* gidParam = checkRequiredParam<String>(req, 0);
  886. a2_gid_t gid = str2Gid(gidParam);
  887. auto group = e->getRequestGroupMan()->findGroup(gid);
  888. if (!group) {
  889. throw DL_ABORT_EX(fmt("No peer data is available for GID#%s",
  890. GroupId::toHex(gid).c_str()));
  891. }
  892. auto peers = List::g();
  893. auto btObject = e->getBtRegistry()->get(group->getGID());
  894. if (btObject) {
  895. assert(btObject->peerStorage);
  896. gatherPeer(peers.get(), btObject->peerStorage);
  897. }
  898. return std::move(peers);
  899. }
  900. #endif // ENABLE_BITTORRENT
  901. std::unique_ptr<ValueBase> TellStatusRpcMethod::process(const RpcRequest& req,
  902. DownloadEngine* e)
  903. {
  904. const String* gidParam = checkRequiredParam<String>(req, 0);
  905. const List* keysParam = checkParam<List>(req, 1);
  906. a2_gid_t gid = str2Gid(gidParam);
  907. std::vector<std::string> keys;
  908. toStringList(std::back_inserter(keys), keysParam);
  909. auto group = e->getRequestGroupMan()->findGroup(gid);
  910. auto entryDict = Dict::g();
  911. if (!group) {
  912. auto ds = e->getRequestGroupMan()->findDownloadResult(gid);
  913. if (!ds) {
  914. throw DL_ABORT_EX(
  915. fmt("No such download for GID#%s", GroupId::toHex(gid).c_str()));
  916. }
  917. gatherStoppedDownload(entryDict.get(), ds, keys);
  918. }
  919. else {
  920. if (requested_key(keys, KEY_STATUS)) {
  921. if (group->getState() == RequestGroup::STATE_ACTIVE) {
  922. entryDict->put(KEY_STATUS, VLB_ACTIVE);
  923. }
  924. else {
  925. if (group->isPauseRequested()) {
  926. entryDict->put(KEY_STATUS, VLB_PAUSED);
  927. }
  928. else {
  929. entryDict->put(KEY_STATUS, VLB_WAITING);
  930. }
  931. }
  932. }
  933. gatherProgress(entryDict.get(), group, e, keys);
  934. }
  935. return std::move(entryDict);
  936. }
  937. std::unique_ptr<ValueBase> TellActiveRpcMethod::process(const RpcRequest& req,
  938. DownloadEngine* e)
  939. {
  940. const List* keysParam = checkParam<List>(req, 0);
  941. std::vector<std::string> keys;
  942. toStringList(std::back_inserter(keys), keysParam);
  943. auto list = List::g();
  944. bool statusReq = requested_key(keys, KEY_STATUS);
  945. for (auto& group : e->getRequestGroupMan()->getRequestGroups()) {
  946. auto entryDict = Dict::g();
  947. if (statusReq) {
  948. entryDict->put(KEY_STATUS, VLB_ACTIVE);
  949. }
  950. gatherProgress(entryDict.get(), group, e, keys);
  951. list->append(std::move(entryDict));
  952. }
  953. return std::move(list);
  954. }
  955. const RequestGroupList& TellWaitingRpcMethod::getItems(DownloadEngine* e) const
  956. {
  957. return e->getRequestGroupMan()->getReservedGroups();
  958. }
  959. void TellWaitingRpcMethod::createEntry(
  960. Dict* entryDict, const std::shared_ptr<RequestGroup>& item,
  961. DownloadEngine* e, const std::vector<std::string>& keys) const
  962. {
  963. if (requested_key(keys, KEY_STATUS)) {
  964. if (item->isPauseRequested()) {
  965. entryDict->put(KEY_STATUS, VLB_PAUSED);
  966. }
  967. else {
  968. entryDict->put(KEY_STATUS, VLB_WAITING);
  969. }
  970. }
  971. gatherProgress(entryDict, item, e, keys);
  972. }
  973. const DownloadResultList&
  974. TellStoppedRpcMethod::getItems(DownloadEngine* e) const
  975. {
  976. return e->getRequestGroupMan()->getDownloadResults();
  977. }
  978. void TellStoppedRpcMethod::createEntry(
  979. Dict* entryDict, const std::shared_ptr<DownloadResult>& item,
  980. DownloadEngine* e, const std::vector<std::string>& keys) const
  981. {
  982. gatherStoppedDownload(entryDict, item, keys);
  983. }
  984. std::unique_ptr<ValueBase>
  985. PurgeDownloadResultRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  986. {
  987. e->getRequestGroupMan()->purgeDownloadResult();
  988. return createOKResponse();
  989. }
  990. std::unique_ptr<ValueBase>
  991. RemoveDownloadResultRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  992. {
  993. const String* gidParam = checkRequiredParam<String>(req, 0);
  994. a2_gid_t gid = str2Gid(gidParam);
  995. if (!e->getRequestGroupMan()->removeDownloadResult(gid)) {
  996. throw DL_ABORT_EX(fmt("Could not remove download result of GID#%s",
  997. GroupId::toHex(gid).c_str()));
  998. }
  999. return createOKResponse();
  1000. }
  1001. std::unique_ptr<ValueBase> ChangeOptionRpcMethod::process(const RpcRequest& req,
  1002. DownloadEngine* e)
  1003. {
  1004. const String* gidParam = checkRequiredParam<String>(req, 0);
  1005. const Dict* optsParam = checkRequiredParam<Dict>(req, 1);
  1006. a2_gid_t gid = str2Gid(gidParam);
  1007. auto group = e->getRequestGroupMan()->findGroup(gid);
  1008. Option option;
  1009. if (group) {
  1010. if (group->getState() == RequestGroup::STATE_ACTIVE) {
  1011. gatherChangeableOption(&option, optsParam);
  1012. }
  1013. else {
  1014. gatherChangeableOptionForReserved(&option, optsParam);
  1015. }
  1016. changeOption(group, option, e);
  1017. }
  1018. else {
  1019. throw DL_ABORT_EX(
  1020. fmt("Cannot change option for GID#%s", GroupId::toHex(gid).c_str()));
  1021. }
  1022. return createOKResponse();
  1023. }
  1024. std::unique_ptr<ValueBase>
  1025. ChangeGlobalOptionRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1026. {
  1027. const Dict* optsParam = checkRequiredParam<Dict>(req, 0);
  1028. Option option;
  1029. gatherChangeableGlobalOption(&option, optsParam);
  1030. changeGlobalOption(option, e);
  1031. return createOKResponse();
  1032. }
  1033. std::unique_ptr<ValueBase> GetVersionRpcMethod::process(const RpcRequest& req,
  1034. DownloadEngine* e)
  1035. {
  1036. auto result = Dict::g();
  1037. result->put(KEY_VERSION, PACKAGE_VERSION);
  1038. auto featureList = List::g();
  1039. for (int feat = 0; feat < MAX_FEATURE; ++feat) {
  1040. const char* name = strSupportedFeature(feat);
  1041. if (name) {
  1042. featureList->append(name);
  1043. }
  1044. }
  1045. result->put(KEY_ENABLED_FEATURES, std::move(featureList));
  1046. return std::move(result);
  1047. }
  1048. namespace {
  1049. void pushRequestOption(Dict* dict, const std::shared_ptr<Option>& option,
  1050. const std::shared_ptr<OptionParser>& oparser)
  1051. {
  1052. for (size_t i = 1, len = option::countOption(); i < len; ++i) {
  1053. PrefPtr pref = option::i2p(i);
  1054. const OptionHandler* h = oparser->find(pref);
  1055. if (h && h->getInitialOption() && option->defined(pref)) {
  1056. dict->put(pref->k, option->get(pref));
  1057. }
  1058. }
  1059. }
  1060. } // namespace
  1061. std::unique_ptr<ValueBase> GetOptionRpcMethod::process(const RpcRequest& req,
  1062. DownloadEngine* e)
  1063. {
  1064. const String* gidParam = checkRequiredParam<String>(req, 0);
  1065. a2_gid_t gid = str2Gid(gidParam);
  1066. auto group = e->getRequestGroupMan()->findGroup(gid);
  1067. auto result = Dict::g();
  1068. if (!group) {
  1069. auto dr = e->getRequestGroupMan()->findDownloadResult(gid);
  1070. if (!dr) {
  1071. throw DL_ABORT_EX(
  1072. fmt("Cannot get option for GID#%s", GroupId::toHex(gid).c_str()));
  1073. }
  1074. pushRequestOption(result.get(), dr->option, getOptionParser());
  1075. }
  1076. else {
  1077. pushRequestOption(result.get(), group->getOption(), getOptionParser());
  1078. }
  1079. return std::move(result);
  1080. }
  1081. std::unique_ptr<ValueBase>
  1082. GetGlobalOptionRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1083. {
  1084. auto result = Dict::g();
  1085. for (size_t i = 0, len = e->getOption()->getTable().size(); i < len; ++i) {
  1086. PrefPtr pref = option::i2p(i);
  1087. if (pref == PREF_RPC_SECRET || !e->getOption()->defined(pref)) {
  1088. continue;
  1089. }
  1090. const OptionHandler* h = getOptionParser()->find(pref);
  1091. if (h) {
  1092. result->put(pref->k, e->getOption()->get(pref));
  1093. }
  1094. }
  1095. return std::move(result);
  1096. }
  1097. std::unique_ptr<ValueBase>
  1098. ChangePositionRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1099. {
  1100. const String* gidParam = checkRequiredParam<String>(req, 0);
  1101. const Integer* posParam = checkRequiredParam<Integer>(req, 1);
  1102. const String* howParam = checkRequiredParam<String>(req, 2);
  1103. a2_gid_t gid = str2Gid(gidParam);
  1104. int pos = posParam->i();
  1105. const std::string& howStr = howParam->s();
  1106. OffsetMode how;
  1107. if (howStr == "POS_SET") {
  1108. how = OFFSET_MODE_SET;
  1109. }
  1110. else if (howStr == "POS_CUR") {
  1111. how = OFFSET_MODE_CUR;
  1112. }
  1113. else if (howStr == "POS_END") {
  1114. how = OFFSET_MODE_END;
  1115. }
  1116. else {
  1117. throw DL_ABORT_EX("Illegal argument.");
  1118. }
  1119. size_t destPos =
  1120. e->getRequestGroupMan()->changeReservedGroupPosition(gid, pos, how);
  1121. return Integer::g(destPos);
  1122. }
  1123. std::unique_ptr<ValueBase>
  1124. GetSessionInfoRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1125. {
  1126. auto result = Dict::g();
  1127. result->put(KEY_SESSION_ID, util::toHex(e->getSessionId()));
  1128. return std::move(result);
  1129. }
  1130. std::unique_ptr<ValueBase> GetServersRpcMethod::process(const RpcRequest& req,
  1131. DownloadEngine* e)
  1132. {
  1133. const String* gidParam = checkRequiredParam<String>(req, 0);
  1134. a2_gid_t gid = str2Gid(gidParam);
  1135. auto group = e->getRequestGroupMan()->findGroup(gid);
  1136. if (!group || group->getState() != RequestGroup::STATE_ACTIVE) {
  1137. throw DL_ABORT_EX(
  1138. fmt("No active download for GID#%s", GroupId::toHex(gid).c_str()));
  1139. }
  1140. auto result = List::g();
  1141. size_t index = 1;
  1142. for (auto& fe : group->getDownloadContext()->getFileEntries()) {
  1143. auto fileEntry = Dict::g();
  1144. fileEntry->put(KEY_INDEX, util::uitos(index++));
  1145. auto servers = List::g();
  1146. for (auto& req : fe->getInFlightRequests()) {
  1147. auto ps = req->getPeerStat();
  1148. if (ps) {
  1149. auto serverEntry = Dict::g();
  1150. serverEntry->put(KEY_URI, req->getUri());
  1151. serverEntry->put(KEY_CURRENT_URI, req->getCurrentUri());
  1152. serverEntry->put(KEY_DOWNLOAD_SPEED,
  1153. util::itos(ps->calculateDownloadSpeed()));
  1154. servers->append(std::move(serverEntry));
  1155. }
  1156. }
  1157. fileEntry->put(KEY_SERVERS, std::move(servers));
  1158. result->append(std::move(fileEntry));
  1159. }
  1160. return std::move(result);
  1161. }
  1162. std::unique_ptr<ValueBase> ChangeUriRpcMethod::process(const RpcRequest& req,
  1163. DownloadEngine* e)
  1164. {
  1165. const String* gidParam = checkRequiredParam<String>(req, 0);
  1166. const Integer* indexParam = checkRequiredInteger(req, 1, IntegerGE(1));
  1167. const List* delUrisParam = checkRequiredParam<List>(req, 2);
  1168. const List* addUrisParam = checkRequiredParam<List>(req, 3);
  1169. const Integer* posParam = checkParam<Integer>(req, 4);
  1170. a2_gid_t gid = str2Gid(gidParam);
  1171. bool posGiven = checkPosParam(posParam);
  1172. size_t pos = posGiven ? posParam->i() : 0;
  1173. size_t index = indexParam->i() - 1;
  1174. auto group = e->getRequestGroupMan()->findGroup(gid);
  1175. if (!group) {
  1176. throw DL_ABORT_EX(
  1177. fmt("Cannot remove URIs from GID#%s", GroupId::toHex(gid).c_str()));
  1178. }
  1179. auto& files = group->getDownloadContext()->getFileEntries();
  1180. if (files.size() <= index) {
  1181. throw DL_ABORT_EX(fmt("fileIndex is out of range"));
  1182. }
  1183. auto& s = files[index];
  1184. size_t delcount = 0;
  1185. for (auto& elem : *delUrisParam) {
  1186. const String* uri = downcast<String>(elem);
  1187. if (uri && s->removeUri(uri->s())) {
  1188. ++delcount;
  1189. }
  1190. }
  1191. size_t addcount = 0;
  1192. if (posGiven) {
  1193. for (auto& elem : *addUrisParam) {
  1194. const String* uri = downcast<String>(elem);
  1195. if (uri && s->insertUri(uri->s(), pos)) {
  1196. ++addcount;
  1197. ++pos;
  1198. }
  1199. }
  1200. }
  1201. else {
  1202. for (auto& elem : *addUrisParam) {
  1203. const String* uri = downcast<String>(elem);
  1204. if (uri && s->addUri(uri->s())) {
  1205. ++addcount;
  1206. }
  1207. }
  1208. }
  1209. if (addcount && group->getPieceStorage()) {
  1210. std::vector<std::unique_ptr<Command>> commands;
  1211. group->createNextCommand(commands, e);
  1212. e->addCommand(std::move(commands));
  1213. group->getSegmentMan()->recognizeSegmentFor(s);
  1214. }
  1215. auto res = List::g();
  1216. res->append(Integer::g(delcount));
  1217. res->append(Integer::g(addcount));
  1218. return std::move(res);
  1219. }
  1220. namespace {
  1221. std::unique_ptr<ValueBase> goingShutdown(const RpcRequest& req,
  1222. DownloadEngine* e, bool forceHalt)
  1223. {
  1224. // Schedule shutdown after 3seconds to give time to client to
  1225. // receive RPC response.
  1226. e->addRoutineCommand(
  1227. make_unique<TimedHaltCommand>(e->newCUID(), e, 3_s, forceHalt));
  1228. A2_LOG_INFO("Scheduled shutdown in 3 seconds.");
  1229. return createOKResponse();
  1230. }
  1231. } // namespace
  1232. std::unique_ptr<ValueBase> ShutdownRpcMethod::process(const RpcRequest& req,
  1233. DownloadEngine* e)
  1234. {
  1235. return goingShutdown(req, e, false);
  1236. }
  1237. std::unique_ptr<ValueBase>
  1238. ForceShutdownRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1239. {
  1240. return goingShutdown(req, e, true);
  1241. }
  1242. std::unique_ptr<ValueBase>
  1243. GetGlobalStatRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1244. {
  1245. auto& rgman = e->getRequestGroupMan();
  1246. auto ts = rgman->calculateStat();
  1247. auto res = Dict::g();
  1248. res->put(KEY_DOWNLOAD_SPEED, util::itos(ts.downloadSpeed));
  1249. res->put(KEY_UPLOAD_SPEED, util::itos(ts.uploadSpeed));
  1250. res->put(KEY_NUM_WAITING, util::uitos(rgman->getReservedGroups().size()));
  1251. res->put(KEY_NUM_STOPPED, util::uitos(rgman->getDownloadResults().size()));
  1252. res->put(KEY_NUM_STOPPED_TOTAL, util::uitos(rgman->getNumStoppedTotal()));
  1253. res->put(KEY_NUM_ACTIVE, util::uitos(rgman->getRequestGroups().size()));
  1254. return std::move(res);
  1255. }
  1256. std::unique_ptr<ValueBase> SaveSessionRpcMethod::process(const RpcRequest& req,
  1257. DownloadEngine* e)
  1258. {
  1259. const std::string& filename = e->getOption()->get(PREF_SAVE_SESSION);
  1260. if (filename.empty()) {
  1261. throw DL_ABORT_EX("Filename is not given.");
  1262. }
  1263. SessionSerializer sessionSerializer(e->getRequestGroupMan().get());
  1264. if (sessionSerializer.save(filename)) {
  1265. A2_LOG_NOTICE(
  1266. fmt(_("Serialized session to '%s' successfully."), filename.c_str()));
  1267. return createOKResponse();
  1268. }
  1269. throw DL_ABORT_EX(
  1270. fmt("Failed to serialize session to '%s'.", filename.c_str()));
  1271. }
  1272. std::unique_ptr<ValueBase>
  1273. SystemMulticallRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1274. {
  1275. // Should never get here, since SystemMulticallRpcMethod overrides execute().
  1276. assert(false);
  1277. return nullptr;
  1278. }
  1279. RpcResponse SystemMulticallRpcMethod::execute(RpcRequest req, DownloadEngine* e)
  1280. {
  1281. auto authorized = RpcResponse::AUTHORIZED;
  1282. try {
  1283. const List* methodSpecs = checkRequiredParam<List>(req, 0);
  1284. auto list = List::g();
  1285. for (auto& methodSpec : *methodSpecs) {
  1286. Dict* methodDict = downcast<Dict>(methodSpec);
  1287. if (!methodDict) {
  1288. list->append(createErrorResponse(
  1289. DL_ABORT_EX("system.multicall expected struct."), req));
  1290. continue;
  1291. }
  1292. const String* methodName =
  1293. downcast<String>(methodDict->get(KEY_METHOD_NAME));
  1294. if (!methodName) {
  1295. list->append(
  1296. createErrorResponse(DL_ABORT_EX("Missing methodName."), req));
  1297. continue;
  1298. }
  1299. if (methodName->s() == getMethodName()) {
  1300. list->append(createErrorResponse(
  1301. DL_ABORT_EX("Recursive system.multicall forbidden."), req));
  1302. continue;
  1303. }
  1304. // TODO what if params missing?
  1305. auto tempParamsList = methodDict->get(KEY_PARAMS);
  1306. std::unique_ptr<List> paramsList;
  1307. if (downcast<List>(tempParamsList)) {
  1308. paramsList.reset(
  1309. static_cast<List*>(methodDict->popValue(KEY_PARAMS).release()));
  1310. }
  1311. else {
  1312. paramsList = List::g();
  1313. }
  1314. RpcRequest r = {methodName->s(), std::move(paramsList), nullptr,
  1315. req.jsonRpc};
  1316. RpcResponse res = getMethod(methodName->s())->execute(std::move(r), e);
  1317. if (rpc::not_authorized(res)) {
  1318. authorized = RpcResponse::NOTAUTHORIZED;
  1319. }
  1320. if (res.code == 0) {
  1321. auto l = List::g();
  1322. l->append(std::move(res.param));
  1323. list->append(std::move(l));
  1324. }
  1325. else {
  1326. list->append(std::move(res.param));
  1327. }
  1328. }
  1329. return RpcResponse(0, authorized, std::move(list), std::move(req.id));
  1330. }
  1331. catch (RecoverableException& ex) {
  1332. A2_LOG_DEBUG_EX(EX_EXCEPTION_CAUGHT, ex);
  1333. return RpcResponse(1, authorized, createErrorResponse(ex, req),
  1334. std::move(req.id));
  1335. }
  1336. }
  1337. std::unique_ptr<ValueBase>
  1338. SystemListMethodsRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1339. {
  1340. auto list = List::g();
  1341. for (auto& s : allMethodNames()) {
  1342. list->append(s);
  1343. }
  1344. return std::move(list);
  1345. }
  1346. RpcResponse SystemListMethodsRpcMethod::execute(RpcRequest req,
  1347. DownloadEngine* e)
  1348. {
  1349. auto r = process(req, e);
  1350. return RpcResponse(0, RpcResponse::AUTHORIZED, std::move(r),
  1351. std::move(req.id));
  1352. }
  1353. std::unique_ptr<ValueBase>
  1354. SystemListNotificationsRpcMethod::process(const RpcRequest& req,
  1355. DownloadEngine* e)
  1356. {
  1357. auto list = List::g();
  1358. for (auto& s : allNotificationsNames()) {
  1359. list->append(s);
  1360. }
  1361. return std::move(list);
  1362. }
  1363. RpcResponse SystemListNotificationsRpcMethod::execute(RpcRequest req,
  1364. DownloadEngine* e)
  1365. {
  1366. auto r = process(req, e);
  1367. return RpcResponse(0, RpcResponse::AUTHORIZED, std::move(r),
  1368. std::move(req.id));
  1369. }
  1370. std::unique_ptr<ValueBase> NoSuchMethodRpcMethod::process(const RpcRequest& req,
  1371. DownloadEngine* e)
  1372. {
  1373. throw DL_ABORT_EX(fmt("No such method: %s", req.methodName.c_str()));
  1374. }
  1375. } // namespace rpc
  1376. bool pauseRequestGroup(const std::shared_ptr<RequestGroup>& group,
  1377. bool reserved, bool forcePause)
  1378. {
  1379. if ((reserved && !group->isPauseRequested()) ||
  1380. (!reserved && !group->isForceHaltRequested() &&
  1381. ((forcePause && group->isHaltRequested() && group->isPauseRequested()) ||
  1382. (!group->isHaltRequested() && !group->isPauseRequested())))) {
  1383. if (!reserved) {
  1384. // Call setHaltRequested before setPauseRequested because
  1385. // setHaltRequested calls setPauseRequested(false) internally.
  1386. if (forcePause) {
  1387. group->setForceHaltRequested(true, RequestGroup::NONE);
  1388. }
  1389. else {
  1390. group->setHaltRequested(true, RequestGroup::NONE);
  1391. }
  1392. }
  1393. group->setPauseRequested(true);
  1394. return true;
  1395. }
  1396. else {
  1397. return false;
  1398. }
  1399. }
  1400. void changeOption(const std::shared_ptr<RequestGroup>& group,
  1401. const Option& option, DownloadEngine* e)
  1402. {
  1403. const std::shared_ptr<DownloadContext>& dctx = group->getDownloadContext();
  1404. const std::shared_ptr<Option>& grOption = group->getOption();
  1405. grOption->merge(option);
  1406. if (option.defined(PREF_CHECKSUM)) {
  1407. const std::string& checksum = grOption->get(PREF_CHECKSUM);
  1408. auto p = util::divide(std::begin(checksum), std::end(checksum), '=');
  1409. std::string hashType(p.first.first, p.first.second);
  1410. util::lowercase(hashType);
  1411. dctx->setDigest(hashType, util::fromHex(p.second.first, p.second.second));
  1412. }
  1413. if (option.defined(PREF_SELECT_FILE)) {
  1414. auto sgl = util::parseIntSegments(grOption->get(PREF_SELECT_FILE));
  1415. sgl.normalize();
  1416. dctx->setFileFilter(std::move(sgl));
  1417. }
  1418. if (option.defined(PREF_SPLIT)) {
  1419. group->setNumConcurrentCommand(grOption->getAsInt(PREF_SPLIT));
  1420. }
  1421. if (option.defined(PREF_MAX_CONNECTION_PER_SERVER)) {
  1422. int maxConn = grOption->getAsInt(PREF_MAX_CONNECTION_PER_SERVER);
  1423. const std::vector<std::shared_ptr<FileEntry>>& files =
  1424. dctx->getFileEntries();
  1425. for (auto& file : files) {
  1426. (file)->setMaxConnectionPerServer(maxConn);
  1427. }
  1428. }
  1429. if (option.defined(PREF_DIR) || option.defined(PREF_OUT)) {
  1430. if (!group->getMetadataInfo()) {
  1431. assert(dctx->getFileEntries().size() == 1);
  1432. auto& fileEntry = dctx->getFirstFileEntry();
  1433. if (!grOption->blank(PREF_OUT)) {
  1434. fileEntry->setPath(
  1435. util::applyDir(grOption->get(PREF_DIR), grOption->get(PREF_OUT)));
  1436. fileEntry->setSuffixPath(A2STR::NIL);
  1437. }
  1438. else if (fileEntry->getSuffixPath().empty()) {
  1439. fileEntry->setPath(A2STR::NIL);
  1440. }
  1441. else {
  1442. fileEntry->setPath(util::applyDir(grOption->get(PREF_DIR),
  1443. fileEntry->getSuffixPath()));
  1444. }
  1445. }
  1446. else if (group->getMetadataInfo()
  1447. #ifdef ENABLE_BITTORRENT
  1448. && !dctx->hasAttribute(CTX_ATTR_BT)
  1449. #endif // ENABLE_BITTORRENT
  1450. ) {
  1451. // In case of Metalink
  1452. for (auto& fileEntry : dctx->getFileEntries()) {
  1453. // PREF_OUT is not applicable to Metalink. We have always
  1454. // suffixPath set.
  1455. fileEntry->setPath(util::applyDir(grOption->get(PREF_DIR),
  1456. fileEntry->getSuffixPath()));
  1457. }
  1458. }
  1459. }
  1460. #ifdef ENABLE_BITTORRENT
  1461. if (option.defined(PREF_DIR) || option.defined(PREF_INDEX_OUT)) {
  1462. if (dctx->hasAttribute(CTX_ATTR_BT)) {
  1463. std::istringstream indexOutIn(grOption->get(PREF_INDEX_OUT));
  1464. std::vector<std::pair<size_t, std::string>> indexPaths =
  1465. util::createIndexPaths(indexOutIn);
  1466. for (std::vector<std::pair<size_t, std::string>>::const_iterator
  1467. i = indexPaths.begin(),
  1468. eoi = indexPaths.end();
  1469. i != eoi; ++i) {
  1470. dctx->setFilePathWithIndex(
  1471. (*i).first, util::applyDir(grOption->get(PREF_DIR), (*i).second));
  1472. }
  1473. }
  1474. }
  1475. #endif // ENABLE_BITTORRENT
  1476. if (option.defined(PREF_MAX_DOWNLOAD_LIMIT)) {
  1477. group->setMaxDownloadSpeedLimit(
  1478. grOption->getAsInt(PREF_MAX_DOWNLOAD_LIMIT));
  1479. }
  1480. if (option.defined(PREF_MAX_UPLOAD_LIMIT)) {
  1481. group->setMaxUploadSpeedLimit(grOption->getAsInt(PREF_MAX_UPLOAD_LIMIT));
  1482. }
  1483. #ifdef ENABLE_BITTORRENT
  1484. auto btObject = e->getBtRegistry()->get(group->getGID());
  1485. if (btObject) {
  1486. if (option.defined(PREF_BT_MAX_PEERS)) {
  1487. btObject->btRuntime->setMaxPeers(grOption->getAsInt(PREF_BT_MAX_PEERS));
  1488. }
  1489. }
  1490. #endif // ENABLE_BITTORRENT
  1491. }
  1492. void changeGlobalOption(const Option& option, DownloadEngine* e)
  1493. {
  1494. e->getOption()->merge(option);
  1495. if (option.defined(PREF_MAX_OVERALL_DOWNLOAD_LIMIT)) {
  1496. e->getRequestGroupMan()->setMaxOverallDownloadSpeedLimit(
  1497. option.getAsInt(PREF_MAX_OVERALL_DOWNLOAD_LIMIT));
  1498. }
  1499. if (option.defined(PREF_MAX_OVERALL_UPLOAD_LIMIT)) {
  1500. e->getRequestGroupMan()->setMaxOverallUploadSpeedLimit(
  1501. option.getAsInt(PREF_MAX_OVERALL_UPLOAD_LIMIT));
  1502. }
  1503. if (option.defined(PREF_MAX_CONCURRENT_DOWNLOADS)) {
  1504. e->getRequestGroupMan()->setMaxConcurrentDownloads(
  1505. option.getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS));
  1506. e->getRequestGroupMan()->requestQueueCheck();
  1507. }
  1508. if (option.defined(PREF_OPTIMIZE_CONCURRENT_DOWNLOADS)) {
  1509. e->getRequestGroupMan()->setupOptimizeConcurrentDownloads();
  1510. e->getRequestGroupMan()->requestQueueCheck();
  1511. }
  1512. if (option.defined(PREF_MAX_DOWNLOAD_RESULT)) {
  1513. e->getRequestGroupMan()->setMaxDownloadResult(
  1514. option.getAsInt(PREF_MAX_DOWNLOAD_RESULT));
  1515. }
  1516. if (option.defined(PREF_LOG_LEVEL)) {
  1517. LogFactory::setLogLevel(option.get(PREF_LOG_LEVEL));
  1518. }
  1519. if (option.defined(PREF_LOG)) {
  1520. LogFactory::setLogFile(option.get(PREF_LOG));
  1521. try {
  1522. LogFactory::reconfigure();
  1523. }
  1524. catch (RecoverableException& e) {
  1525. // TODO no exception handling
  1526. }
  1527. }
  1528. if (option.defined(PREF_BT_MAX_OPEN_FILES)) {
  1529. auto& openedFileCounter = e->getRequestGroupMan()->getOpenedFileCounter();
  1530. openedFileCounter->setMaxOpenFiles(option.getAsInt(PREF_BT_MAX_OPEN_FILES));
  1531. }
  1532. }
  1533. } // namespace aria2