/* */ #include "Metalink2RequestGroup.h" #include "RequestGroup.h" #include "Option.h" #include "LogFactory.h" #include "Logger.h" #include "prefs.h" #include "Util.h" #include "message.h" #include "SingleFileDownloadContext.h" #include "MetalinkHelper.h" #include "BinaryStream.h" #include "MemoryBufferPreDownloadHandler.h" #include "TrueRequestGroupCriteria.h" #include "MetalinkEntry.h" #include "MetalinkResource.h" #include "FileEntry.h" #include "A2STR.h" #ifdef ENABLE_BITTORRENT # include "BtDependency.h" #endif // ENABLE_BITTORRENT #ifdef ENABLE_MESSAGE_DIGEST # include "Checksum.h" # include "ChunkChecksum.h" #endif // ENABLE_MESSAGE_DIGEST #include namespace aria2 { Metalink2RequestGroup::Metalink2RequestGroup(const Option* option): _option(option), _logger(LogFactory::getInstance()) {} Metalink2RequestGroup::~Metalink2RequestGroup() {} class AccumulateNonP2PUrl { private: std::deque& urlsPtr; public: AccumulateNonP2PUrl(std::deque& urlsPtr) :urlsPtr(urlsPtr) {} void operator()(const SharedHandle& resource) { switch(resource->type) { case MetalinkResource::TYPE_HTTP: case MetalinkResource::TYPE_HTTPS: case MetalinkResource::TYPE_FTP: urlsPtr.push_back(resource->url); break; default: break; } } }; class FindBitTorrentUrl { public: FindBitTorrentUrl() {} bool operator()(const SharedHandle& resource) { if(resource->type == MetalinkResource::TYPE_BITTORRENT) { return true; } else { return false; } } }; void Metalink2RequestGroup::generate(std::deque >& groups, const std::string& metalinkFile, const Option& requestOption) { std::deque > entries; MetalinkHelper::parseAndQuery(entries, metalinkFile, _option); createRequestGroup(groups, entries, requestOption); } void Metalink2RequestGroup::generate(std::deque >& groups, const SharedHandle& binaryStream, const Option& requestOption) { std::deque > entries; MetalinkHelper::parseAndQuery(entries, binaryStream, _option); createRequestGroup(groups, entries, requestOption); } void Metalink2RequestGroup::createRequestGroup (std::deque >& groups, std::deque > entries, const Option& requestOption) { if(entries.size() == 0) { _logger->notice(EX_NO_RESULT_WITH_YOUR_PREFS); return; } std::deque selectIndexes = Util::parseIntRange(_option->get(PREF_SELECT_FILE)).flush(); bool useIndex; if(selectIndexes.size()) { useIndex = true; } else { useIndex = false; } int32_t count = 0; for(std::deque >::iterator itr = entries.begin(); itr != entries.end(); itr++, ++count) { SharedHandle& entry = *itr; if(_option->defined(PREF_METALINK_LOCATION)) { std::deque locations; Util::slice(locations, _option->get(PREF_METALINK_LOCATION), ',', true); entry->setLocationPreference(locations, 100); } if(_option->get(PREF_METALINK_PREFERRED_PROTOCOL) != V_NONE) { entry->setProtocolPreference(_option->get(PREF_METALINK_PREFERRED_PROTOCOL), 100); } if(useIndex) { if(std::find(selectIndexes.begin(), selectIndexes.end(), count+1) == selectIndexes.end()) { continue; } } entry->dropUnsupportedResource(); if(entry->resources.size() == 0) { continue; } _logger->info(MSG_METALINK_QUEUEING, entry->getPath().c_str()); std::deque >::iterator itr = std::find_if(entry->resources.begin(), entry->resources.end(), FindBitTorrentUrl()); #ifdef ENABLE_BITTORRENT SharedHandle torrentRg; // there is torrent entry if(itr != entry->resources.end()) { std::deque uris; uris.push_back((*itr)->url); torrentRg.reset(new RequestGroup(_option, uris)); SharedHandle dctx (new SingleFileDownloadContext(_option->getAsInt(PREF_SEGMENT_SIZE), 0, A2STR::NIL)); //dctx->setDir(_option->get(PREF_DIR)); torrentRg->setDownloadContext(dctx); torrentRg->clearPreDowloadHandler(); torrentRg->clearPostDowloadHandler(); // remove "metalink" from Accept Type list to avoid loop in tranparent // metalink torrentRg->removeAcceptType(RequestGroup::ACCEPT_METALINK); // make it in-memory download SharedHandle preh(new MemoryBufferPreDownloadHandler()); { SharedHandle cri(new TrueRequestGroupCriteria()); preh->setCriteria(cri); } torrentRg->addPreDownloadHandler(preh); groups.push_back(torrentRg); } #endif // ENABLE_BITTORRENT entry->reorderResourcesByPreference(); std::deque uris; std::for_each(entry->resources.begin(), entry->resources.end(), AccumulateNonP2PUrl(uris)); SharedHandle rg(new RequestGroup(_option, uris)); // If piece hash is specified in the metalink, // make segment size equal to piece hash size. size_t pieceLength; #ifdef ENABLE_MESSAGE_DIGEST if(entry->chunkChecksum.isNull()) { pieceLength = _option->getAsInt(PREF_SEGMENT_SIZE); } else { pieceLength = entry->chunkChecksum->getChecksumLength(); } #else pieceLength = _option->getAsInt(PREF_SEGMENT_SIZE); #endif // ENABLE_MESSAGE_DIGEST SharedHandle dctx (new SingleFileDownloadContext(pieceLength, entry->getLength(), A2STR::NIL, requestOption.get(PREF_DIR)+"/"+ entry->file->getPath())); dctx->setDir(requestOption.get(PREF_DIR)); #ifdef ENABLE_MESSAGE_DIGEST if(entry->chunkChecksum.isNull()) { if(!entry->checksum.isNull()) { dctx->setChecksum(entry->checksum->getMessageDigest()); dctx->setChecksumHashAlgo(entry->checksum->getAlgo()); } } else { dctx->setPieceHashes(entry->chunkChecksum->getChecksums()); dctx->setPieceHashAlgo(entry->chunkChecksum->getAlgo()); } #endif // ENABLE_MESSAGE_DIGEST dctx->setSignature(entry->getSignature()); rg->setDownloadContext(dctx); rg->setNumConcurrentCommand (entry->maxConnections < 0 ? _option->getAsInt(PREF_METALINK_SERVERS) : std::min(_option->getAsInt(PREF_METALINK_SERVERS), static_cast(entry->maxConnections))); // In metalink, multi connection to a single host is not allowed by default. rg->setSingleHostMultiConnectionEnabled(!_option->getAsBool(PREF_METALINK_ENABLE_UNIQUE_PROTOCOL)); // remove "metalink" from Accept Type list to avoid loop in tranparent // metalink rg->removeAcceptType(RequestGroup::ACCEPT_METALINK); #ifdef ENABLE_BITTORRENT // Inject depenency between rg and torrentRg here if torrentRg.isNull() == false if(!torrentRg.isNull()) { SharedHandle dep(new BtDependency(rg, torrentRg, _option)); rg->dependsOn(dep); } #endif // ENABLE_BITTORRENT groups.push_back(rg); } } } // namespace aria2