Ver código fonte

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 anos atrás
pai
commit
f9c6c0ccd8
7 arquivos alterados com 226 adições e 91 exclusões
  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>
 2010-01-17  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 
 	Added --human-readable option.  This option, when true is given,
 	Added --human-readable option.  This option, when true is given,

+ 15 - 3
doc/aria2c.1

@@ -2376,15 +2376,27 @@ seeder
 .sp
 .sp
 \fBaria2\&.tellActive\fR
 \fBaria2\&.tellActive\fR
 .sp
 .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
 .sp
 \fBaria2\&.tellWaiting\fR \fIoffset, num\fR
 \fBaria2\&.tellWaiting\fR \fIoffset, num\fR
 .sp
 .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
 .sp
 \fBaria2\&.tellStopped\fR \fIoffset, num\fR
 \fBaria2\&.tellStopped\fR \fIoffset, num\fR
 .sp
 .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
 .sp
 \fBaria2\&.changePosition\fR \fIgid, pos, how\fR
 \fBaria2\&.changePosition\fR \fIgid, pos, how\fR
 .sp
 .sp

+ 25 - 16
doc/aria2c.1.html

@@ -3031,25 +3031,34 @@ seeder
 </dd>
 </dd>
 </dl></div>
 </dl></div>
 <div class="paragraph"><p><strong>aria2.tellActive</strong></p></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
 type array and its element is the same struct returned by
 <strong>aria2.tellStatus</strong> method.</p></div>
 <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><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><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><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
 <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
 <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="footnotes"><hr /></div>
 <div id="footer">
 <div id="footer">
 <div id="footer-text">
 <div id="footer-text">
-Last updated 2010-01-17 16:21:53 JST
+Last updated 2010-01-17 18:47:03 JST
 </div>
 </div>
 </div>
 </div>
 </body>
 </body>

+ 30 - 15
doc/aria2c.1.txt

@@ -1352,29 +1352,44 @@ seeder::
 
 
 *aria2.tellActive*
 *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
 type array and its element is the same struct returned by
 *aria2.tellStatus* method.
 *aria2.tellStatus* method.
 
 
 *aria2.tellWaiting* 'offset, num'
 *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'
 *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'
 *aria2.changePosition* 'gid, pos, how'
 
 

+ 23 - 53
src/XmlRpcMethodImpl.cc

@@ -586,73 +586,43 @@ BDE TellActiveXmlRpcMethod::process
   return list;
   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());
   assert(params.isList());
-
   if(params.size() != 2 ||
   if(params.size() != 2 ||
      !params[0].isInteger() || !params[1].isInteger() ||
      !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.");
     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
 BDE PurgeDownloadResultXmlRpcMethod::process

+ 88 - 4
src/XmlRpcMethodImpl.h

@@ -37,6 +37,12 @@
 
 
 #include "XmlRpcMethod.h"
 #include "XmlRpcMethod.h"
 
 
+#include <deque>
+#include <algorithm>
+
+#include "BDE.h"
+#include "XmlRpcRequest.h"
+
 namespace aria2 {
 namespace aria2 {
 
 
 class DownloadResult;
 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:
 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:
 public:
   static const std::string& getMethodName()
   static const std::string& getMethodName()
   {
   {
@@ -171,9 +249,15 @@ public:
   }
   }
 };
 };
 
 
-class TellStoppedXmlRpcMethod:public XmlRpcMethod {
+class TellStoppedXmlRpcMethod:
+    public AbstractPaginationXmlRpcMethod<DownloadResult> {
 protected:
 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:
 public:
   static const std::string& getMethodName()
   static const std::string& getMethodName()
   {
   {

+ 33 - 0
test/XmlRpcMethodTest.cc

@@ -608,6 +608,39 @@ void XmlRpcMethodTest::testTellWaiting()
 #else //!ENABLE_BITTORRENT
 #else //!ENABLE_BITTORRENT
   CPPUNIT_ASSERT_EQUAL((size_t)2, res._param.size());
   CPPUNIT_ASSERT_EQUAL((size_t)2, res._param.size());
 #endif // !ENABLE_BITTORRENT
 #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()
 void XmlRpcMethodTest::testTellWaiting_fail()