blob: 92dedd334b61d7de8e8a58cb1e65f7c6cb547f9b [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California.
*
* This file is part of NDN repo-ng (Next generation of NDN repository).
* See AUTHORS.md for complete list of repo-ng authors and contributors.
*
* repo-ng is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* repo-ng 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* This file demonstrates how to generate data to be stored in repo with repo watch
* protocol and repo insert protocol.
* The details of the protocols can be find here
* <https://redmine.named-data.net/projects/repo-ng/wiki/Watched_Prefix_Insertion_Protocol>
* <https://redmine.named-data.net/projects/repo-ng/wiki/Basic_Repo_Insertion_Protocol>
*
* This file is used for debugging purpose. There are two modes for users to assign
* names for the data.
* 1)read the data name from a specific file
* 2)input a prefix and a random version number will be added automatically
* Users need to run nfd and repo-ng and set up specific repo protocols mentioned
* above before running this program.
* The description of command parameter can be found in the function usage().
*/
#include "../src/common.hpp"
#include <boost/asio/io_service.hpp>
#include <boost/lexical_cast.hpp>
#include <fstream>
#include <iostream>
#include <random>
#include <string>
namespace repo {
using ndn::time::milliseconds;
static const milliseconds DEFAULT_TIME_INTERVAL(2000);
enum Mode {
AUTO,
READFILE
};
class Publisher
{
public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
public:
Publisher()
: mode(AUTO)
, dataPrefix(Name("/example/data"))
, timeInterval(DEFAULT_TIME_INTERVAL)
, duration(0)
, m_scheduler(m_face.getIoService())
, m_randomEngine(std::random_device{}())
, m_randomDist(200, 1000)
, m_range([this] { return m_randomDist(m_randomEngine); })
{
}
void
run();
void
autoGenerate();
void
generateFromFile();
std::shared_ptr<ndn::Data>
createData(const ndn::Name& name);
public:
std::ifstream insertStream;
Mode mode;
Name dataPrefix;
milliseconds timeInterval;
milliseconds duration;
private:
ndn::Face m_face;
ndn::Scheduler m_scheduler;
std::mt19937 m_randomEngine;
std::uniform_int_distribution<unsigned int> m_randomDist;
std::function<unsigned int(void)> m_range;
};
void
Publisher::run()
{
if (mode == AUTO) {
m_scheduler.scheduleEvent(timeInterval,
bind(&Publisher::autoGenerate, this));
}
else {
m_scheduler.scheduleEvent(timeInterval,
bind(&Publisher::generateFromFile, this));
}
m_face.processEvents(duration);
}
void
Publisher::autoGenerate()
{
Name name = dataPrefix;
name.appendNumber(m_range());
std::shared_ptr<Data> data = createData(name);
// std::cout<<"data name = "<<data->getName()<<std::endl;
m_face.put(*data);
m_scheduler.scheduleEvent(timeInterval,
bind(&Publisher::autoGenerate, this));
}
void
Publisher::generateFromFile()
{
if (insertStream.eof()) {
m_face.getIoService().stop();
return;
}
std::string name;
getline(insertStream, name);
std::shared_ptr<Data> data = createData(Name(name));
m_face.put(*data);
m_scheduler.scheduleEvent(timeInterval,
bind(&Publisher::generateFromFile, this));
}
std::shared_ptr<Data>
Publisher::createData(const Name& name)
{
static ndn::KeyChain keyChain;
static std::vector<uint8_t> content(1500, '-');
std::shared_ptr<ndn::Data> data = std::make_shared<Data>();
data->setName(name);
data->setContent(&content[0], content.size());
keyChain.sign(*data);
return data;
}
static void
usage()
{
std::cerr
<< " Publisher [-d dataPrefix] [-f filename] [-s duration time] [-t generate time interval] \n"
<< " -d: specify the data prefix publisher generate\n"
<< " -f: specify filename that publish would read from\n"
<< " -s: specify the time duration of generate data\n"
<< " -t: specify the time interval between two data generated\n"
<< std::endl;
exit(1);
}
static int
main(int argc, char** argv)
{
Publisher generator;
bool isAuto = false;
bool isRead = false;
int opt;
while ((opt = getopt(argc, argv, "d:f:s:t:")) != -1) {
switch (opt) {
case 'd':
{
generator.dataPrefix = Name(std::string(optarg));
generator.mode = AUTO;
isAuto = true;
}
break;
case 'f':
{
isRead = true;
generator.mode = READFILE;
std::string str = std::string(optarg);
generator.insertStream.open(str.c_str());
if (!generator.insertStream.is_open()) {
std::cerr << "ERROR: cannot open " << std::string(optarg) << std::endl;
return 1;
}
}
break;
case 's':
try {
generator.duration = milliseconds(boost::lexical_cast<uint64_t>(optarg));
}
catch (const boost::bad_lexical_cast&) {
std::cerr << "-s option should be an integer.";
return 1;
}
break;
case 't':
try {
generator.timeInterval = milliseconds(boost::lexical_cast<uint64_t>(optarg));
}
catch (const boost::bad_lexical_cast&) {
std::cerr << "-t option should be an integer.";
return 1;
}
break;
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if (argc != 0)
usage();
if (isAuto && isRead)
usage();
generator.run();
return 0;
}
} // namespace repo
int
main(int argc, char** argv)
{
try {
return repo::main(argc, argv);
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
}