summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2013-05-16 23:09:19 +0900
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2013-05-16 23:09:19 +0900
commitc7c4d46672a12eec9531723037ee1fb7cd5028b4 (patch)
tree698b38190c44204d4b0dd78e65b7c3dbfe002a25
parentbe4c9aa95e4ee240507d91de2925a6d6a2394ebf (diff)
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.
-rw-r--r--doc/manual-src/en/aria2c.rst2
-rw-r--r--src/RpcMethodImpl.cc156
-rw-r--r--src/RpcMethodImpl.h5
-rw-r--r--src/aria2api.cc83
-rw-r--r--src/includes/aria2/aria2.h52
-rw-r--r--test/Aria2ApiTest.cc41
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