blob: c564671d2763c1958f7a8e48486f53dcb06f2788 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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/>.
*/
/**
* @file This file demonstrates how to generate data to be stored in a repo using
* the repo watch protocol and repo insertion protocol.
*
* The details of the protocols can be found 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 <boost/asio/io_context.hpp>
#include <boost/lexical_cast.hpp>
#include <ndn-cxx/data.hpp>
#include <ndn-cxx/face.hpp>
#include <ndn-cxx/name.hpp>
#include <ndn-cxx/util/random.hpp>
#include <ndn-cxx/util/scheduler.hpp>
#include <ndn-cxx/util/time.hpp>
#include <fstream>
#include <iostream>
#include <random>
#include <string>
namespace repo::examples {
enum Mode {
AUTO,
READFILE
};
class Publisher
{
public:
class Error : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
};
public:
void
run();
void
autoGenerate();
void
generateFromFile();
static std::shared_ptr<ndn::Data>
createData(const ndn::Name& name);
public:
std::ifstream insertStream;
Mode mode{AUTO};
ndn::Name dataPrefix{"/example/data"};
ndn::time::milliseconds timeInterval{2000};
ndn::time::milliseconds duration{0};
private:
ndn::Face m_face;
ndn::Scheduler m_scheduler{m_face.getIoContext()};
std::uniform_int_distribution<> m_randomDist{200, 1000};
};
void
Publisher::run()
{
if (mode == AUTO) {
m_scheduler.schedule(timeInterval, [this] { autoGenerate(); });
}
else {
m_scheduler.schedule(timeInterval, [this] { generateFromFile(); });
}
m_face.processEvents(duration);
}
void
Publisher::autoGenerate()
{
ndn::Name name = dataPrefix;
name.appendNumber(m_randomDist(ndn::random::getRandomNumberEngine()));
auto data = createData(name);
m_face.put(*data);
m_scheduler.schedule(timeInterval, [this] { autoGenerate(); });
}
void
Publisher::generateFromFile()
{
if (insertStream.eof()) {
m_face.getIoContext().stop();
return;
}
std::string name;
getline(insertStream, name);
auto data = createData(name);
m_face.put(*data);
m_scheduler.schedule(timeInterval, [this] { generateFromFile(); });
}
std::shared_ptr<ndn::Data>
Publisher::createData(const ndn::Name& name)
{
static ndn::KeyChain keyChain;
static const std::vector<uint8_t> content(1500, '-');
auto data = std::make_shared<ndn::Data>(name);
data->setContent(content);
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 = ndn::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 = ndn::time::milliseconds(boost::lexical_cast<uint64_t>(optarg));
}
catch (const boost::bad_lexical_cast&) {
std::cerr << "-s option should be an integer" << std::endl;
return 1;
}
break;
case 't':
try {
generator.timeInterval = ndn::time::milliseconds(boost::lexical_cast<uint64_t>(optarg));
}
catch (const boost::bad_lexical_cast&) {
std::cerr << "-t option should be an integer" << std::endl;
return 1;
}
break;
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if (argc != 0)
usage();
if (isAuto && isRead)
usage();
generator.run();
return 0;
}
} // namespace repo::examples
int
main(int argc, char* argv[])
{
try {
return repo::examples::main(argc, argv);
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
}