blob: a82ff823de78d2d45d32e25bd4cd2f017d44455d [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>
Mickey Sweattec9188b2016-05-03 10:31:20 -070030#include <unordered_map>
Mickey Sweattf91ced42016-04-20 13:30:37 -070031
32#include <boost/program_options.hpp>
33#include <boost/program_options/errors.hpp>
Mickey Sweatt617d2d42016-04-25 22:02:08 -070034#include <boost/log/utility/setup/common_attributes.hpp>
Mickey Sweattf91ced42016-04-20 13:30:37 -070035
Mickey Sweatt617d2d42016-04-25 22:02:08 -070036namespace logging = boost::log;
Mickey Sweattf91ced42016-04-20 13:30:37 -070037namespace po = boost::program_options;
Mickey Sweatt617d2d42016-04-25 22:02:08 -070038
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070039using namespace ndn;
Mickey Sweattf91ced42016-04-20 13:30:37 -070040using namespace ndn::ntorrent;
41
42namespace ndn {
43
44class Error : public std::runtime_error
45{
46public:
47 explicit
48 Error(const std::string& what)
49 : runtime_error(what)
50 {
51 }
52};
53
spirosmastorakisd351c6b2016-05-06 17:02:48 -070054namespace ntorrent {
55
56const char * SharedConstants::commonPrefix = "/ndn";
57
58} // end ntorrent
Mickey Sweattf91ced42016-04-20 13:30:37 -070059} // end ndn
60
61// TODO(msweatt) Add options verification
62int main(int argc, char *argv[])
63{
64 try {
65 po::options_description desc("Allowed options");
66 desc.add_options()
67 // TODO(msweatt) Consider adding flagged args for other parameters
68 ("help,h", "produce help message")
69 ("generate,g" , "-g <data directory> <output-path>? <names-per-segment>? <names-per-manifest-segment>? <data-packet-size>?")
70 ("seed,s", "After download completes, continue to seed")
Mickey Sweatt15dde2d2016-04-28 23:42:45 -070071 ("dump,d", "-d <file> Dump the contents of the Data stored at the <file>.")
Mickey Sweattec9188b2016-05-03 10:31:20 -070072 ("log-level", po::value<std::string>(), "trace | debug | info | warming | error | fatal")
Mickey Sweattf91ced42016-04-20 13:30:37 -070073 ("args", po::value<std::vector<std::string> >(), "For arguments you want to specify without flags")
74 ;
75 po::positional_options_description p;
76 p.add("args", -1);
77
78 po::variables_map vm;
79 po::store(po::command_line_parser(argc, argv).
80 options(desc).allow_unregistered().positional(p).run(), vm);
81 po::notify(vm);
82
83 if (vm.count("help")) {
84 std::cout << desc << std::endl;
85 return 1;
86 }
Mickey Sweattec9188b2016-05-03 10:31:20 -070087 if (vm.count("log-level")) {
88 std::unordered_map<std::string, log::severity_level> supported_levels = {
89 {"trace" , log::severity_level::trace},
90 { "debug" , log::severity_level::debug},
91 { "info" , log::severity_level::info},
92 { "warning", log::severity_level::warning},
93 { "error" , log::severity_level::error},
94 { "fatal" , log::severity_level::fatal}
95 };
96 auto log_str = vm["log-level"].as<std::string>();
97 if (supported_levels.count(log_str)) {
98 LoggingUtil::severity_threshold = supported_levels[log_str];
99 }
100 else {
101 throw ndn::Error("Unsupported log level: " + log_str);
102 }
103 }
104 // setup log
105 LoggingUtil::init();
106 logging::add_common_attributes();
107
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700108 if (vm.count("args")) {
Mickey Sweattf91ced42016-04-20 13:30:37 -0700109 auto args = vm["args"].as<std::vector<std::string>>();
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700110 // if generate mode
111 if (vm.count("generate")) {
112 if (args.size() < 1 || args.size() > 5) {
113 throw ndn::Error("wrong number of arguments for generate");
114 }
115 auto dataPath = args[0];
116 auto outputPath = args.size() >= 2 ? args[1] : ".appdata/";
117 auto namesPerSegment = args.size() >= 3 ? boost::lexical_cast<size_t>(args[2]) : 1024;
118 auto namesPerManifest = args.size() >= 4 ? boost::lexical_cast<size_t>(args[3]) : 1024;
119 auto dataPacketSize = args.size() == 5 ? boost::lexical_cast<size_t>(args[4]) : 1024;
Mickey Sweattf91ced42016-04-20 13:30:37 -0700120
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700121 const auto& content = TorrentFile::generate(dataPath,
122 namesPerSegment,
123 namesPerManifest,
124 dataPacketSize);
125 const auto& torrentSegments = content.first;
126 std::vector<FileManifest> manifests;
127 for (const auto& ms : content.second) {
128 manifests.insert(manifests.end(), ms.first.begin(), ms.first.end());
129 }
130 auto torrentPrefix = fs::canonical(dataPath).filename().string();
Mickey Sweatt0dc0a1e2016-05-04 11:25:49 -0700131 outputPath += ("/" + torrentPrefix);
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700132 auto torrentPath = outputPath + "/torrent_files/";
133 // write all the torrent segments
134 for (const TorrentFile& t : torrentSegments) {
135 if (!IoUtil::writeTorrentSegment(t, torrentPath)) {
136 LOG_ERROR << "Write failed: " << t.getName() << std::endl;
137 return -1;
138 }
139 }
140 auto manifestPath = outputPath + "/manifests/";
141 for (const FileManifest& m : manifests) {
142 if (!IoUtil::writeFileManifest(m, manifestPath)) {
143 LOG_ERROR << "Write failed: " << m.getName() << std::endl;
144 return -1;
145 }
Mickey Sweattf91ced42016-04-20 13:30:37 -0700146 }
147 }
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700148 // if dump mode
149 else if(vm.count("dump")) {
150 if (args.size() != 1) {
151 throw ndn::Error("wrong number of arguments for dump");
152 }
153 auto filePath = args[0];
154 auto data = io::load<Data>(filePath);
155 if (nullptr != data) {
156 std::cout << data->getFullName() << std::endl;
157 }
158 else {
159 throw ndn::Error("Invalid data.");
Mickey Sweattf91ced42016-04-20 13:30:37 -0700160 }
161 }
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700162 // standard torrent mode
163 else {
164 // <torrent-file-name> <data-path>
165 if (args.size() != 2) {
166 throw ndn::Error("wrong number of arguments for torrent");
167 }
168 auto torrentName = args[0];
Mickey Sweatt44e4fd92016-05-02 15:43:11 -0700169 auto dataPath = args[1];
170 auto seedFlag = (vm.count("seed") != 0);
171 SequentialDataFetcher fetcher(torrentName, dataPath, seedFlag);
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700172 fetcher.start();
Mickey Sweattf91ced42016-04-20 13:30:37 -0700173 }
174 }
175 else {
176 std::cout << desc << std::endl;
177 return 1;
178 }
179 }
180 catch(std::exception& e) {
181 std::cerr << "error: " << e.what() << "\n";
182 return 1;
183 }
184 catch(...) {
185 std::cerr << "Exception of unknown type!\n";
186 }
187 return 0;
Mickey Sweatt15dde2d2016-04-28 23:42:45 -0700188}