blob: b99438488708acfb29bbb4d792f4fdc3a35b5464 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016 Regents of the University of California.
*
* This file is part of the nTorrent codebase.
*
* nTorrent is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* nTorrent 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 Lesser General Public License for more details.
*
* You should have received copies of the GNU General Public License and GNU Lesser
* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
* <http://www.gnu.org/licenses/>.
*
* See AUTHORS for complete list of nTorrent authors and contributors.
*/
#include "sequential-data-fetcher.hpp"
#include "util/logging.hpp"
#include "util/io-util.hpp"
namespace ndn {
namespace ntorrent {
SequentialDataFetcher::SequentialDataFetcher(const ndn::Name& torrentFileName,
const std::string& dataPath)
: m_dataPath(dataPath)
, m_torrentFileName(torrentFileName)
{
m_manager = make_shared<TorrentManager>(m_torrentFileName, m_dataPath);
}
SequentialDataFetcher::~SequentialDataFetcher()
{
}
void
SequentialDataFetcher::start()
{
m_manager->Initialize();
// downloading logic
this->implementSequentialLogic();
}
void
SequentialDataFetcher::pause()
{
// TODO(Spyros): Implement asyncrhonous pause of the torrent downloading
// For now, do nothing...
throw(Error("Not implemented yet"));
}
void
SequentialDataFetcher::resume()
{
// TODO(Spyros): Implement asyncrhonous re-establishment of the torrent downloading
// For now, do nothing...
throw(Error("Not implemented yet"));
}
std::vector<ndn::Name>
SequentialDataFetcher::downloadTorrentFile()
{
std::vector<ndn::Name> returnedNames;
returnedNames = m_manager->downloadTorrentFile(".appdata/torrent_files/");
if (!returnedNames.empty() && IoUtil::NAME_TYPE::FILE_MANIFEST == IoUtil::findType(returnedNames[0])) {
LOG_INFO << "Torrent File Received: "
<< m_torrentFileName.getSubName(0, m_torrentFileName.size() - 1) << std::endl;
}
return returnedNames;
}
void
SequentialDataFetcher::downloadManifestFiles(const std::vector<ndn::Name>& manifestsName)
{
std::vector<ndn::Name> packetsName;
for (auto i = manifestsName.begin(); i != manifestsName.end(); i++) {
m_manager->download_file_manifest(*i,
".appdata/manifests/",
bind(&SequentialDataFetcher::onManifestReceived, this, _1),
bind(&SequentialDataFetcher::onDataRetrievalFailure, this, _1, _2));
m_manager->processEvents();
}
}
void
SequentialDataFetcher::downloadPackets(const std::vector<ndn::Name>& packetsName)
{
for (auto i = packetsName.begin(); i != packetsName.end(); i++) {
m_manager->download_data_packet(*i,
bind(&SequentialDataFetcher::onDataPacketReceived, this, _1),
bind(&SequentialDataFetcher::onDataRetrievalFailure, this, _1, _2));
}
m_manager->processEvents();
}
void
SequentialDataFetcher::implementSequentialLogic() {
std::vector<ndn::Name> returnedNames;
returnedNames = this->downloadTorrentFile();
if (returnedNames.empty()) {
// we have downloaded the entire torrent (including manifests, data packets, etc..)
return;
}
// check the first returned name whether it is the name of a file manifest or a data packet
const Name& nameToCheck = returnedNames[0];
if (IoUtil::findType(nameToCheck) == IoUtil::DATA_PACKET) {
// In this case, the returned names correspond to data packets
this->downloadPackets(returnedNames);
}
else {
// In this case, the returned names correspond to file manifests
this->downloadManifestFiles(returnedNames);
}
}
void
SequentialDataFetcher::onDataPacketReceived(const ndn::Data& data)
{
// Data Packet Received
LOG_INFO << "Data Packet Received: " << data.getName();
}
void
SequentialDataFetcher::onManifestReceived(const std::vector<Name>& packetNames)
{
LOG_INFO << "Manifest File Received: "
<< packetNames[0].getSubName(0, packetNames[0].size()- 3) << std::endl;
this->downloadPackets(packetNames);
}
void
SequentialDataFetcher::onDataRetrievalFailure(const ndn::Interest& interest,
const std::string& errorCode)
{
// Data retrieval failure
uint32_t nameType = IoUtil::findType(interest.getName());
if (nameType == IoUtil::TORRENT_FILE) {
// this should never happen
LOG_ERROR << "Torrent File Segment Downloading Failed: " << interest.getName();
this->downloadTorrentFile();
}
else if (nameType == IoUtil::FILE_MANIFEST) {
LOG_ERROR << "Manifest File Segment Downloading Failed: " << interest.getName();
this->downloadManifestFiles({ interest.getName() });
}
else if (nameType == IoUtil::DATA_PACKET) {
LOG_ERROR << "Torrent File Segment Downloading Failed: " << interest.getName();
this->downloadTorrentFile();
}
else if (nameType == IoUtil::FILE_MANIFEST) {
LOG_ERROR << "Manifest File Segment Downloading Failed: " << interest.getName();
this->downloadManifestFiles({ interest.getName() });
}
else if (nameType == IoUtil::DATA_PACKET) {
LOG_ERROR << "Data Packet Downloading Failed: " << interest.getName();
this->downloadPackets({ interest.getName() });
}
else {
// This should never happen
LOG_ERROR << "Unknown Packet Type Downloading Failed: " << interest.getName();
}
}
} // namespace ntorrent
} // namespace ndn