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

Added --save-session=FILE option.  This option saves
	error/unfinished downloads to FILE on exit.  You can pass this
	output file to aria2c with -i option on restart. Please note that
	downloads added by aria2.addTorrent and aria2.addMetalink XML-RPC
	method are not saved.
	* src/BtPostDownloadHandler.cc
	* src/DownloadResult.h
	* src/Makefile.am
	* src/MetadataInfo.cc
	* src/MetadataInfo.h
	* src/Metalink2RequestGroup.cc
	* src/MetalinkPostDownloadHandler.cc
	* src/MultiUrlRequestInfo.cc
	* src/OptionHandlerFactory.cc
	* src/RequestGroup.cc
	* src/RequestGroup.h
	* src/SessionSerializer.cc
	* src/SessionSerializer.h
	* src/UTMetadataPostDownloadHandler.cc
	* src/download_helper.cc
	* src/download_helper.h
	* src/prefs.cc
	* src/prefs.h
	* src/usage_text.h
	* test/Makefile.am
	* test/SessionSerializerTest.cc
	* test/XmlRpcMethodTest.cc
	* test/serialize_session.meta4
pull/1/head
Tatsuhiro Tsujikawa 2010-04-08 12:54:14 +00:00
parent dd7590f927
commit 5cd0108f93
29 changed files with 707 additions and 35 deletions

View File

@ -1,3 +1,34 @@
2010-04-08 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added --save-session=FILE option. This option saves
error/unfinished downloads to FILE on exit. You can pass this
output file to aria2c with -i option on restart. Please note that
downloads added by aria2.addTorrent and aria2.addMetalink XML-RPC
method are not saved.
* src/BtPostDownloadHandler.cc
* src/DownloadResult.h
* src/Makefile.am
* src/MetadataInfo.cc
* src/MetadataInfo.h
* src/Metalink2RequestGroup.cc
* src/MetalinkPostDownloadHandler.cc
* src/MultiUrlRequestInfo.cc
* src/OptionHandlerFactory.cc
* src/RequestGroup.cc
* src/RequestGroup.h
* src/SessionSerializer.cc
* src/SessionSerializer.h
* src/UTMetadataPostDownloadHandler.cc
* src/download_helper.cc
* src/download_helper.h
* src/prefs.cc
* src/prefs.h
* src/usage_text.h
* test/Makefile.am
* test/SessionSerializerTest.cc
* test/XmlRpcMethodTest.cc
* test/serialize_session.meta4
2010-04-07 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Fixed the bug that FTP data connection is not established via

View File

@ -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/03/2010
.\" Date: 04/08/2010
.\" Manual: Aria2 Manual
.\" Source: Aria2 1.9.1a
.\" Language: English
.\"
.TH "ARIA2C" "1" "04/03/2010" "Aria2 1\&.9\&.1a" "Aria2 Manual"
.TH "ARIA2C" "1" "04/08/2010" "Aria2 1\&.9\&.1a" "Aria2 Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -1354,6 +1354,17 @@ For Metalink downloads, \-C1 is recommended for proxy server which disables resu
.sp .5v
.RE
.PP
\fB\-\-save\-session\fR=FILE
.RS 4
Save error/unfinished downloads to FILE on exit\&. You can pass this output file to aria2c with
\fB\-i\fR
option on restart\&. Please note that downloads added by
\fBaria2\&.addTorrent\fR
and
\fBaria2\&.addMetalink\fR
XML\-RPC method are not saved\&.
.RE
.PP
\fB\-\-stop\fR=SEC
.RS 4
Stop application after SEC seconds has passed\&. If

View File

@ -2201,6 +2201,17 @@ connections.</td>
</div>
<div class="dlist"><dl>
<dt class="hdlist1">
<strong>--save-session</strong>=FILE
</dt>
<dd>
<p>
Save error/unfinished downloads to FILE on exit. You can pass this
output file to aria2c with <strong>-i</strong> option on restart. Please note that
downloads added by <strong>aria2.addTorrent</strong> and <strong>aria2.addMetalink</strong>
XML-RPC method are not saved.
</p>
</dd>
<dt class="hdlist1">
<strong>--stop</strong>=SEC
</dt>
<dd>
@ -4137,7 +4148,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-03 13:10:23 JST
Last updated 2010-04-08 21:48:17 JST
</div>
</div>
</body>

View File

@ -914,6 +914,13 @@ For Metalink downloads, -C1 is recommended for proxy server which
disables resume, in order to avoid establishing unnecessary
connections.
*--save-session*=FILE::
Save error/unfinished downloads to FILE on exit. You can pass this
output file to aria2c with *-i* option on restart. Please note that
downloads added by *aria2.addTorrent* and *aria2.addMetalink*
XML-RPC method are not saved.
*--stop*=SEC::
Stop application after SEC seconds has passed.
If '0' is given, this feature is disabled.

View File

@ -82,6 +82,11 @@ void BtPostDownloadHandler::getNextRequestGroups
std::vector<std::string>(),
content);
requestGroup->followedBy(newRgs.begin(), newRgs.end());
SharedHandle<MetadataInfo> mi =
createMetadataInfoFromFirstFileEntry(requestGroup->getDownloadContext());
if(!mi.isNull()) {
setMetadataInfo(newRgs.begin(), newRgs.end(), mi);
}
groups.insert(groups.end(), newRgs.begin(), newRgs.end());
}

View File

@ -45,6 +45,8 @@
#include "SharedHandle.h"
#include "DownloadResultCode.h"
#include "RequestGroup.h"
#include "Option.h"
#include "MetadataInfo.h"
namespace aria2 {
@ -74,6 +76,10 @@ public:
// RequestGroup.cc::_belongsToGID.
gid_t belongsTo;
SharedHandle<Option> option;
SharedHandle<MetadataInfo> metadataInfo;
DownloadResult(gid_t gid,
const std::vector<SharedHandle<FileEntry> >& fileEntries,
bool inMemoryDownload,
@ -81,7 +87,9 @@ public:
int64_t sessionTime,
downloadresultcode::RESULT result,
const std::vector<gid_t> followedBy,
gid_t belongsTo):
gid_t belongsTo,
const SharedHandle<Option>& option,
const SharedHandle<MetadataInfo>& metadataInfo):
gid(gid),
fileEntries(fileEntries),
inMemoryDownload(inMemoryDownload),
@ -89,7 +97,9 @@ public:
sessionTime(sessionTime),
result(result),
followedBy(followedBy),
belongsTo(belongsTo) {}
belongsTo(belongsTo),
option(option),
metadataInfo(metadataInfo) {}
};
typedef SharedHandle<DownloadResult> DownloadResultHandle;

View File

@ -198,7 +198,9 @@ SRCS = Socket.h\
CreateRequestCommand.cc CreateRequestCommand.h\
DownloadResultCode.h\
wallclock.h\
download_helper.cc download_helper.h
download_helper.cc download_helper.h\
MetadataInfo.cc MetadataInfo.h\
SessionSerializer.cc SessionSerializer.h
if ENABLE_XML_RPC
SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\

View File

@ -429,7 +429,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
LongestSequencePieceSelector.cc LongestSequencePieceSelector.h \
bitfield.cc bitfield.h BDE.cc BDE.h CreateRequestCommand.cc \
CreateRequestCommand.h DownloadResultCode.h wallclock.h \
download_helper.cc download_helper.h \
download_helper.cc download_helper.h MetadataInfo.cc \
MetadataInfo.h SessionSerializer.cc SessionSerializer.h \
XmlRpcRequestParserController.cc \
XmlRpcRequestParserController.h \
XmlRpcRequestParserStateMachine.cc \
@ -855,7 +856,8 @@ am__objects_27 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
URIResult.$(OBJEXT) SelectEventPoll.$(OBJEXT) \
LongestSequencePieceSelector.$(OBJEXT) bitfield.$(OBJEXT) \
BDE.$(OBJEXT) CreateRequestCommand.$(OBJEXT) \
download_helper.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
download_helper.$(OBJEXT) MetadataInfo.$(OBJEXT) \
SessionSerializer.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
$(am__objects_3) $(am__objects_4) $(am__objects_5) \
$(am__objects_6) $(am__objects_7) $(am__objects_8) \
$(am__objects_9) $(am__objects_10) $(am__objects_11) \
@ -1189,16 +1191,17 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
LongestSequencePieceSelector.cc LongestSequencePieceSelector.h \
bitfield.cc bitfield.h BDE.cc BDE.h CreateRequestCommand.cc \
CreateRequestCommand.h DownloadResultCode.h wallclock.h \
download_helper.cc download_helper.h $(am__append_1) \
$(am__append_2) $(am__append_3) $(am__append_4) \
$(am__append_5) $(am__append_6) $(am__append_7) \
$(am__append_8) $(am__append_9) $(am__append_10) \
$(am__append_11) $(am__append_12) $(am__append_13) \
$(am__append_14) $(am__append_15) $(am__append_16) \
$(am__append_17) $(am__append_18) $(am__append_19) \
$(am__append_20) $(am__append_21) $(am__append_22) \
$(am__append_23) $(am__append_24) $(am__append_25) \
$(am__append_26)
download_helper.cc download_helper.h MetadataInfo.cc \
MetadataInfo.h SessionSerializer.cc SessionSerializer.h \
$(am__append_1) $(am__append_2) $(am__append_3) \
$(am__append_4) $(am__append_5) $(am__append_6) \
$(am__append_7) $(am__append_8) $(am__append_9) \
$(am__append_10) $(am__append_11) $(am__append_12) \
$(am__append_13) $(am__append_14) $(am__append_15) \
$(am__append_16) $(am__append_17) $(am__append_18) \
$(am__append_19) $(am__append_20) $(am__append_21) \
$(am__append_22) $(am__append_23) $(am__append_24) \
$(am__append_25) $(am__append_26)
noinst_LIBRARIES = libaria2c.a
libaria2c_a_SOURCES = $(SRCS)
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
@ -1495,6 +1498,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MSEHandshake.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemoryBufferPreDownloadHandler.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MessageDigestHelper.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetadataInfo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalink2RequestGroup.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkEntry.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkHelper.Po@am__quote@
@ -1552,6 +1556,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SelectEventPoll.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerStat.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerStatMan.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SessionSerializer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Signature.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleBtMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleLogger.Po@am__quote@

49
src/MetadataInfo.cc Normal file
View File

@ -0,0 +1,49 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "MetadataInfo.h"
namespace aria2 {
int64_t MetadataInfo::_count = 0;
int64_t MetadataInfo::genId()
{
if(_count == INT64_MAX) {
_count = 0;
}
return ++_count;
}
} // namespace aria2

76
src/MetadataInfo.h Normal file
View File

@ -0,0 +1,76 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef _D_METADATA_INFO_H_
#define _D_METADATA_INFO_H_
#include "common.h"
#include <string>
namespace aria2 {
class MetadataInfo {
private:
int64_t _id;
std::string _uri;
bool _dataOnly;
static int64_t _count;
public:
MetadataInfo(const std::string& uri):_id(genId()), _uri(uri), _dataOnly(false)
{}
MetadataInfo():_id(genId()), _dataOnly(true) {}
bool dataOnly() const
{
return _dataOnly;
}
const std::string& getUri() const
{
return _uri;
}
int64_t getId() const
{
return _id;
}
static int64_t genId();
};
} // namespace aria2
#endif // _D_METADATA_INFO_H_

View File

@ -109,7 +109,16 @@ Metalink2RequestGroup::generate
{
std::vector<SharedHandle<MetalinkEntry> > entries;
MetalinkHelper::parseAndQuery(entries, metalinkFile, option.get());
createRequestGroup(groups, entries, option);
std::vector<SharedHandle<RequestGroup> > tempgroups;
createRequestGroup(tempgroups, entries, option);
SharedHandle<MetadataInfo> mi;
if(metalinkFile == "-") {
mi.reset(new MetadataInfo());
} else {
mi.reset(new MetadataInfo(metalinkFile));
}
setMetadataInfo(tempgroups.begin(), tempgroups.end(), mi);
groups.insert(groups.end(), tempgroups.begin(), tempgroups.end());
}
void
@ -120,7 +129,11 @@ Metalink2RequestGroup::generate
{
std::vector<SharedHandle<MetalinkEntry> > entries;
MetalinkHelper::parseAndQuery(entries, binaryStream, option.get());
createRequestGroup(groups, entries, option);
std::vector<SharedHandle<RequestGroup> > tempgroups;
createRequestGroup(tempgroups, entries, option);
SharedHandle<MetadataInfo> mi(new MetadataInfo());
setMetadataInfo(tempgroups.begin(), tempgroups.end(), mi);
groups.insert(groups.end(), tempgroups.begin(), tempgroups.end());
}
void

View File

@ -44,6 +44,7 @@
#include "prefs.h"
#include "Option.h"
#include "DownloadContext.h"
#include "download_helper.h"
namespace aria2 {
@ -77,6 +78,11 @@ void MetalinkPostDownloadHandler::getNextRequestGroups
Metalink2RequestGroup().generate(newRgs, diskAdaptor,
requestGroup->getOption());
requestGroup->followedBy(newRgs.begin(), newRgs.end());
SharedHandle<MetadataInfo> mi =
createMetadataInfoFromFirstFileEntry(requestGroup->getDownloadContext());
if(!mi.isNull()) {
setMetadataInfo(newRgs.begin(), newRgs.end(), mi);
}
groups.insert(groups.end(), newRgs.begin(), newRgs.end());
diskAdaptor->closeFile();
} catch(Exception& e) {

View File

@ -55,6 +55,8 @@
#include "Netrc.h"
#include "AuthConfigFactory.h"
#include "DownloadContext.h"
#include "SessionSerializer.h"
#include "ServerStatMan.h"
#ifdef ENABLE_SSL
# include "SocketCore.h"
# include "TLSContext.h"
@ -193,6 +195,15 @@ downloadresultcode::RESULT MultiUrlRequestInfo::execute()
returnValue = s.getLastErrorResult();
}
}
SessionSerializer sessionSerializer(e->_requestGroupMan);
// TODO Add option: --save-session-status=error,inprogress,waiting
if(!_option->blank(PREF_SAVE_SESSION)) {
if(sessionSerializer.save(_option->get(PREF_SAVE_SESSION))) {
_logger->notice("Serialized session successfully.");
} else {
_logger->notice("Failed to serialize session.");
}
}
} catch(RecoverableException& e) {
if(returnValue == downloadresultcode::FINISHED) {
returnValue = downloadresultcode::UNKNOWN_ERROR;

View File

@ -442,6 +442,15 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
op->addTag(TAG_ADVANCED);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new DefaultOptionHandler
(PREF_SAVE_SESSION,
TEXT_SAVE_SESSION,
NO_DEFAULT_VALUE,
"FILENAME"));
op->addTag(TAG_ADVANCED);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new NumberOptionHandler
(PREF_STOP,

View File

@ -1050,7 +1050,9 @@ DownloadResultHandle RequestGroup::createDownloadResult() const
_downloadContext->calculateSessionTime(),
downloadResult(),
_followedByGIDs,
_belongsToGID));
_belongsToGID,
_option,
_metadataInfo));
}
void RequestGroup::reportDownloadFinished()

View File

@ -46,6 +46,7 @@
#include "TimeA2.h"
#include "Request.h"
#include "DownloadResultCode.h"
#include "MetadataInfo.h"
namespace aria2 {
@ -165,6 +166,8 @@ private:
// RequestGroup.
gid_t _belongsToGID;
SharedHandle<MetadataInfo> _metadataInfo;
RequestGroupMan* _requestGroupMan;
int _resumeFailureCount;
@ -514,6 +517,16 @@ public:
bool p2pInvolved() const;
void setMetadataInfo(const SharedHandle<MetadataInfo>& info)
{
_metadataInfo = info;
}
const SharedHandle<MetadataInfo>& getMetadataInfo() const
{
return _metadataInfo;
}
static void resetGIDCounter() { _gidCounter = 0; }
static gid_t newGID();

203
src/SessionSerializer.cc Normal file
View File

@ -0,0 +1,203 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "SessionSerializer.h"
#include <fstream>
#include <iterator>
#include "RequestGroupMan.h"
#include "ServerStatMan.h"
#include "a2functional.h"
#include "File.h"
#include "A2STR.h"
#include "download_helper.h"
#include "Option.h"
#include "DownloadResult.h"
#include "FileEntry.h"
#include "prefs.h"
#include "util.h"
#include "array_fun.h"
namespace aria2 {
SessionSerializer::SessionSerializer
(const SharedHandle<RequestGroupMan>& requestGroupMan):
_rgman(requestGroupMan),
_saveError(true),
_saveInProgress(true),
_saveWaiting(true) {}
bool SessionSerializer::save(const std::string& filename) const
{
std::string tempFilename = strconcat(filename, "__temp");
std::ofstream out(tempFilename.c_str(), std::ios::binary);
if(!out) {
return false;
}
save(out);
out.flush();
if(!out) {
return false;
}
return File(tempFilename).renameTo(filename);
}
static const std::vector<std::string>& getCumulativeOpts()
{
static std::string cumulativeOpts[] = { PREF_INDEX_OUT, PREF_HEADER };
static std::vector<std::string> opts
(vbegin(cumulativeOpts), vend(cumulativeOpts));
return opts;
}
static bool inCumulativeOpts(const std::string& opt)
{
const std::vector<std::string>& cumopts = getCumulativeOpts();
for(std::vector<std::string>::const_iterator itr = cumopts.begin(),
eoi = cumopts.end(); itr != eoi; ++itr) {
if(opt == *itr) {
return true;
}
}
return false;
}
static void writeOption(std::ostream& out, const SharedHandle<Option>& op)
{
const std::set<std::string>& requestOptions = listRequestOptions();
for(std::set<std::string>::const_iterator itr = requestOptions.begin(),
eoi = requestOptions.end(); itr != eoi; ++itr) {
if(inCumulativeOpts(*itr)) {
continue;
}
if(op->defined(*itr)) {
out << " " << *itr << "=" << op->get(*itr) << "\n";
}
}
const std::vector<std::string>& cumopts = getCumulativeOpts();
for(std::vector<std::string>::const_iterator opitr = cumopts.begin(),
eoi = cumopts.end(); opitr != eoi; ++opitr) {
if(op->defined(*opitr)) {
std::vector<std::string> v;
util::split(op->get(*opitr), std::back_inserter(v), "\n",
false, false);
for(std::vector<std::string>::const_iterator i = v.begin(), eoi = v.end();
i != eoi; ++i) {
out << " " << *opitr << "=" << *i << "\n";
}
}
}
}
static void writeDownloadResult
(std::ostream& out, std::set<int64_t>& metainfoCache,
const SharedHandle<DownloadResult>& dr)
{
const SharedHandle<MetadataInfo>& mi = dr->metadataInfo;
if(dr->belongsTo != 0 || (!mi.isNull() && mi->dataOnly())) {
return;
}
if(mi.isNull()) {
// only save first file entry
if(dr->fileEntries.empty()) {
return;
}
const SharedHandle<FileEntry>& file = dr->fileEntries[0];
std::vector<std::string> uris;
file->getUris(uris);
if(uris.empty()) {
return;
}
std::copy(uris.begin(), uris.end(),
std::ostream_iterator<std::string>(out, "\t"));
out << "\n";
} else {
if(metainfoCache.count(mi->getId()) != 0) {
return;
} else {
metainfoCache.insert(mi->getId());
out << mi->getUri() << "\n";
}
}
writeOption(out, dr->option);
}
void SessionSerializer::save(std::ostream& out) const
{
std::set<int64_t> metainfoCache;
const std::deque<SharedHandle<DownloadResult> >& results =
_rgman->getDownloadResults();
for(std::deque<SharedHandle<DownloadResult> >::const_iterator itr =
results.begin(), eoi = results.end(); itr != eoi; ++itr) {
if((*itr)->result == downloadresultcode::FINISHED) {
continue;
} else if((*itr)->result == downloadresultcode::IN_PROGRESS) {
if(_saveInProgress) {
writeDownloadResult(out, metainfoCache, *itr);
}
} else {
// error download
if(_saveError) {
writeDownloadResult(out, metainfoCache, *itr);
}
}
}
if(_saveInProgress) {
const std::deque<SharedHandle<RequestGroup> >& groups =
_rgman->getRequestGroups();
for(std::deque<SharedHandle<RequestGroup> >::const_iterator itr =
groups.begin(), eoi = groups.end(); itr != eoi; ++itr) {
SharedHandle<DownloadResult> result = (*itr)->createDownloadResult();
if(result->result == downloadresultcode::FINISHED) {
continue;
}
writeDownloadResult(out, metainfoCache, result);
}
}
if(_saveWaiting) {
const std::deque<SharedHandle<RequestGroup> >& groups =
_rgman->getReservedGroups();
for(std::deque<SharedHandle<RequestGroup> >::const_iterator itr =
groups.begin(), eoi = groups.end(); itr != eoi; ++itr) {
SharedHandle<DownloadResult> result = (*itr)->createDownloadResult();
writeDownloadResult(out, metainfoCache, result);
}
}
}
} // namespace aria2

65
src/SessionSerializer.h Normal file
View File

@ -0,0 +1,65 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef _D_SESSION_SERIALIZER_H_
#define _D_SESSION_SERIALIZER_H_
#include "common.h"
#include <string>
#include <iosfwd>
#include "SharedHandle.h"
namespace aria2 {
class RequestGroupMan;
class SessionSerializer {
private:
SharedHandle<RequestGroupMan> _rgman;
bool _saveError;
bool _saveInProgress;
bool _saveWaiting;
public:
SessionSerializer(const SharedHandle<RequestGroupMan>& requestGroupMan);
bool save(const std::string& filename) const;
void save(std::ostream& out) const;
};
} // namespace aria2
#endif // _D_SESSION_SERIALIZER_H_

View File

@ -96,8 +96,11 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups
std::vector<SharedHandle<RequestGroup> > newRgs;
createRequestGroupForBitTorrent(newRgs, requestGroup->getOption(),
std::vector<std::string>(), torrent);
requestGroup->followedBy(newRgs.begin(), newRgs.end());
if(!requestGroup->getMetadataInfo().isNull()) {
setMetadataInfo(newRgs.begin(), newRgs.end(),
requestGroup->getMetadataInfo());
}
groups.insert(groups.end(), newRgs.begin(), newRgs.end());
}
}

View File

@ -61,6 +61,7 @@
#include "ByteArrayDiskWriter.h"
#include "a2functional.h"
#include "ByteArrayDiskWriterFactory.h"
#include "MetadataInfo.h"
#ifdef ENABLE_BITTORRENT
# include "bittorrent_helper.h"
# include "BtConstants.h"
@ -212,6 +213,16 @@ static SharedHandle<RequestGroup> createRequestGroup
return rg;
}
static SharedHandle<MetadataInfo> createMetadataInfo(const std::string& uri)
{
return SharedHandle<MetadataInfo>(new MetadataInfo(uri));
}
static SharedHandle<MetadataInfo> createMetadataInfoDataOnly()
{
return SharedHandle<MetadataInfo>(new MetadataInfo());
}
#ifdef ENABLE_BITTORRENT
static
@ -226,10 +237,12 @@ createBtRequestGroup(const std::string& torrentFilePath,
dctx->setDir(option->get(PREF_DIR));
if(torrentData.empty()) {
bittorrent::load(torrentFilePath, dctx, auxUris);// may throw exception
rg->setMetadataInfo(createMetadataInfo(torrentFilePath));
} else {
bittorrent::loadFromMemory(torrentData, dctx, auxUris, "default"); // may
// throw
// exception
rg->setMetadataInfo(createMetadataInfoDataOnly());
}
dctx->setFileFilter(util::parseIntRange(option->get(PREF_SELECT_FILE)));
std::istringstream indexOutIn(option->get(PREF_INDEX_OUT));
@ -272,6 +285,7 @@ createBtMagnetRequestGroup(const std::string& magnetLink,
(new UTMetadataPostDownloadHandler()));
rg->setDiskWriterFactory
(SharedHandle<DiskWriterFactory>(new ByteArrayDiskWriterFactory()));
rg->setMetadataInfo(createMetadataInfo(magnetLink));
return rg;
}
@ -476,4 +490,19 @@ void createRequestGroupForUriList
}
}
SharedHandle<MetadataInfo>
createMetadataInfoFromFirstFileEntry(const SharedHandle<DownloadContext>& dctx)
{
if(dctx->getFileEntries().empty()) {
return SharedHandle<MetadataInfo>();
} else {
std::vector<std::string> uris;
dctx->getFileEntries()[0]->getUris(uris);
if(uris.empty()) {
return SharedHandle<MetadataInfo>();
}
return SharedHandle<MetadataInfo>(new MetadataInfo(uris[0]));
}
}
} // namespace aria2

View File

@ -47,6 +47,8 @@ namespace aria2 {
class RequestGroup;
class Option;
class MetadataInfo;
class DownloadContext;
const std::set<std::string>& listRequestOptions();
@ -90,6 +92,18 @@ void createRequestGroupForUri
bool ignoreForceSequential = false,
bool ignoreLocalPath = false);
template<typename InputIterator>
void setMetadataInfo
(InputIterator first, InputIterator last, const SharedHandle<MetadataInfo>& mi)
{
for(; first != last; ++first) {
(*first)->setMetadataInfo(mi);
}
}
SharedHandle<MetadataInfo>
createMetadataInfoFromFirstFileEntry(const SharedHandle<DownloadContext>& dctx);
} // namespace aria2
#endif // _D_DOWNLOAD_HELPER_H_

View File

@ -184,8 +184,8 @@ const std::string PREF_REMOVE_CONTROL_FILE("remove-control-file");
const std::string PREF_ALWAYS_RESUME("always-resume");
// value: 1*digit
const std::string PREF_MAX_RESUME_FAILURE_TRIES("max-resume-failure-tries");
// value: true | false
const std::string PREF_HTTP_ACCEPT_GZIP("http-accept-gzip");
// value: string that your file system recognizes as a file name.
const std::string PREF_SAVE_SESSION("save-session");
/**
* FTP related preferences
@ -234,6 +234,8 @@ const std::string PREF_USE_HEAD("use-head");
const std::string PREF_HTTP_AUTH_CHALLENGE("http-auth-challenge");
// value: true | false
const std::string PREF_HTTP_NO_CACHE("http-no-cache");
// value: true | false
const std::string PREF_HTTP_ACCEPT_GZIP("http-accept-gzip");
/**
* Proxy related preferences

View File

@ -188,8 +188,8 @@ extern const std::string PREF_REMOVE_CONTROL_FILE;
extern const std::string PREF_ALWAYS_RESUME;
// value: 1*digit
extern const std::string PREF_MAX_RESUME_FAILURE_TRIES;
// value: true | false
extern const std::string PREF_HTTP_ACCEPT_GZIP;
// value: string that your file system recognizes as a file name.
extern const std::string PREF_SAVE_SESSION;
/**
* FTP related preferences
@ -238,6 +238,8 @@ extern const std::string PREF_USE_HEAD;
extern const std::string PREF_HTTP_AUTH_CHALLENGE;
// value: true | false
extern const std::string PREF_HTTP_NO_CACHE;
// value: true | false
extern const std::string PREF_HTTP_ACCEPT_GZIP;
/**;
* Proxy related preferences

View File

@ -672,3 +672,9 @@
" and inflate response if remote server responds\n" \
" with 'Content-Encoding: gzip' or\n" \
" 'Content-Encoding: deflate'.")
#define TEXT_SAVE_SESSION \
_(" --save-session=FILE Save error/unfinished downloads to FILE on exit.\n" \
" You can pass this output file to aria2c with -i\n" \
" option on restart. Please note that downloads\n" \
" added by aria2.addTorrent and aria2.addMetalink\n" \
" XML-RPC method are not saved.")

View File

@ -71,7 +71,8 @@ aria2c_SOURCES = AllTest.cc\
a2algoTest.cc\
bitfieldTest.cc\
BDETest.cc\
DownloadContextTest.cc
DownloadContextTest.cc\
SessionSerializerTest.cc
if ENABLE_XML_RPC
aria2c_SOURCES += XmlRpcRequestParserControllerTest.cc\

View File

@ -213,7 +213,8 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
RarestPieceSelectorTest.cc PieceStatManTest.cc \
InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \
a2algoTest.cc bitfieldTest.cc BDETest.cc \
DownloadContextTest.cc XmlRpcRequestParserControllerTest.cc \
DownloadContextTest.cc SessionSerializerTest.cc \
XmlRpcRequestParserControllerTest.cc \
XmlRpcRequestProcessorTest.cc XmlRpcMethodTest.cc \
FallocFileAllocationIteratorTest.cc GZipDecoderTest.cc \
GZipEncoderTest.cc Sqlite3MozCookieParserTest.cc \
@ -406,9 +407,10 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \
RarestPieceSelectorTest.$(OBJEXT) PieceStatManTest.$(OBJEXT) \
LongestSequencePieceSelectorTest.$(OBJEXT) \
a2algoTest.$(OBJEXT) bitfieldTest.$(OBJEXT) BDETest.$(OBJEXT) \
DownloadContextTest.$(OBJEXT) $(am__objects_1) \
$(am__objects_2) $(am__objects_3) $(am__objects_4) \
$(am__objects_5) $(am__objects_6) $(am__objects_7)
DownloadContextTest.$(OBJEXT) SessionSerializerTest.$(OBJEXT) \
$(am__objects_1) $(am__objects_2) $(am__objects_3) \
$(am__objects_4) $(am__objects_5) $(am__objects_6) \
$(am__objects_7)
aria2c_OBJECTS = $(am_aria2c_OBJECTS)
am__DEPENDENCIES_1 =
aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
@ -639,9 +641,10 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \
RarestPieceSelectorTest.cc PieceStatManTest.cc \
InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \
a2algoTest.cc bitfieldTest.cc BDETest.cc \
DownloadContextTest.cc $(am__append_1) $(am__append_2) \
$(am__append_3) $(am__append_4) $(am__append_5) \
$(am__append_6) $(am__append_7)
DownloadContextTest.cc SessionSerializerTest.cc \
$(am__append_1) $(am__append_2) $(am__append_3) \
$(am__append_4) $(am__append_5) $(am__append_6) \
$(am__append_7)
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
@ -870,6 +873,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SequentialPickerTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerStatManTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerStatTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SessionSerializerTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShareRatioSeedCriteriaTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SharedHandleTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SignatureTest.Po@am__quote@

View File

@ -0,0 +1,71 @@
#include "SessionSerializer.h"
#include <iostream>
#include <sstream>
#include <cppunit/extensions/HelperMacros.h>
#include "RequestGroupMan.h"
#include "ServerStatMan.h"
#include "array_fun.h"
#include "download_helper.h"
#include "FileEntry.h"
#include "prefs.h"
namespace aria2 {
class SessionSerializerTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(SessionSerializerTest);
CPPUNIT_TEST(testSave);
CPPUNIT_TEST_SUITE_END();
public:
void testSave();
};
CPPUNIT_TEST_SUITE_REGISTRATION(SessionSerializerTest);
void SessionSerializerTest::testSave()
{
#if defined(ENABLE_BITTORRENT) && defined(ENABLE_METALINK)
const std::string URIs[] =
{ "http://localhost/file",
"http://mirror/file",
"test.torrent",
"serialize_session.meta4",
"magnet:?xt=urn:btih:248D0A1CD08284299DE78D5C1ED359BB46717D8C"};
std::vector<std::string> uris(vbegin(URIs), vend(URIs));
std::vector<SharedHandle<RequestGroup> > result;
SharedHandle<Option> option(new Option());
option->put(PREF_DIR, "/tmp");
createRequestGroupForUri(result, option, uris);
CPPUNIT_ASSERT_EQUAL((size_t)5, result.size());
SharedHandle<RequestGroupMan> rgman
(new RequestGroupMan(result, 1, option.get()));
SessionSerializer s(rgman);
std::stringstream ss;
s.save(ss);
std::string line;
std::getline(ss, line);
CPPUNIT_ASSERT_EQUAL(strconcat(uris[0], "\t", uris[1], "\t"), line);
std::getline(ss, line);
CPPUNIT_ASSERT_EQUAL(std::string(" dir=/tmp"), line);
std::getline(ss, line);
CPPUNIT_ASSERT_EQUAL(uris[2], line);
std::getline(ss, line);
CPPUNIT_ASSERT_EQUAL(std::string(" dir=/tmp"), line);
std::getline(ss, line);
CPPUNIT_ASSERT_EQUAL(uris[3], line);
std::getline(ss, line);
CPPUNIT_ASSERT_EQUAL(std::string(" dir=/tmp"), line);
std::getline(ss, line);
CPPUNIT_ASSERT_EQUAL(uris[4], line);
std::getline(ss, line);
CPPUNIT_ASSERT_EQUAL(std::string(" dir=/tmp"), line);
std::getline(ss, line);
CPPUNIT_ASSERT(!ss);
#endif // defined(ENABLE_BITTORRENT) && defined(ENABLE_METALINK)
}
} // namespace aria2

View File

@ -679,7 +679,9 @@ void XmlRpcMethodTest::testGatherStoppedDownload()
1000,
downloadresultcode::FINISHED,
followedBy,
2));
2,
SharedHandle<Option>(),
SharedHandle<MetadataInfo>()));
BDE entry = BDE::dict();
gatherStoppedDownload(entry, d);

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<metalink xmlns="urn:ietf:params:xml:ns:metalink">
<file name="t/README">
<url>http://example.org/README</url>
</file>
<file name="t/image.iso">
<url>http://example.org/image.iso</url>
</file>
</metalink>