/* */ #include "Metalink2RequestGroup.h" #include "RequestGroup.h" #include "Option.h" #include "LogFactory.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" #ifdef ENABLE_BITTORRENT # include "BtDependency.h" #endif // ENABLE_BITTORRENT Metalink2RequestGroup::Metalink2RequestGroup(const Option* option):_option(option), _logger(LogFactory::getInstance()) {} Metalink2RequestGroup::~Metalink2RequestGroup() {} class AccumulateNonP2PUrl { private: Strings& urlsPtr; public: AccumulateNonP2PUrl(Strings& urlsPtr) :urlsPtr(urlsPtr) {} void operator()(const MetalinkResourceHandle& 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 MetalinkResourceHandle& resource) { if(resource->type == MetalinkResource::TYPE_BITTORRENT) { return true; } else { return false; } } }; RequestGroups Metalink2RequestGroup::generate(const string& metalinkFile) { MetalinkEntries entries = MetalinkHelper::parseAndQuery(metalinkFile, _option); return createRequestGroup(entries); } RequestGroups Metalink2RequestGroup::generate(const BinaryStreamHandle& binaryStream) { MetalinkEntries entries = MetalinkHelper::parseAndQuery(binaryStream, _option); return createRequestGroup(entries); } RequestGroups Metalink2RequestGroup::createRequestGroup(MetalinkEntries entries) { if(entries.size() == 0) { _logger->notice(EX_NO_RESULT_WITH_YOUR_PREFS); return RequestGroups(); } Integers selectIndexes = Util::parseIntRange(_option->get(PREF_SELECT_FILE)).flush(); bool useIndex; if(selectIndexes.size()) { useIndex = true; } else { useIndex = false; } RequestGroups groups; int32_t count = 0; for(MetalinkEntries::iterator itr = entries.begin(); itr != entries.end(); itr++, ++count) { MetalinkEntryHandle& entry = *itr; if(_option->defined(PREF_METALINK_LOCATION)) { Strings 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(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()); MetalinkResources::iterator itr = find_if(entry->resources.begin(), entry->resources.end(), FindBitTorrentUrl()); #ifdef ENABLE_BITTORRENT RequestGroupHandle torrentRg = 0; // there is torrent entry if(itr != entry->resources.end()) { Strings uris; uris.push_back((*itr)->url); torrentRg = new RequestGroup(_option, uris); SingleFileDownloadContextHandle dctx = new SingleFileDownloadContext(_option->getAsInt(PREF_SEGMENT_SIZE), 0, ""); //dctx->setDir(_option->get(PREF_DIR)); torrentRg->setDownloadContext(dctx); torrentRg->clearPreDowloadHandler(); torrentRg->clearPostDowloadHandler(); // make it in-memory download PreDownloadHandlerHandle preh = new MemoryBufferPreDownloadHandler(); preh->setCriteria(new TrueRequestGroupCriteria()); torrentRg->addPreDownloadHandler(preh); groups.push_back(torrentRg); } #endif // ENABLE_BITTORRENT entry->reorderResourcesByPreference(); Strings uris; for_each(entry->resources.begin(), entry->resources.end(), AccumulateNonP2PUrl(uris)); RequestGroupHandle rg = new RequestGroup(_option, uris); // If piece hash is specified in the metalink, // make segment size equal to piece hash size. int32_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 SingleFileDownloadContextHandle dctx = new SingleFileDownloadContext(pieceLength, entry->getLength(), "", entry->file->getPath()); dctx->setDir(_option->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 rg->setDownloadContext(dctx); rg->setNumConcurrentCommand(entry->maxConnections < 0 ? _option->getAsInt(PREF_METALINK_SERVERS) : min(_option->getAsInt(PREF_METALINK_SERVERS), entry->maxConnections)); // In metalink, multi connection to a single host is not allowed by default. rg->setSingleHostMultiConnectionEnabled(!_option->getAsBool(PREF_METALINK_ENABLE_UNIQUE_PROTOCOL)); #ifdef ENABLE_BITTORRENT // Inject depenency between rg and torrentRg here if torrentRg.isNull() == false if(!torrentRg.isNull()) { rg->dependsOn(new BtDependency(rg, torrentRg, _option)); } #endif // ENABLE_BITTORRENT groups.push_back(rg); } return groups; }