blob: 472cd7176063db4bf19cae2865ccbfb16938fbb9 [file] [log] [blame]
spirosmastorakis2f769c22016-03-12 11:46:04 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3* Copyright (c) 2016 Regents of the University of California.
4*
5* This file is part of the nTorrent codebase.
6*
7* nTorrent is free software: you can redistribute it and/or modify it under the
8* terms of the GNU Lesser General Public License as published by the Free Software
9* Foundation, either version 3 of the License, or (at your option) any later version.
10*
11* nTorrent is distributed in the hope that it will be useful, but WITHOUT ANY
12* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14*
15* You should have received copies of the GNU General Public License and GNU Lesser
16* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
17* <http://www.gnu.org/licenses/>.
18*
19* See AUTHORS for complete list of nTorrent authors and contributors.
20*/
21
22#include "sequential-data-fetcher.hpp"
Mickey Sweatt617d2d42016-04-25 22:02:08 -070023#include "util/logging.hpp"
spirosmastorakis2f769c22016-03-12 11:46:04 -080024#include "util/io-util.hpp"
25
26namespace ndn {
27namespace ntorrent {
28
Mickey Sweatt44e4fd92016-05-02 15:43:11 -070029SequentialDataFetcher::SequentialDataFetcher(const ndn::Name& torrentFileName,
30 const std::string& dataPath,
31 bool seed)
spirosmastorakis2f769c22016-03-12 11:46:04 -080032 : m_dataPath(dataPath)
33 , m_torrentFileName(torrentFileName)
Mickey Sweatt44e4fd92016-05-02 15:43:11 -070034 , m_seedFlag(seed)
spirosmastorakis2f769c22016-03-12 11:46:04 -080035{
Mickey Sweatt44e4fd92016-05-02 15:43:11 -070036 m_manager = make_shared<TorrentManager>(m_torrentFileName, m_dataPath, seed);
spirosmastorakis2f769c22016-03-12 11:46:04 -080037}
38
39SequentialDataFetcher::~SequentialDataFetcher()
40{
41}
42
43void
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070044SequentialDataFetcher::start(const time::milliseconds& timeout)
spirosmastorakis2f769c22016-03-12 11:46:04 -080045{
46 m_manager->Initialize();
47 // downloading logic
48 this->implementSequentialLogic();
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070049 m_manager->processEvents(timeout);
spirosmastorakis2f769c22016-03-12 11:46:04 -080050}
51
52void
53SequentialDataFetcher::pause()
54{
55 // TODO(Spyros): Implement asyncrhonous pause of the torrent downloading
56 // For now, do nothing...
57 throw(Error("Not implemented yet"));
58}
59
60void
61SequentialDataFetcher::resume()
62{
63 // TODO(Spyros): Implement asyncrhonous re-establishment of the torrent downloading
64 // For now, do nothing...
65 throw(Error("Not implemented yet"));
66}
67
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070068void
spirosmastorakis2f769c22016-03-12 11:46:04 -080069SequentialDataFetcher::downloadTorrentFile()
70{
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070071 auto torrentPath = ".appdata/" + m_torrentFileName.get(-3).toUri() + "/torrent_files/";
72 m_manager->downloadTorrentFile(torrentPath,
73 bind(&SequentialDataFetcher::onTorrentFileSegmentReceived, this, _1),
74 bind(&SequentialDataFetcher::onDataRetrievalFailure, this, _1, _2));
spirosmastorakis2f769c22016-03-12 11:46:04 -080075}
76
77void
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070078SequentialDataFetcher::downloadManifestFiles(const std::vector<ndn::Name>& manifestNames)
spirosmastorakis2f769c22016-03-12 11:46:04 -080079{
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070080 auto manifestPath = ".appdata/" + m_torrentFileName.get(-3).toUri() + "/manifests/";
81 for (auto i = manifestNames.begin(); i != manifestNames.end(); i++) {
spirosmastorakis2f769c22016-03-12 11:46:04 -080082 m_manager->download_file_manifest(*i,
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070083 manifestPath,
spirosmastorakis2f769c22016-03-12 11:46:04 -080084 bind(&SequentialDataFetcher::onManifestReceived, this, _1),
85 bind(&SequentialDataFetcher::onDataRetrievalFailure, this, _1, _2));
86 }
87}
88
89void
90SequentialDataFetcher::downloadPackets(const std::vector<ndn::Name>& packetsName)
91{
92 for (auto i = packetsName.begin(); i != packetsName.end(); i++) {
93 m_manager->download_data_packet(*i,
94 bind(&SequentialDataFetcher::onDataPacketReceived, this, _1),
95 bind(&SequentialDataFetcher::onDataRetrievalFailure, this, _1, _2));
96 }
97}
98
99void
100SequentialDataFetcher::implementSequentialLogic() {
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700101 // TODO(?) Fix seeding, and implement windowing:
102 /*
103 Alex says look at ndn-cxx:
104 * fetcher with queue (with window)
105 * segment fetcher ?
106 * catchunks (pipeline?)
107 */
108 if (!m_manager->hasAllTorrentSegments()) {
109 this->downloadTorrentFile();
spirosmastorakis2f769c22016-03-12 11:46:04 -0800110 }
111 else {
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700112 LOG_INFO << m_torrentFileName << " complete" << std::endl;
113 std::vector<ndn::Name> namesToFetch;
114 m_manager->findFileManifestsToDownload(namesToFetch);
115 if (!namesToFetch.empty()) {
116 this->downloadManifestFiles(namesToFetch);
117 }
118 else {
119 LOG_INFO << "All manifests complete" << std::endl;
120 m_manager->findAllMissingDataPackets(namesToFetch);
121 if (!namesToFetch.empty()) {
122 this->downloadPackets(namesToFetch);
123 }
124 else {
125 LOG_INFO << "All data complete" << std::endl;
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700126 if (!m_seedFlag) {
127 m_manager->shutdown();
128 }
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700129 }
130 }
spirosmastorakis2f769c22016-03-12 11:46:04 -0800131 }
132}
133
134void
135SequentialDataFetcher::onDataPacketReceived(const ndn::Data& data)
136{
137 // Data Packet Received
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700138 LOG_INFO << "Data Packet Received: " << data.getName();
spirosmastorakis2f769c22016-03-12 11:46:04 -0800139}
140
141void
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700142SequentialDataFetcher::onTorrentFileSegmentReceived(const std::vector<Name>& manifestNames)
143{
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700144 // TODO(msweatt) Add parameter for torrent file
145 LOG_INFO << "Torrent Segment Received: " << m_torrentFileName << std::endl;
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700146 this->downloadManifestFiles(manifestNames);
147}
148
149void
spirosmastorakis2f769c22016-03-12 11:46:04 -0800150SequentialDataFetcher::onManifestReceived(const std::vector<Name>& packetNames)
151{
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700152 LOG_INFO << "Manifest File Received: "
spirosmastorakis2f769c22016-03-12 11:46:04 -0800153 << packetNames[0].getSubName(0, packetNames[0].size()- 3) << std::endl;
154 this->downloadPackets(packetNames);
155}
156
157void
158SequentialDataFetcher::onDataRetrievalFailure(const ndn::Interest& interest,
159 const std::string& errorCode)
160{
spirosmastorakis2f769c22016-03-12 11:46:04 -0800161 // Data retrieval failure
162 uint32_t nameType = IoUtil::findType(interest.getName());
163 if (nameType == IoUtil::TORRENT_FILE) {
164 // this should never happen
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700165 LOG_ERROR << "Torrent File Segment Downloading Failed: " << interest.getName();
spirosmastorakis2f769c22016-03-12 11:46:04 -0800166 this->downloadTorrentFile();
167 }
168 else if (nameType == IoUtil::FILE_MANIFEST) {
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700169 LOG_ERROR << "Manifest File Segment Downloading Failed: " << interest.getName();
spirosmastorakis2f769c22016-03-12 11:46:04 -0800170 this->downloadManifestFiles({ interest.getName() });
171 }
172 else if (nameType == IoUtil::DATA_PACKET) {
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700173 LOG_ERROR << "Torrent File Segment Downloading Failed: " << interest.getName();
174 this->downloadTorrentFile();
175 }
176 else if (nameType == IoUtil::FILE_MANIFEST) {
177 LOG_ERROR << "Manifest File Segment Downloading Failed: " << interest.getName();
178 this->downloadManifestFiles({ interest.getName() });
179 }
180 else if (nameType == IoUtil::DATA_PACKET) {
181 LOG_ERROR << "Data Packet Downloading Failed: " << interest.getName();
spirosmastorakis2f769c22016-03-12 11:46:04 -0800182 this->downloadPackets({ interest.getName() });
183 }
184 else {
185 // This should never happen
Mickey Sweatt617d2d42016-04-25 22:02:08 -0700186 LOG_ERROR << "Unknown Packet Type Downloading Failed: " << interest.getName();
spirosmastorakis2f769c22016-03-12 11:46:04 -0800187 }
188}
189
190} // namespace ntorrent
191} // namespace ndn