blob: 2a0f69a02687c9c58d885405dd09dc57d27c43f8 [file] [log] [blame]
Mickey Sweattf91ced42016-04-20 13:30:37 -07001/* -*- 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.md for complete list of nTorrent authors and contributors.
20 */
Mickey Sweattf91ced42016-04-20 13:30:37 -070021#include "sequential-data-fetcher.hpp"
22#include "torrent-file.hpp"
23#include "util/io-util.hpp"
Mickey Sweatt617d2d42016-04-25 22:02:08 -070024#include "util/logging.hpp"
Mickey Sweattf91ced42016-04-20 13:30:37 -070025
26#include <iostream>
27#include <iterator>
28#include <stdexcept>
29#include <algorithm>
30
31#include <boost/program_options.hpp>
32#include <boost/program_options/errors.hpp>
Mickey Sweatt617d2d42016-04-25 22:02:08 -070033#include <boost/log/utility/setup/common_attributes.hpp>
Mickey Sweattf91ced42016-04-20 13:30:37 -070034
Mickey Sweatt617d2d42016-04-25 22:02:08 -070035namespace logging = boost::log;
Mickey Sweattf91ced42016-04-20 13:30:37 -070036namespace po = boost::program_options;
Mickey Sweatt617d2d42016-04-25 22:02:08 -070037
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070038using namespace ndn;
Mickey Sweattf91ced42016-04-20 13:30:37 -070039using namespace ndn::ntorrent;
40
41namespace ndn {
42
43class Error : public std::runtime_error
44{
45public:
46 explicit
47 Error(const std::string& what)
48 : runtime_error(what)
49 {
50 }
51};
52
spirosmastorakisd351c6b2016-05-06 17:02:48 -070053namespace ntorrent {
54
55const char * SharedConstants::commonPrefix = "/ndn";
56
57} // end ntorrent
Mickey Sweattf91ced42016-04-20 13:30:37 -070058} // end ndn
59
60// TODO(msweatt) Add options verification
61int main(int argc, char *argv[])
62{
63 try {
Mickey Sweatt617d2d42016-04-25 22:02:08 -070064 LoggingUtil::init();
65 logging::add_common_attributes();
66
Mickey Sweattf91ced42016-04-20 13:30:37 -070067 po::options_description desc("Allowed options");
68 desc.add_options()
69 // TODO(msweatt) Consider adding flagged args for other parameters
70 ("help,h", "produce help message")
71 ("generate,g" , "-g <data directory> <output-path>? <names-per-segment>? <names-per-manifest-segment>? <data-packet-size>?")
72 ("seed,s", "After download completes, continue to seed")
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070073 ("dump,d", "-d <file> Dump the contents of the Data stored at the <file>.")
Mickey Sweattf91ced42016-04-20 13:30:37 -070074 ("args", po::value<std::vector<std::string> >(), "For arguments you want to specify without flags")
75 ;
76 po::positional_options_description p;
77 p.add("args", -1);
78
79 po::variables_map vm;
80 po::store(po::command_line_parser(argc, argv).
81 options(desc).allow_unregistered().positional(p).run(), vm);
82 po::notify(vm);
83
84 if (vm.count("help")) {
85 std::cout << desc << std::endl;
86 return 1;
87 }
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070088 if (vm.count("args")) {
Mickey Sweattf91ced42016-04-20 13:30:37 -070089 auto args = vm["args"].as<std::vector<std::string>>();
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070090 // if generate mode
91 if (vm.count("generate")) {
92 if (args.size() < 1 || args.size() > 5) {
93 throw ndn::Error("wrong number of arguments for generate");
94 }
95 auto dataPath = args[0];
96 auto outputPath = args.size() >= 2 ? args[1] : ".appdata/";
97 auto namesPerSegment = args.size() >= 3 ? boost::lexical_cast<size_t>(args[2]) : 1024;
98 auto namesPerManifest = args.size() >= 4 ? boost::lexical_cast<size_t>(args[3]) : 1024;
99 auto dataPacketSize = args.size() == 5 ? boost::lexical_cast<size_t>(args[4]) : 1024;
Mickey Sweattf91ced42016-04-20 13:30:37 -0700100
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700101 const auto& content = TorrentFile::generate(dataPath,
102 namesPerSegment,
103 namesPerManifest,
104 dataPacketSize);
105 const auto& torrentSegments = content.first;
106 std::vector<FileManifest> manifests;
107 for (const auto& ms : content.second) {
108 manifests.insert(manifests.end(), ms.first.begin(), ms.first.end());
109 }
110 auto torrentPrefix = fs::canonical(dataPath).filename().string();
Mickey Sweatt0dc0a1e2016-05-04 11:25:49 -0700111 outputPath += ("/" + torrentPrefix);
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700112 auto torrentPath = outputPath + "/torrent_files/";
113 // write all the torrent segments
114 for (const TorrentFile& t : torrentSegments) {
115 if (!IoUtil::writeTorrentSegment(t, torrentPath)) {
116 LOG_ERROR << "Write failed: " << t.getName() << std::endl;
117 return -1;
118 }
119 }
120 auto manifestPath = outputPath + "/manifests/";
121 for (const FileManifest& m : manifests) {
122 if (!IoUtil::writeFileManifest(m, manifestPath)) {
123 LOG_ERROR << "Write failed: " << m.getName() << std::endl;
124 return -1;
125 }
Mickey Sweattf91ced42016-04-20 13:30:37 -0700126 }
127 }
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700128 // if dump mode
129 else if(vm.count("dump")) {
130 if (args.size() != 1) {
131 throw ndn::Error("wrong number of arguments for dump");
132 }
133 auto filePath = args[0];
134 auto data = io::load<Data>(filePath);
135 if (nullptr != data) {
136 std::cout << data->getFullName() << std::endl;
137 }
138 else {
139 throw ndn::Error("Invalid data.");
Mickey Sweattf91ced42016-04-20 13:30:37 -0700140 }
141 }
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700142 // standard torrent mode
143 else {
144 // <torrent-file-name> <data-path>
145 if (args.size() != 2) {
146 throw ndn::Error("wrong number of arguments for torrent");
147 }
148 auto torrentName = args[0];
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700149 auto dataPath = args[1];
150 auto seedFlag = (vm.count("seed") != 0);
151 SequentialDataFetcher fetcher(torrentName, dataPath, seedFlag);
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700152 fetcher.start();
Mickey Sweattf91ced42016-04-20 13:30:37 -0700153 }
154 }
155 else {
156 std::cout << desc << std::endl;
157 return 1;
158 }
159 }
160 catch(std::exception& e) {
161 std::cerr << "error: " << e.what() << "\n";
162 return 1;
163 }
164 catch(...) {
165 std::cerr << "Exception of unknown type!\n";
166 }
167 return 0;
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700168}