diff options
| -rw-r--r-- | doc/manual-src/en/aria2c.rst | 2 | ||||
| -rw-r--r-- | src/RpcMethodImpl.cc | 156 | ||||
| -rw-r--r-- | src/RpcMethodImpl.h | 5 | ||||
| -rw-r--r-- | src/aria2api.cc | 83 | ||||
| -rw-r--r-- | src/includes/aria2/aria2.h | 52 | ||||
| -rw-r--r-- | test/Aria2ApiTest.cc | 41 |
6 files changed, 260 insertions, 79 deletions
diff --git a/doc/manual-src/en/aria2c.rst b/doc/manual-src/en/aria2c.rst index 0a26fa92..7734ec02 100644 --- a/doc/manual-src/en/aria2c.rst +++ b/doc/manual-src/en/aria2c.rst @@ -1733,6 +1733,8 @@ if you have a torrent or metalink with chunk checksums for the file, you can resume the download without a control file by giving -V option to aria2c in command-line. +.. _input-file: + Input File ~~~~~~~~~~ diff --git a/src/RpcMethodImpl.cc b/src/RpcMethodImpl.cc index c88753f7..1142c445 100644 --- a/src/RpcMethodImpl.cc +++ b/src/RpcMethodImpl.cc @@ -1082,85 +1082,6 @@ SharedHandle<ValueBase> RemoveDownloadResultRpcMethod::process return VLB_OK; } -namespace { -void changeOption -(const SharedHandle<RequestGroup>& group, - const Option& option, - DownloadEngine* e) -{ - const SharedHandle<DownloadContext>& dctx = group->getDownloadContext(); - const SharedHandle<Option>& grOption = group->getOption(); - grOption->merge(option); - if(option.defined(PREF_CHECKSUM)) { - const std::string& checksum = grOption->get(PREF_CHECKSUM); - std::pair<Scip, Scip> p; - util::divide(p, checksum.begin(), checksum.end(), '='); - std::string hashType(p.first.first, p.first.second); - util::lowercase(hashType); - dctx->setDigest(hashType, util::fromHex(p.second.first, p.second.second)); - } - if(option.defined(PREF_SELECT_FILE)) { - SegList<int> sgl; - util::parseIntSegments(sgl, grOption->get(PREF_SELECT_FILE)); - sgl.normalize(); - dctx->setFileFilter(sgl); - } - if(option.defined(PREF_SPLIT)) { - group->setNumConcurrentCommand(grOption->getAsInt(PREF_SPLIT)); - } - if(option.defined(PREF_MAX_CONNECTION_PER_SERVER)) { - int maxConn = grOption->getAsInt(PREF_MAX_CONNECTION_PER_SERVER); - const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries(); - for(std::vector<SharedHandle<FileEntry> >::const_iterator i = files.begin(), - eoi = files.end(); i != eoi; ++i) { - (*i)->setMaxConnectionPerServer(maxConn); - } - } - if(option.defined(PREF_DIR) || option.defined(PREF_OUT)) { - if(dctx->getFileEntries().size() == 1 -#ifdef ENABLE_BITTORRENT - && !dctx->hasAttribute(CTX_ATTR_BT) -#endif // ENABLE_BITTORRENT - ) { - dctx->getFirstFileEntry()->setPath - (grOption->blank(PREF_OUT) ? A2STR::NIL : - util::applyDir(grOption->get(PREF_DIR), grOption->get(PREF_OUT))); - } - } -#ifdef ENABLE_BITTORRENT - if(option.defined(PREF_DIR) || option.defined(PREF_INDEX_OUT)) { - if(dctx->hasAttribute(CTX_ATTR_BT)) { - std::istringstream indexOutIn(grOption->get(PREF_INDEX_OUT)); - std::vector<std::pair<size_t, std::string> > indexPaths = - util::createIndexPaths(indexOutIn); - for(std::vector<std::pair<size_t, std::string> >::const_iterator i = - indexPaths.begin(), eoi = indexPaths.end(); i != eoi; ++i) { - dctx->setFilePathWithIndex - ((*i).first, - util::applyDir(grOption->get(PREF_DIR), (*i).second)); - } - } - } -#endif // ENABLE_BITTORRENT - if(option.defined(PREF_MAX_DOWNLOAD_LIMIT)) { - group->setMaxDownloadSpeedLimit - (grOption->getAsInt(PREF_MAX_DOWNLOAD_LIMIT)); - } - if(option.defined(PREF_MAX_UPLOAD_LIMIT)) { - group->setMaxUploadSpeedLimit(grOption->getAsInt(PREF_MAX_UPLOAD_LIMIT)); - } -#ifdef ENABLE_BITTORRENT - const SharedHandle<BtObject>& btObject = - e->getBtRegistry()->get(group->getGID()); - if(btObject) { - if(option.defined(PREF_BT_MAX_PEERS)) { - btObject->btRuntime->setMaxPeers(grOption->getAsInt(PREF_BT_MAX_PEERS)); - } - } -#endif // ENABLE_BITTORRENT -} -} // namespace - SharedHandle<ValueBase> ChangeOptionRpcMethod::process (const RpcRequest& req, DownloadEngine* e) { @@ -1544,4 +1465,81 @@ bool pauseRequestGroup } } +void changeOption +(const SharedHandle<RequestGroup>& group, + const Option& option, + DownloadEngine* e) +{ + const SharedHandle<DownloadContext>& dctx = group->getDownloadContext(); + const SharedHandle<Option>& grOption = group->getOption(); + grOption->merge(option); + if(option.defined(PREF_CHECKSUM)) { + const std::string& checksum = grOption->get(PREF_CHECKSUM); + std::pair<Scip, Scip> p; + util::divide(p, checksum.begin(), checksum.end(), '='); + std::string hashType(p.first.first, p.first.second); + util::lowercase(hashType); + dctx->setDigest(hashType, util::fromHex(p.second.first, p.second.second)); + } + if(option.defined(PREF_SELECT_FILE)) { + SegList<int> sgl; + util::parseIntSegments(sgl, grOption->get(PREF_SELECT_FILE)); + sgl.normalize(); + dctx->setFileFilter(sgl); + } + if(option.defined(PREF_SPLIT)) { + group->setNumConcurrentCommand(grOption->getAsInt(PREF_SPLIT)); + } + if(option.defined(PREF_MAX_CONNECTION_PER_SERVER)) { + int maxConn = grOption->getAsInt(PREF_MAX_CONNECTION_PER_SERVER); + const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries(); + for(std::vector<SharedHandle<FileEntry> >::const_iterator i = files.begin(), + eoi = files.end(); i != eoi; ++i) { + (*i)->setMaxConnectionPerServer(maxConn); + } + } + if(option.defined(PREF_DIR) || option.defined(PREF_OUT)) { + if(dctx->getFileEntries().size() == 1 +#ifdef ENABLE_BITTORRENT + && !dctx->hasAttribute(CTX_ATTR_BT) +#endif // ENABLE_BITTORRENT + ) { + dctx->getFirstFileEntry()->setPath + (grOption->blank(PREF_OUT) ? A2STR::NIL : + util::applyDir(grOption->get(PREF_DIR), grOption->get(PREF_OUT))); + } + } +#ifdef ENABLE_BITTORRENT + if(option.defined(PREF_DIR) || option.defined(PREF_INDEX_OUT)) { + if(dctx->hasAttribute(CTX_ATTR_BT)) { + std::istringstream indexOutIn(grOption->get(PREF_INDEX_OUT)); + std::vector<std::pair<size_t, std::string> > indexPaths = + util::createIndexPaths(indexOutIn); + for(std::vector<std::pair<size_t, std::string> >::const_iterator i = + indexPaths.begin(), eoi = indexPaths.end(); i != eoi; ++i) { + dctx->setFilePathWithIndex + ((*i).first, + util::applyDir(grOption->get(PREF_DIR), (*i).second)); + } + } + } +#endif // ENABLE_BITTORRENT + if(option.defined(PREF_MAX_DOWNLOAD_LIMIT)) { + group->setMaxDownloadSpeedLimit + (grOption->getAsInt(PREF_MAX_DOWNLOAD_LIMIT)); + } + if(option.defined(PREF_MAX_UPLOAD_LIMIT)) { + group->setMaxUploadSpeedLimit(grOption->getAsInt(PREF_MAX_UPLOAD_LIMIT)); + } +#ifdef ENABLE_BITTORRENT + const SharedHandle<BtObject>& btObject = + e->getBtRegistry()->get(group->getGID()); + if(btObject) { + if(option.defined(PREF_BT_MAX_PEERS)) { + btObject->btRuntime->setMaxPeers(grOption->getAsInt(PREF_BT_MAX_PEERS)); + } + } +#endif // ENABLE_BITTORRENT +} + } // namespace aria2 diff --git a/src/RpcMethodImpl.h b/src/RpcMethodImpl.h index 90e439c4..b1b254b5 100644 --- a/src/RpcMethodImpl.h +++ b/src/RpcMethodImpl.h @@ -608,6 +608,11 @@ void gatherBitTorrentMetadata bool pauseRequestGroup (const SharedHandle<RequestGroup>& group, bool reserved, bool forcePause); +void changeOption +(const SharedHandle<RequestGroup>& group, + const Option& option, + DownloadEngine* e); + } // namespace aria2 #endif // D_RPC_METHOD_IMPL_H diff --git a/src/aria2api.cc b/src/aria2api.cc index f3634224..069bb12a 100644 --- a/src/aria2api.cc +++ b/src/aria2api.cc @@ -226,6 +226,27 @@ void apiGatherRequestOption(Option* option, const KeyVals& options, } // namespace namespace { +void apiGatherChangeableOption(Option* option, const KeyVals& options, + const SharedHandle<OptionParser>& optionParser) +{ + apiGatherOption(options.begin(), options.end(), + std::mem_fun(&OptionHandler::getChangeOption), + option, optionParser); +} +} // namespace + +namespace { +void apiGatherChangeableOptionForReserved +(Option* option, const KeyVals& options, + const SharedHandle<OptionParser>& optionParser) +{ + apiGatherOption(options.begin(), options.end(), + std::mem_fun(&OptionHandler::getChangeOptionForReserved), + option, optionParser); +} +} // namespace + +namespace { void addRequestGroup(const SharedHandle<RequestGroup>& group, const SharedHandle<DownloadEngine>& e, int position) @@ -419,6 +440,32 @@ int changePosition(Session* session, const A2Gid& gid, int pos, OffsetMode how) } } +int changeOption(Session* session, const A2Gid& gid, const KeyVals& options) +{ + const SharedHandle<DownloadEngine>& e = + session->context->reqinfo->getDownloadEngine(); + SharedHandle<RequestGroup> group = e->getRequestGroupMan()->findGroup(gid); + if(group) { + Option option; + try { + if(group->getState() == RequestGroup::STATE_ACTIVE) { + apiGatherChangeableOption(&option, options, + OptionParser::getInstance()); + } else { + apiGatherChangeableOptionForReserved(&option, options, + OptionParser::getInstance()); + } + } catch(RecoverableException& err) { + A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, err); + return -1; + } + changeOption(group, option, e.get()); + return 0; + } else { + return -1; + } +} + std::vector<A2Gid> getActiveDownload(Session* session) { const SharedHandle<DownloadEngine>& e = @@ -528,6 +575,23 @@ void createFileEntry } // namespace namespace { +template<typename OutputIterator> +void pushRequestOption +(OutputIterator out, + const SharedHandle<Option>& option, + const SharedHandle<OptionParser>& oparser) +{ + for(size_t i = 1, len = option::countOption(); i < len; ++i) { + const Pref* pref = option::i2p(i); + const OptionHandler* h = oparser->find(pref); + if(h && h->getInitialOption() && option->defined(pref)) { + out++ = KeyVals::value_type(pref->k, option->get(pref)); + } + } +} +} // namespace + +namespace { struct RequestGroupDH : public DownloadHandle { RequestGroupDH(const SharedHandle<RequestGroup>& group) : group(group), @@ -660,6 +724,17 @@ struct RequestGroupDH : public DownloadHandle { #endif // ENABLE_BITTORRENT return res; } + virtual const std::string& getOption(const std::string& name) + { + return group->getOption()->get(option::k2p(name)); + } + virtual KeyVals getOption() + { + KeyVals res; + pushRequestOption(std::back_inserter(res), group->getOption(), + OptionParser::getInstance()); + return res; + } SharedHandle<RequestGroup> group; TransferStat ts; }; @@ -761,6 +836,14 @@ struct DownloadResultDH : public DownloadHandle { { return BtMetaInfoData(); } + virtual const std::string& getOption(const std::string& name) + { + return A2STR::NIL; + } + virtual KeyVals getOption() + { + return KeyVals(); + } SharedHandle<DownloadResult> dr; }; } // namespace diff --git a/src/includes/aria2/aria2.h b/src/includes/aria2/aria2.h index 8ca87e29..c1a4b637 100644 --- a/src/includes/aria2/aria2.h +++ b/src/includes/aria2/aria2.h @@ -405,6 +405,38 @@ int pauseDownload(Session* session, const A2Gid& gid, bool force = false); int unpauseDownload(Session* session, const A2Gid& gid); /** + * @function + * + * Apply options in the |options| to the download denoted by the |gid| + * dynamically. The following options can be changed for downloads in + * :c:macro:`DOWNLOAD_ACTIVE` status: + * + * * :option:`bt-max-peers <--bt-max-peers>` + * * :option:`bt-request-peer-speed-limit <--bt-request-peer-speed-limit>` + * * :option:`bt-remove-unselected-file <--bt-remove-unselected-file>` + * * :option:`force-save <--force-save>` + * * :option:`max-download-limit <--max-download-limit>` + * * :option:`max-upload-limit <-u>` + * + * For downloads in :c:macro:`DOWNLOAD_WAITING` or + * :c:macro:`DOWNLOAD_PAUSED` status, in addition to the above + * options, options listed in :ref:`input-file` subsection are available, + * except for following options: + * :option:`dry-run <--dry-run>`, + * :option:`metalink-base-uri <--metalink-base-uri>`, + * :option:`parameterized-uri <-P>`, + * :option:`pause <--pause>`, + * :option:`piece-length <--piece-length>` and + * :option:`rpc-save-upload-metadata <--rpc-save-upload-metadata>` option. + * + * The options which are not applicable or unknown, they are just + * ignored. + * + * This function returns 0 if it succeeds, or negative error code. + */ +int changeOption(Session* session, const A2Gid& gid, const KeyVals& options); + +/** * @enum * * Constants how to re-position a download. @@ -733,6 +765,26 @@ public: * stopped/completed. */ virtual BtMetaInfoData getBtMetaInfo() = 0; + /** + * Returns the option value denoted by the |name|. If the option + * denoted by the |name| is not available, returns empty string. + * + * Calling this function for the download which is not in + * :c:macro:`DOWNLOAD_ACTIVE`, :c:macro:`DOWNLOAD_PAUSED` or + * :c:macro:`DOWNLOAD_WAITING` will return empty string. + */ + virtual const std::string& getOption(const std::string& name) = 0; + /** + * Returns options for this download. Note that this function does + * not return options which have no default value and have not been + * set by :func:`sessionNew()`, configuration files or API + * functions. + * + * Calling this function for the download which is not in + * :c:macro:`DOWNLOAD_ACTIVE`, :c:macro:`DOWNLOAD_PAUSED` or + * :c:macro:`DOWNLOAD_WAITING` will return empty array. + */ + virtual KeyVals getOption() = 0; }; /** diff --git a/test/Aria2ApiTest.cc b/test/Aria2ApiTest.cc index 1948273a..96be3b61 100644 --- a/test/Aria2ApiTest.cc +++ b/test/Aria2ApiTest.cc @@ -12,6 +12,7 @@ class Aria2ApiTest:public CppUnit::TestFixture { CPPUNIT_TEST(testAddTorrent); CPPUNIT_TEST(testRemovePause); CPPUNIT_TEST(testChangePosition); + CPPUNIT_TEST(testChangeOption); CPPUNIT_TEST_SUITE_END(); Session* session_; @@ -33,6 +34,7 @@ public: void testAddTorrent(); void testRemovePause(); void testChangePosition(); + void testChangeOption(); }; CPPUNIT_TEST_SUITE_REGISTRATION(Aria2ApiTest); @@ -149,4 +151,43 @@ void Aria2ApiTest::testChangePosition() } +void Aria2ApiTest::testChangeOption() +{ + A2Gid gid; + std::vector<std::string> uris(1); + KeyVals options; + uris[0] = "http://localhost/1"; + options.push_back(KeyVals::value_type("dir", "mydownload")); + CPPUNIT_ASSERT_EQUAL(0, addUri(session_, &gid, uris, options)); + + DownloadHandle* hd = getDownloadHandle(session_, gid); + CPPUNIT_ASSERT(hd); + CPPUNIT_ASSERT_EQUAL(1, hd->getNumFiles()); + FileData file = hd->getFile(1); + CPPUNIT_ASSERT_EQUAL((size_t)1, file.uris.size()); + CPPUNIT_ASSERT_EQUAL(uris[0], file.uris[0].uri); + + CPPUNIT_ASSERT_EQUAL(std::string("mydownload"), hd->getOption("dir")); + CPPUNIT_ASSERT(hd->getOption("unknown").empty()); + KeyVals retopts = hd->getOption(); + CPPUNIT_ASSERT(std::find(retopts.begin(), retopts.end(), + KeyVals::value_type("dir", "mydownload")) + != retopts.end()); + deleteDownloadHandle(hd); + // failure with null gid + CPPUNIT_ASSERT_EQUAL(-1, changeOption(session_, (A2Gid)0, options)); + // change option + options.clear(); + options.push_back(KeyVals::value_type("dir", "newlocation")); + CPPUNIT_ASSERT_EQUAL(0, changeOption(session_, gid, options)); + hd = getDownloadHandle(session_, gid); + CPPUNIT_ASSERT_EQUAL(std::string("newlocation"), hd->getOption("dir")); + deleteDownloadHandle(hd); + // failure with bad option value + options.clear(); + options.push_back(KeyVals::value_type("file-allocation", "foo")); + CPPUNIT_ASSERT_EQUAL(-1, changeOption(session_, gid, options)); +} + + } // namespace aria2 |
