Przeglądaj źródła

2010-01-17 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Now offset argument in aria2.tellWaiting and aria2.tellStopped
	accepts a negative integer.  'offset' == -1 points last download
	in the waiting queue and 'offset' == -2 points the download before
	the last download, and so on. The downloads in the response are in
	reversed order.
	* doc/aria2c.1.txt
	* src/XmlRpcMethodImpl.cc
	* src/XmlRpcMethodImpl.h
	* test/XmlRpcMethodTest.cc
Tatsuhiro Tsujikawa 15 lat temu
rodzic
commit
f9c6c0ccd8
7 zmienionych plików z 226 dodań i 91 usunięć
  1. 12 0
      ChangeLog
  2. 15 3
      doc/aria2c.1
  3. 25 16
      doc/aria2c.1.html
  4. 30 15
      doc/aria2c.1.txt
  5. 23 53
      src/XmlRpcMethodImpl.cc
  6. 88 4
      src/XmlRpcMethodImpl.h
  7. 33 0
      test/XmlRpcMethodTest.cc

+ 12 - 0
ChangeLog

@@ -1,3 +1,15 @@
+2010-01-17  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Now offset argument in aria2.tellWaiting and aria2.tellStopped
+	accepts a negative integer.  'offset' == -1 points last download
+	in the waiting queue and 'offset' == -2 points the download before
+	the last download, and so on. The downloads in the response are in
+	reversed order.
+	* doc/aria2c.1.txt
+	* src/XmlRpcMethodImpl.cc
+	* src/XmlRpcMethodImpl.h
+	* test/XmlRpcMethodTest.cc
+
 2010-01-17  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Added --human-readable option.  This option, when true is given,

+ 15 - 3
doc/aria2c.1

@@ -2376,15 +2376,27 @@ seeder
 .sp
 \fBaria2\&.tellActive\fR
 .sp
-This method returns the list of active downloads\&. The respose is of type array and its element is the same struct returned by \fBaria2\&.tellStatus\fR method\&.
+This method returns the list of active downloads\&. The response is of type array and its element is the same struct returned by \fBaria2\&.tellStatus\fR method\&.
 .sp
 \fBaria2\&.tellWaiting\fR \fIoffset, num\fR
 .sp
-This method returns the list of waiting download in the range of [\fIoffset\fR, \fIoffset\fR+\fInum\fR)\&. \fIoffset\fR is of type integer and specifies the offset from the download waiting at the front\&. \fInum\fR is of type integer and specifies the number of downloads to be returned\&. For example, imagine that three downloads "A","B" and "C" are waiting in this order\&. aria2\&.tellWaiting(0, 1) returns "A"\&. aria2\&.tellWaiting(1, 2) returns "B" and "C"\&. The respose is of type array and its element is the same struct returned by \fBaria2\&.tellStatus\fR method\&.
+This method returns the list of waiting download\&. \fIoffset\fR is of type integer and specifies the offset from the download waiting at the front\&. \fInum\fR is of type integer and specifies the number of downloads to be returned\&.
+.sp
+If offset is a positive integer, this method returns downloads in the range of [\fIoffset\fR, \fIoffset\fR+\fInum\fR)\&.
+.sp
+\fIoffset\fR can be a negative integer\&. \fIoffset\fR == \-1 points last download in the waiting queue and \fIoffset\fR == \-2 points the download before the last download, and so on\&. The downloads in the response are in reversed order\&.
+.sp
+For example, imagine that three downloads "A","B" and "C" are waiting in this order\&. aria2\&.tellWaiting(0, 1) returns ["A"]\&. aria2\&.tellWaiting(1, 2) returns ["B", "C"]\&. aria2\&.tellWaiting(\-1, 2) returns ["C", "B"]\&.
+.sp
+The response is of type array and its element is the same struct returned by \fBaria2\&.tellStatus\fR method\&.
 .sp
 \fBaria2\&.tellStopped\fR \fIoffset, num\fR
 .sp
-This method returns the list of stopped download in the range of [\fIoffset\fR, \fIoffset\fR+\fInum\fR)\&. \fIoffset\fR is of type integer and specifies the offset from the oldest download\&. \fInum\fR is of type integer and specifies the number of downloads to be returned\&. The respose is of type array and its element is the same struct returned by \fBaria2\&.tellStatus\fR method\&.
+This method returns the list of stopped download\&. \fIoffset\fR is of type integer and specifies the offset from the oldest download\&. \fInum\fR is of type integer and specifies the number of downloads to be returned\&.
+.sp
+\fIoffset\fR and \fInum\fR have the same semantics as \fBaria2\&.tellWaiting\fR method\&.
+.sp
+The response is of type array and its element is the same struct returned by \fBaria2\&.tellStatus\fR method\&.
 .sp
 \fBaria2\&.changePosition\fR \fIgid, pos, how\fR
 .sp

+ 25 - 16
doc/aria2c.1.html

@@ -3031,25 +3031,34 @@ seeder
 </dd>
 </dl></div>
 <div class="paragraph"><p><strong>aria2.tellActive</strong></p></div>
-<div class="paragraph"><p>This method returns the list of active downloads.  The respose is of
+<div class="paragraph"><p>This method returns the list of active downloads.  The response is of
 type array and its element is the same struct returned by
 <strong>aria2.tellStatus</strong> method.</p></div>
 <div class="paragraph"><p><strong>aria2.tellWaiting</strong> <em>offset, num</em></p></div>
-<div class="paragraph"><p>This method returns the list of waiting download in the range of
-[<em>offset</em>, <em>offset</em>+<em>num</em>). <em>offset</em> is of type integer and specifies
-the offset from the download waiting at the front. <em>num</em> is of type
-integer and specifies the number of downloads to be returned. For
-example, imagine that three downloads "A","B" and "C" are waiting in
-this order. aria2.tellWaiting(0, 1) returns "A". aria2.tellWaiting(1,
-2) returns "B" and "C".  The respose is of type array and its element
-is the same struct returned by <strong>aria2.tellStatus</strong> method.</p></div>
+<div class="paragraph"><p>This method returns the list of waiting download.  <em>offset</em> is of type
+integer and specifies the offset from the download waiting at the
+front. <em>num</em> is of type integer and specifies the number of downloads
+to be returned.</p></div>
+<div class="paragraph"><p>If offset is a positive integer, this method returns downloads in the
+range of [<em>offset</em>, <em>offset</em>+<em>num</em>).</p></div>
+<div class="paragraph"><p><em>offset</em> can be a negative integer. <em>offset</em> == -1 points last
+download in the waiting queue and <em>offset</em> == -2 points the download
+before the last download, and so on. The downloads in the response are
+in reversed order.</p></div>
+<div class="paragraph"><p>For example, imagine that three downloads "A","B" and "C" are waiting
+in this order. aria2.tellWaiting(0, 1) returns
+["A"]. aria2.tellWaiting(1, 2) returns ["B", "C"].
+aria2.tellWaiting(-1, 2) returns ["C", "B"].</p></div>
+<div class="paragraph"><p>The response is of type array and its element is the same struct
+returned by <strong>aria2.tellStatus</strong> method.</p></div>
 <div class="paragraph"><p><strong>aria2.tellStopped</strong> <em>offset, num</em></p></div>
-<div class="paragraph"><p>This method returns the list of stopped download in the range of
-[<em>offset</em>, <em>offset</em>+<em>num</em>). <em>offset</em> is of type integer and specifies
-the offset from the oldest download. <em>num</em> is of type integer and
-specifies the number of downloads to be returned.  The respose is of
-type array and its element is the same struct returned by
-<strong>aria2.tellStatus</strong> method.</p></div>
+<div class="paragraph"><p>This method returns the list of stopped download.  <em>offset</em> is of type
+integer and specifies the offset from the oldest download. <em>num</em> is of
+type integer and specifies the number of downloads to be returned.</p></div>
+<div class="paragraph"><p><em>offset</em> and <em>num</em> have the same semantics as <strong>aria2.tellWaiting</strong>
+method.</p></div>
+<div class="paragraph"><p>The response is of type array and its element is the same struct
+returned by <strong>aria2.tellStatus</strong> method.</p></div>
 <div class="paragraph"><p><strong>aria2.changePosition</strong> <em>gid, pos, how</em></p></div>
 <div class="paragraph"><p>This method changes the position of the download denoted by
 <em>gid</em>. <em>pos</em> is of type integer. <em>how</em> is of type string. If <em>how</em> is
@@ -3587,7 +3596,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-01-17 16:21:53 JST
+Last updated 2010-01-17 18:47:03 JST
 </div>
 </div>
 </body>

+ 30 - 15
doc/aria2c.1.txt

@@ -1352,29 +1352,44 @@ seeder::
 
 *aria2.tellActive*
 
-This method returns the list of active downloads.  The respose is of
+This method returns the list of active downloads.  The response is of
 type array and its element is the same struct returned by
 *aria2.tellStatus* method.
 
 *aria2.tellWaiting* 'offset, num'
 
-This method returns the list of waiting download in the range of
-['offset', 'offset'+'num'). 'offset' is of type integer and specifies
-the offset from the download waiting at the front. 'num' is of type
-integer and specifies the number of downloads to be returned. For
-example, imagine that three downloads "A","B" and "C" are waiting in
-this order. aria2.tellWaiting(0, 1) returns "A". aria2.tellWaiting(1,
-2) returns "B" and "C".  The respose is of type array and its element
-is the same struct returned by *aria2.tellStatus* method.
+This method returns the list of waiting download.  'offset' is of type
+integer and specifies the offset from the download waiting at the
+front. 'num' is of type integer and specifies the number of downloads
+to be returned.
+
+If offset is a positive integer, this method returns downloads in the
+range of ['offset', 'offset'+'num').
+
+'offset' can be a negative integer. 'offset' == -1 points last
+download in the waiting queue and 'offset' == -2 points the download
+before the last download, and so on. The downloads in the response are
+in reversed order.
+
+For example, imagine that three downloads "A","B" and "C" are waiting
+in this order. aria2.tellWaiting(0, 1) returns
+["A"]. aria2.tellWaiting(1, 2) returns ["B", "C"].
+aria2.tellWaiting(-1, 2) returns ["C", "B"].
+
+The response is of type array and its element is the same struct
+returned by *aria2.tellStatus* method.
 
 *aria2.tellStopped* 'offset, num'
 
-This method returns the list of stopped download in the range of
-['offset', 'offset'+'num'). 'offset' is of type integer and specifies
-the offset from the oldest download. 'num' is of type integer and
-specifies the number of downloads to be returned.  The respose is of
-type array and its element is the same struct returned by
-*aria2.tellStatus* method.
+This method returns the list of stopped download.  'offset' is of type
+integer and specifies the offset from the oldest download. 'num' is of
+type integer and specifies the number of downloads to be returned.
+
+'offset' and 'num' have the same semantics as *aria2.tellWaiting*
+method.
+
+The response is of type array and its element is the same struct
+returned by *aria2.tellStatus* method.
 
 *aria2.changePosition* 'gid, pos, how'
 

+ 23 - 53
src/XmlRpcMethodImpl.cc

@@ -586,73 +586,43 @@ BDE TellActiveXmlRpcMethod::process
   return list;
 }
 
-template<typename InputIterator>
-static std::pair<InputIterator, InputIterator>
-getPaginationRange
-(const XmlRpcRequest& req, InputIterator first, InputIterator last)
+template<typename T>
+void AbstractPaginationXmlRpcMethod<T>::checkPaginationParams
+(const BDE& params) const
 {
-  const BDE& params = req._params;
   assert(params.isList());
-
   if(params.size() != 2 ||
      !params[0].isInteger() || !params[1].isInteger() ||
-     params[0].i() < 0 || params[1].i() < 0) {
+     params[1].i() < 0) {
     throw DL_ABORT_EX("Invalid argument. Specify offset and num in integer.");
   }
+}
 
-  size_t offset = params[0].i();
-  size_t num = params[1].i();
+const std::deque<SharedHandle<RequestGroup> >&
+TellWaitingXmlRpcMethod::getItems(DownloadEngine* e) const
+{
+  return e->_requestGroupMan->getReservedGroups();
+}
 
-  BDE list = BDE::list();
-  size_t size = std::distance(first, last);
-  if(size <= offset) {
-    return std::make_pair(last, last);
-  }
-  size_t lastDistance;
-  if(size < offset+num) {
-    lastDistance = size;
-  } else {
-    lastDistance = offset+num;
-  }
-  last = first;
-  std::advance(first, offset);
-  std::advance(last, lastDistance);
-  return std::make_pair(first, last);
+void TellWaitingXmlRpcMethod::createEntry
+(BDE& entryDict, const SharedHandle<RequestGroup>& item,
+ DownloadEngine* e) const
+{
+  entryDict[KEY_STATUS] = BDE_WAITING;
+  gatherProgress(entryDict, item, e);
 }
 
-BDE TellWaitingXmlRpcMethod::process
-(const XmlRpcRequest& req, DownloadEngine* e)
+const std::deque<SharedHandle<DownloadResult> >&
+TellStoppedXmlRpcMethod::getItems(DownloadEngine* e) const
 {
-  const std::deque<SharedHandle<RequestGroup> >& waitings =
-    e->_requestGroupMan->getReservedGroups();
-  std::pair<std::deque<SharedHandle<RequestGroup> >::const_iterator,
-    std::deque<SharedHandle<RequestGroup> >::const_iterator> range =
-    getPaginationRange(req, waitings.begin(), waitings.end());
-  BDE list = BDE::list();
-  for(; range.first != range.second; ++range.first) {
-    BDE entryDict = BDE::dict();
-    entryDict[KEY_STATUS] = BDE_WAITING;
-    gatherProgress(entryDict, *range.first, e);
-    list << entryDict;
-  }
-  return list;
+  return e->_requestGroupMan->getDownloadResults();
 }
 
-BDE TellStoppedXmlRpcMethod::process
-(const XmlRpcRequest& req, DownloadEngine* e)
+void TellStoppedXmlRpcMethod::createEntry
+(BDE& entryDict, const SharedHandle<DownloadResult>& item,
+ DownloadEngine* e) const
 {
-  const std::deque<SharedHandle<DownloadResult> >& stopped =
-    e->_requestGroupMan->getDownloadResults();
-  std::pair<std::deque<SharedHandle<DownloadResult> >::const_iterator,
-    std::deque<SharedHandle<DownloadResult> >::const_iterator> range =
-    getPaginationRange(req, stopped.begin(), stopped.end());
-  BDE list = BDE::list();
-  for(; range.first != range.second; ++range.first) {
-    BDE entryDict = BDE::dict();
-    gatherStoppedDownload(entryDict, *range.first);
-    list << entryDict;
-  }
-  return list;
+  gatherStoppedDownload(entryDict, item);
 }
 
 BDE PurgeDownloadResultXmlRpcMethod::process

+ 88 - 4
src/XmlRpcMethodImpl.h

@@ -37,6 +37,12 @@
 
 #include "XmlRpcMethod.h"
 
+#include <deque>
+#include <algorithm>
+
+#include "BDE.h"
+#include "XmlRpcRequest.h"
+
 namespace aria2 {
 
 class DownloadResult;
@@ -160,9 +166,81 @@ public:
   }
 };
 
-class TellWaitingXmlRpcMethod:public XmlRpcMethod {
+template<typename T>
+class AbstractPaginationXmlRpcMethod:public XmlRpcMethod {
+private:
+  template<typename InputIterator>
+  std::pair<InputIterator, InputIterator>
+  getPaginationRange
+  (ssize_t offset, size_t num, InputIterator first, InputIterator last)
+  {
+    size_t size = std::distance(first, last);
+    if(offset < 0) {
+      ssize_t tempoffset = offset+size;
+      if(tempoffset < 0) {
+        return std::make_pair(last, last);
+      }
+      offset = tempoffset-(num-1);
+      if(offset < 0) {
+        offset = 0;
+        num = tempoffset+1;
+      }
+    } else if(size <= (size_t)offset) {
+      return std::make_pair(last, last);
+    }
+    BDE list = BDE::list();
+    size_t lastDistance;
+    if(size < offset+num) {
+      lastDistance = size;
+    } else {
+      lastDistance = offset+num;
+    }
+    last = first;
+    std::advance(first, offset);
+    std::advance(last, lastDistance);
+    return std::make_pair(first, last);
+  }
+
+  void checkPaginationParams(const BDE& params) const;
 protected:
-  virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e);
+  virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e)
+  {
+    const BDE& params = req._params;
+    checkPaginationParams(params);
+    ssize_t offset = params[0].i();
+    size_t num = params[1].i();
+    const std::deque<SharedHandle<T> >& items = getItems(e);
+    std::pair<typename std::deque<SharedHandle<T> >::const_iterator,
+      typename std::deque<SharedHandle<T> >::const_iterator> range =
+      getPaginationRange(offset, num, items.begin(), items.end());
+    BDE list = BDE::list();
+    for(; range.first != range.second; ++range.first) {
+      BDE entryDict = BDE::dict();
+      createEntry(entryDict, *range.first, e);
+      list << entryDict;
+    }
+    if(offset < 0) {
+      std::reverse(list.listBegin(), list.listEnd());
+    }
+    return list;
+  }
+
+  virtual const std::deque<SharedHandle<T> >&
+  getItems(DownloadEngine* e) const = 0;
+
+  virtual void createEntry
+  (BDE& entryDict, const SharedHandle<T>& item, DownloadEngine* e) const = 0;
+};
+
+class TellWaitingXmlRpcMethod:
+    public AbstractPaginationXmlRpcMethod<RequestGroup> {
+protected:
+  virtual const std::deque<SharedHandle<RequestGroup> >&
+  getItems(DownloadEngine* e) const;
+
+  virtual void createEntry
+  (BDE& entryDict, const SharedHandle<RequestGroup>& item,
+   DownloadEngine* e) const;
 public:
   static const std::string& getMethodName()
   {
@@ -171,9 +249,15 @@ public:
   }
 };
 
-class TellStoppedXmlRpcMethod:public XmlRpcMethod {
+class TellStoppedXmlRpcMethod:
+    public AbstractPaginationXmlRpcMethod<DownloadResult> {
 protected:
-  virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e);
+   virtual const std::deque<SharedHandle<DownloadResult> >&
+   getItems(DownloadEngine* e) const;
+
+  virtual void createEntry
+  (BDE& entryDict, const SharedHandle<DownloadResult>& item,
+   DownloadEngine* e) const;
 public:
   static const std::string& getMethodName()
   {

+ 33 - 0
test/XmlRpcMethodTest.cc

@@ -608,6 +608,39 @@ void XmlRpcMethodTest::testTellWaiting()
 #else //!ENABLE_BITTORRENT
   CPPUNIT_ASSERT_EQUAL((size_t)2, res._param.size());
 #endif // !ENABLE_BITTORRENT
+  // negative offset
+  req = XmlRpcRequest(TellWaitingXmlRpcMethod::getMethodName(), BDE::list());
+  req._params << BDE((int64_t)-1);
+  req._params << BDE((int64_t)2);
+  res = m.execute(req, _e.get());
+  CPPUNIT_ASSERT_EQUAL(0, res._code);
+  CPPUNIT_ASSERT_EQUAL((size_t)2, res._param.size());
+#ifdef ENABLE_BITTORRENT
+  CPPUNIT_ASSERT_EQUAL(std::string("4"), res._param[0]["gid"].s());
+  CPPUNIT_ASSERT_EQUAL(std::string("3"), res._param[1]["gid"].s());
+#else // !ENABLE_BITTORRENT
+  CPPUNIT_ASSERT_EQUAL(std::string("3"), res._param[0]["gid"].s());
+  CPPUNIT_ASSERT_EQUAL(std::string("2"), res._param[1]["gid"].s());
+#endif // !ENABLE_BITTORRENT
+  // negative offset and size < num
+  req._params[1] = BDE((int64_t)100);
+  res = m.execute(req, _e.get());
+  CPPUNIT_ASSERT_EQUAL(0, res._code);
+#ifdef ENABLE_BITTORRENT
+  CPPUNIT_ASSERT_EQUAL((size_t)4, res._param.size());
+#else // !ENABLE_BITTORRENT
+  CPPUNIT_ASSERT_EQUAL((size_t)3, res._param.size());
+#endif // !ENABLE_BITTORRENT
+  // nagative offset and normalized offset < 0
+  req._params[0] = BDE((int64_t)-5);
+  res = m.execute(req, _e.get());
+  CPPUNIT_ASSERT_EQUAL(0, res._code);
+  CPPUNIT_ASSERT_EQUAL((size_t)0, res._param.size());
+  // nagative offset and normalized offset == 0
+  req._params[0] = BDE((int64_t)-4);
+  res = m.execute(req, _e.get());
+  CPPUNIT_ASSERT_EQUAL(0, res._code);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, res._param.size());
 }
 
 void XmlRpcMethodTest::testTellWaiting_fail()