Преглед изворни кода

2010-04-11 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Added aria2.pauseAll, aria2.forcePauseAll and aria2.unpauseAll
	XML-RPC method.
	* doc/aria2c.1.txt
	* src/XmlRpcMethodFactory.cc
	* src/XmlRpcMethodImpl.cc
	* src/XmlRpcMethodImpl.h
	* test/XmlRpcMethodTest.cc
Tatsuhiro Tsujikawa пре 15 година
родитељ
комит
15bb26cac8
8 измењених фајлова са 252 додато и 31 уклоњено
  1. 10 0
      ChangeLog
  2. 22 6
      doc/aria2c.1
  3. 22 8
      doc/aria2c.1.html
  4. 26 4
      doc/aria2c.1.txt
  5. 6 0
      src/XmlRpcMethodFactory.cc
  6. 72 13
      src/XmlRpcMethodImpl.cc
  7. 33 0
      src/XmlRpcMethodImpl.h
  8. 61 0
      test/XmlRpcMethodTest.cc

+ 10 - 0
ChangeLog

@@ -1,3 +1,13 @@
+2010-04-11  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Added aria2.pauseAll, aria2.forcePauseAll and aria2.unpauseAll
+	XML-RPC method.
+	* doc/aria2c.1.txt
+	* src/XmlRpcMethodFactory.cc
+	* src/XmlRpcMethodImpl.cc
+	* src/XmlRpcMethodImpl.h
+	* test/XmlRpcMethodTest.cc
+
 2010-04-11  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Added aria2.forcePause XML-RPC command.

+ 22 - 6
doc/aria2c.1

@@ -2,12 +2,12 @@
 .\"     Title: aria2c
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 04/09/2010
+.\"      Date: 04/11/2010
 .\"    Manual: Aria2 Manual
 .\"    Source: Aria2 1.9.1a
 .\"  Language: English
 .\"
-.TH "ARIA2C" "1" "04/09/2010" "Aria2 1\&.9\&.1a" "Aria2 Manual"
+.TH "ARIA2C" "1" "04/11/2010" "Aria2 1\&.9\&.1a" "Aria2 Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -2631,12 +2631,28 @@ This method removes the download denoted by \fIgid\fR\&. This method behaves jus
 .sp
 \fBaria2\&.pause\fR \fIgid\fR
 .sp
-This method pauses the download denoted by \fIgid\fR\&. \fIgid\fR is of type string\&. The status of paused download becomes "paused" and the download is placed on the first position of waiting queue\&. As long as the status is "paused", the download is not started\&. To change status to "waiting", use \fBaria2\&.unpause\fR method\&. This method returns GID of paused download\&.
+This method pauses the download denoted by \fIgid\fR\&. \fIgid\fR is of type string\&. The status of paused download becomes "paused"\&. If the download is active, the download is placed on the first position of waiting queue\&. As long as the status is "paused", the download is not started\&. To change status to "waiting", use \fBaria2\&.unpause\fR method\&. This method returns GID of paused download\&.
+.sp
+\fBaria2\&.pauseAll\fR
+.sp
+This method is equal to calling \fBaria2\&.pause\fR for every active/waiting download\&. This methods returns "OK" for success\&.
+.sp
+\fBaria2\&.forcePause\fR \fIpid\fR
+.sp
+This method pauses the download denoted by \fIgid\fR\&. This method behaves just like \fBaria2\&.pause\fR except that this method pauses download without any action which takes time such as contacting BitTorrent tracker\&.
+.sp
+\fBaria2\&.forcePauseAll\fR
+.sp
+This method is equal to calling \fBaria2\&.forcePause\fR for every active/waiting download\&. This methods returns "OK" for success\&.
 .sp
 \fBaria2\&.unpause\fR \fIgid\fR
 .sp
 This method changes the status of the download denoted by \fIgid\fR from "paused" to "waiting"\&. This makes the download eligible to restart\&. \fIgid\fR is of type string\&. This method returns GID of unpaused download\&.
 .sp
+\fBaria2\&.unpauseAll\fR
+.sp
+This method is equal to calling \fBaria2\&.unpause\fR for every active/waiting download\&. This methods returns "OK" for success\&.
+.sp
 \fBaria2\&.tellStatus\fR \fIgid\fR
 .sp
 This method returns download progress of the download denoted by \fIgid\fR\&. \fIgid\fR is of type string\&. The response is of type struct and it contains following keys\&. The value type is string\&.
@@ -3167,7 +3183,7 @@ aria2 uses 5 connections to download 1 file by default\&. \-s1 limits the number
 .ps -1
 .br
 .sp
-To pause a download, press Ctrl\-C\&. You can resume the transfer by running aria2c with the same argument in the same directory\&. You can change URIs as long as they are pointing to the same file\&.
+To stop a download, press Ctrl\-C\&. You can resume the transfer by running aria2c with the same argument in the same directory\&. You can change URIs as long as they are pointing to the same file\&.
 .sp .5v
 .RE
 .RE
@@ -3383,7 +3399,7 @@ aria2c \-p \-\-lowest\-speed\-limit=4000 file\&.metalink
 .ps -1
 .br
 .sp
-To pause a download, press Ctrl\-C\&. You can resume the transfer by running aria2c with the same argument in the same directory\&.
+To stop a download, press Ctrl\-C\&. You can resume the transfer by running aria2c with the same argument in the same directory\&.
 .sp .5v
 .RE
 .RE
@@ -3527,7 +3543,7 @@ aria2c \-\-max\-upload\-limit=40K file\&.torrent
 .ps -1
 .br
 .sp
-To pause a download, press Ctrl\-C\&. You can resume the transfer by running aria2c with the same argument in the same directory\&.
+To stop a download, press Ctrl\-C\&. You can resume the transfer by running aria2c with the same argument in the same directory\&.
 .sp .5v
 .RE
 .RE

+ 22 - 8
doc/aria2c.1.html

@@ -3102,16 +3102,30 @@ download without any action which takes time such as contacting
 BitTorrent tracker.</p></div>
 <div class="paragraph"><p><strong>aria2.pause</strong> <em>gid</em></p></div>
 <div class="paragraph"><p>This method pauses the download denoted by <em>gid</em>. <em>gid</em> is of type
-string. The status of paused download becomes "paused" and the
-download is placed on the first position of waiting queue.  As long as
-the status is "paused", the download is not started.  To change status
-to "waiting", use <strong>aria2.unpause</strong> method.
+string. The status of paused download becomes "paused".  If the
+download is active, the download is placed on the first position of
+waiting queue.  As long as the status is "paused", the download is not
+started.  To change status to "waiting", use <strong>aria2.unpause</strong> method.
 This method returns GID of paused download.</p></div>
+<div class="paragraph"><p><strong>aria2.pauseAll</strong></p></div>
+<div class="paragraph"><p>This method is equal to calling <strong>aria2.pause</strong> for every active/waiting
+download. This methods returns "OK" for success.</p></div>
+<div class="paragraph"><p><strong>aria2.forcePause</strong> <em>pid</em></p></div>
+<div class="paragraph"><p>This method pauses the download denoted by <em>gid</em>.  This method
+behaves just like <strong>aria2.pause</strong> except that this method pauses
+download without any action which takes time such as contacting
+BitTorrent tracker.</p></div>
+<div class="paragraph"><p><strong>aria2.forcePauseAll</strong></p></div>
+<div class="paragraph"><p>This method is equal to calling <strong>aria2.forcePause</strong> for every
+active/waiting download. This methods returns "OK" for success.</p></div>
 <div class="paragraph"><p><strong>aria2.unpause</strong> <em>gid</em></p></div>
 <div class="paragraph"><p>This method changes the status of the download denoted by <em>gid</em> from
 "paused" to "waiting". This makes the download eligible to restart.
 <em>gid</em> is of type string.  This method returns GID of unpaused
 download.</p></div>
+<div class="paragraph"><p><strong>aria2.unpauseAll</strong></p></div>
+<div class="paragraph"><p>This method is equal to calling <strong>aria2.unpause</strong> for every active/waiting
+download. This methods returns "OK" for success.</p></div>
 <div class="paragraph"><p><strong>aria2.tellStatus</strong> <em>gid</em></p></div>
 <div class="paragraph"><p>This method returns download progress of the download denoted by
 <em>gid</em>. <em>gid</em> is of type string. The response is of type struct and it
@@ -3794,7 +3808,7 @@ pprint(r)</tt></pre>
 <td class="icon">
 <div class="title">Note</div>
 </td>
-<td class="content">To pause a download, press Ctrl-C. You can resume the transfer by running aria2c with the same argument in the same directory. You can change URIs as long as they are pointing to the same file.</td>
+<td class="content">To stop a download, press Ctrl-C. You can resume the transfer by running aria2c with the same argument in the same directory. You can change URIs as long as they are pointing to the same file.</td>
 </tr></table>
 </div>
 <h4 id="_download_a_file_from_2_different_http_servers">Download a file from 2 different HTTP servers</h4>
@@ -3870,7 +3884,7 @@ variables. See <strong>ENVIRONMENT</strong> section.</td>
 <td class="icon">
 <div class="title">Note</div>
 </td>
-<td class="content">To pause a download, press Ctrl-C.
+<td class="content">To stop a download, press Ctrl-C.
 You can resume the transfer by running aria2c with the same argument in the same
 directory.</td>
 </tr></table>
@@ -3922,7 +3936,7 @@ directory.</td>
 <td class="icon">
 <div class="title">Note</div>
 </td>
-<td class="content">To pause a download, press Ctrl-C. You can resume the transfer by running aria2c with the same argument in the same directory.</td>
+<td class="content">To stop a download, press Ctrl-C. You can resume the transfer by running aria2c with the same argument in the same directory.</td>
 </tr></table>
 </div>
 <h4 id="_download_using_bittorrent_magnet_uri">Download using BitTorrent Magnet URI</h4>
@@ -4174,7 +4188,7 @@ files in the program, then also delete it here.</p></div>
 <div id="footnotes"><hr /></div>
 <div id="footer">
 <div id="footer-text">
-Last updated 2010-04-09 00:32:31 JST
+Last updated 2010-04-11 23:42:41 JST
 </div>
 </div>
 </body>

+ 26 - 4
doc/aria2c.1.txt

@@ -1371,12 +1371,29 @@ BitTorrent tracker.
 *aria2.pause* 'gid'
 
 This method pauses the download denoted by 'gid'. 'gid' is of type
-string. The status of paused download becomes "paused" and the
-download is placed on the first position of waiting queue.  As long as
-the status is "paused", the download is not started.  To change status
-to "waiting", use *aria2.unpause* method.
+string. The status of paused download becomes "paused".  If the
+download is active, the download is placed on the first position of
+waiting queue.  As long as the status is "paused", the download is not
+started.  To change status to "waiting", use *aria2.unpause* method.
 This method returns GID of paused download.
 
+*aria2.pauseAll*
+
+This method is equal to calling *aria2.pause* for every active/waiting
+download. This methods returns "OK" for success.
+
+*aria2.forcePause* 'pid'
+
+This method pauses the download denoted by 'gid'.  This method
+behaves just like *aria2.pause* except that this method pauses
+download without any action which takes time such as contacting
+BitTorrent tracker.
+
+*aria2.forcePauseAll*
+
+This method is equal to calling *aria2.forcePause* for every
+active/waiting download. This methods returns "OK" for success.
+
 *aria2.unpause* 'gid'
 
 This method changes the status of the download denoted by 'gid' from
@@ -1384,6 +1401,11 @@ This method changes the status of the download denoted by 'gid' from
 'gid' is of type string.  This method returns GID of unpaused
 download.
 
+*aria2.unpauseAll*
+
+This method is equal to calling *aria2.unpause* for every active/waiting
+download. This methods returns "OK" for success.
+
 *aria2.tellStatus* 'gid'
 
 This method returns download progress of the download denoted by

+ 6 - 0
src/XmlRpcMethodFactory.cc

@@ -62,8 +62,14 @@ XmlRpcMethodFactory::create(const std::string& methodName)
     return SharedHandle<XmlRpcMethod>(new PauseXmlRpcMethod());
   } else if(methodName == ForcePauseXmlRpcMethod::getMethodName()) {
     return SharedHandle<XmlRpcMethod>(new ForcePauseXmlRpcMethod());
+  } else if(methodName == PauseAllXmlRpcMethod::getMethodName()) {
+    return SharedHandle<XmlRpcMethod>(new PauseAllXmlRpcMethod());
+  } else if(methodName == ForcePauseAllXmlRpcMethod::getMethodName()) {
+    return SharedHandle<XmlRpcMethod>(new ForcePauseAllXmlRpcMethod());
   } else if(methodName == UnpauseXmlRpcMethod::getMethodName()) {
     return SharedHandle<XmlRpcMethod>(new UnpauseXmlRpcMethod());
+  } else if(methodName == UnpauseAllXmlRpcMethod::getMethodName()) {
+    return SharedHandle<XmlRpcMethod>(new UnpauseAllXmlRpcMethod());
   } else if(methodName == ForceRemoveXmlRpcMethod::getMethodName()) {
     return SharedHandle<XmlRpcMethod>(new ForceRemoveXmlRpcMethod());
   } else if(methodName == ChangePositionXmlRpcMethod::getMethodName()) {

+ 72 - 13
src/XmlRpcMethodImpl.cc

@@ -348,17 +348,28 @@ BDE ForceRemoveXmlRpcMethod::process
   return removeDownload(req, e, true);
 }
 
-static void pauseRequestGroup
-(const SharedHandle<RequestGroup>& group, bool forcePause)
+static bool pauseRequestGroup
+(const SharedHandle<RequestGroup>& group, bool reserved,  bool forcePause)
 {
-  // Call setHaltRequested before setPauseRequested because
-  // setHaltRequested calls setPauseRequested(false) internally.
-  if(forcePause) {
-    group->setForceHaltRequested(true, RequestGroup::USER_REQUEST);
+  if((reserved && !group->isPauseRequested()) ||
+     (!reserved &&
+      !group->isForceHaltRequested() &&
+      ((forcePause && group->isHaltRequested() && group->isPauseRequested()) ||
+       (!group->isHaltRequested() && !group->isPauseRequested())))) {
+    if(!reserved) {
+      // Call setHaltRequested before setPauseRequested because
+      // setHaltRequested calls setPauseRequested(false) internally.
+      if(forcePause) {
+        group->setForceHaltRequested(true, RequestGroup::USER_REQUEST);
+      } else {
+        group->setHaltRequested(true, RequestGroup::USER_REQUEST);
+      }
+    }
+    group->setPauseRequested(true);
+    return true;
   } else {
-    group->setHaltRequested(true, RequestGroup::USER_REQUEST);
+    return false;
   }
-  group->setPauseRequested(true);
 }
 
 static BDE pauseDownload
@@ -370,15 +381,19 @@ static BDE pauseDownload
     throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
   }
   gid_t gid = util::parseLLInt(params[0].s());
-  SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
-  if(group.isNull() || group->isHaltRequested()) {
+  bool reserved = false;
+  SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
+  if(group.isNull()) {
+    reserved = true;
+    group = e->_requestGroupMan->findReservedGroup(gid);
+  }
+  if(!group.isNull() && pauseRequestGroup(group, reserved, forcePause)) {
+    return createGIDResponse(gid);
+  } else {
     throw DL_ABORT_EX
       (StringFormat("GID#%s cannot be paused now",
                     util::itos(gid).c_str()).str());
-  } else {
-    pauseRequestGroup(group, forcePause);
   }
-  return createGIDResponse(gid);
 }
 
 BDE PauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
@@ -391,6 +406,39 @@ BDE ForcePauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
   return pauseDownload(req, e, true);
 }
 
+template<typename InputIterator>
+static void pauseRequestGroups
+(InputIterator first, InputIterator last, bool reserved, bool forcePause)
+{
+  for(; first != last; ++first) {
+    pauseRequestGroup(*first, reserved, forcePause);
+  }
+}
+
+static BDE pauseAllDownloads
+(const XmlRpcRequest& req, DownloadEngine* e, bool forcePause)
+{
+  const std::deque<SharedHandle<RequestGroup> >& groups =
+    e->_requestGroupMan->getRequestGroups();
+  pauseRequestGroups(groups.begin(), groups.end(), false, forcePause);
+  const std::deque<SharedHandle<RequestGroup> >& reservedGroups =
+    e->_requestGroupMan->getReservedGroups();
+  pauseRequestGroups(reservedGroups.begin(), reservedGroups.end(),
+                     true, forcePause);
+  return BDE_OK;
+}
+
+BDE PauseAllXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
+{
+  return pauseAllDownloads(req, e, false);
+}
+
+BDE ForcePauseAllXmlRpcMethod::process
+(const XmlRpcRequest& req, DownloadEngine* e)
+{
+  return pauseAllDownloads(req, e, true);
+}
+
 BDE UnpauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
 {
   const BDE& params = req._params;
@@ -411,6 +459,17 @@ BDE UnpauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
   return createGIDResponse(gid);
 }
 
+BDE UnpauseAllXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
+{
+  const std::deque<SharedHandle<RequestGroup> >& groups =
+    e->_requestGroupMan->getReservedGroups();
+  std::for_each(groups.begin(), groups.end(),
+                std::bind2nd(mem_fun_sh(&RequestGroup::setPauseRequested),
+                             false));
+  e->_requestGroupMan->requestQueueCheck();    
+  return BDE_OK;
+}
+
 static void createUriEntry(BDE& uriList, const SharedHandle<FileEntry>& file)
 {
   {

+ 33 - 0
src/XmlRpcMethodImpl.h

@@ -106,6 +106,28 @@ public:
   }
 };
 
+class PauseAllXmlRpcMethod:public XmlRpcMethod {
+protected:
+  virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e);
+public:
+  static const std::string& getMethodName()
+  {
+    static std::string methodName = "aria2.pauseAll";
+    return methodName;
+  }
+};
+
+class ForcePauseAllXmlRpcMethod:public XmlRpcMethod {
+protected:
+  virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e);
+public:
+  static const std::string& getMethodName()
+  {
+    static std::string methodName = "aria2.forcePauseAll";
+    return methodName;
+  }
+};
+
 class UnpauseXmlRpcMethod:public XmlRpcMethod {
 protected:
   virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e);
@@ -117,6 +139,17 @@ public:
   }
 };
 
+class UnpauseAllXmlRpcMethod:public XmlRpcMethod {
+protected:
+  virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e);
+public:
+  static const std::string& getMethodName()
+  {
+    static std::string methodName = "aria2.unpauseAll";
+    return methodName;
+  }
+};
+
 #ifdef ENABLE_BITTORRENT
 class AddTorrentXmlRpcMethod:public XmlRpcMethod {
 protected:

+ 61 - 0
test/XmlRpcMethodTest.cc

@@ -20,6 +20,7 @@
 #include "FeatureConfig.h"
 #include "util.h"
 #include "array_fun.h"
+#include "download_helper.h"
 #ifdef ENABLE_BITTORRENT
 # include "BtRegistry.h"
 # include "BtRuntime.h"
@@ -77,6 +78,7 @@ class XmlRpcMethodTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testGetSessionInfo);
   CPPUNIT_TEST(testChangeUri);
   CPPUNIT_TEST(testChangeUri_fail);
+  CPPUNIT_TEST(testPause);
   CPPUNIT_TEST(testSystemMulticall);
   CPPUNIT_TEST(testSystemMulticall_fail);
   CPPUNIT_TEST_SUITE_END();
@@ -139,6 +141,7 @@ public:
   void testGetSessionInfo();
   void testChangeUri();
   void testChangeUri_fail();
+  void testPause();
   void testSystemMulticall();
   void testSystemMulticall_fail();
 };
@@ -920,6 +923,64 @@ void XmlRpcMethodTest::testGetSessionInfo()
                        res._param["sessionId"].s());
 }
 
+void XmlRpcMethodTest::testPause()
+{
+  const std::string URIS[] = {
+    "http://url1",
+    "http://url2",
+    "http://url3",
+  };
+  std::vector<std::string> uris(vbegin(URIS), vend(URIS));
+  _option->put(PREF_FORCE_SEQUENTIAL, V_TRUE);
+  std::vector<SharedHandle<RequestGroup> > groups;
+  createRequestGroupForUri(groups, _option, uris);
+  CPPUNIT_ASSERT_EQUAL((size_t)3, groups.size());  
+  _e->_requestGroupMan->addReservedGroup(groups);
+  {
+    PauseXmlRpcMethod m;
+    XmlRpcRequest req(PauseXmlRpcMethod::getMethodName(), BDE::list());
+    req._params << std::string("1");
+    XmlRpcResponse res = m.execute(req, _e.get());
+    CPPUNIT_ASSERT_EQUAL(0, res._code);
+  }
+  CPPUNIT_ASSERT(groups[0]->isPauseRequested());
+  {
+    UnpauseXmlRpcMethod m;
+    XmlRpcRequest req(UnpauseXmlRpcMethod::getMethodName(), BDE::list());
+    req._params << std::string("1");
+    XmlRpcResponse res = m.execute(req, _e.get());
+    CPPUNIT_ASSERT_EQUAL(0, res._code);
+  }
+  CPPUNIT_ASSERT(!groups[0]->isPauseRequested());
+  {
+    PauseAllXmlRpcMethod m;
+    XmlRpcRequest req(PauseAllXmlRpcMethod::getMethodName(), BDE::list());
+    XmlRpcResponse res = m.execute(req, _e.get());
+    CPPUNIT_ASSERT_EQUAL(0, res._code);
+  }
+  for(size_t i = 0; i < groups.size(); ++i) {
+    CPPUNIT_ASSERT(groups[i]->isPauseRequested());
+  }
+  {
+    UnpauseAllXmlRpcMethod m;
+    XmlRpcRequest req(UnpauseAllXmlRpcMethod::getMethodName(), BDE::list());
+    XmlRpcResponse res = m.execute(req, _e.get());
+    CPPUNIT_ASSERT_EQUAL(0, res._code);
+  }
+  for(size_t i = 0; i < groups.size(); ++i) {
+    CPPUNIT_ASSERT(!groups[i]->isPauseRequested());
+  }
+  {
+    ForcePauseAllXmlRpcMethod m;
+    XmlRpcRequest req(ForcePauseAllXmlRpcMethod::getMethodName(), BDE::list());
+    XmlRpcResponse res = m.execute(req, _e.get());
+    CPPUNIT_ASSERT_EQUAL(0, res._code);
+  }
+  for(size_t i = 0; i < groups.size(); ++i) {
+    CPPUNIT_ASSERT(groups[i]->isPauseRequested());
+  }
+}
+
 void XmlRpcMethodTest::testSystemMulticall()
 {
   SystemMulticallXmlRpcMethod m;