Add changeOption and DownloadHandle::getOption API

In aria2c.rst, define section label for "Input File" section so that
it can be referenced from other document.
pull/89/head
Tatsuhiro Tsujikawa 2013-05-16 23:09:19 +09:00
parent be4c9aa95e
commit c7c4d46672
6 changed files with 260 additions and 79 deletions

View File

@ -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
~~~~~~~~~~

View File

@ -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

View File

@ -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

View File

@ -225,6 +225,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,
@ -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 =
@ -527,6 +574,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)
@ -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

View File

@ -404,6 +404,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
*
@ -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;
};
/**

View File

@ -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