repo: data publisher

Change-Id: Ieda373e18ee11b4584ca223ee23cee4b7fcbde12
refs #1829
diff --git a/examples/data-producer.cpp b/examples/data-producer.cpp
new file mode 100644
index 0000000..73f731a
--- /dev/null
+++ b/examples/data-producer.cpp
@@ -0,0 +1,251 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  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
+ *  <http://redmine.named-data.net/projects/repo-ng/wiki/Watched_Prefix_Insertion_Protocol>
+ *  <http://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 <fstream>
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+#include <string>
+#include <boost/random.hpp>
+#include <iostream>
+
+namespace repo {
+
+using namespace ndn::time;
+
+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_randomGenerator(static_cast<unsigned int> (0))
+    , m_range(m_randomGenerator, boost::uniform_int<> (200,1000))
+  {
+  }
+
+  void
+  run();
+
+  void
+  autoGenerate();
+
+  void
+  generateFromFile();
+
+  ndn::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;
+  boost::mt19937 m_randomGenerator;
+  boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_range;
+};
+
+void
+Publisher::run()
+{
+
+  if (mode == AUTO) {
+    m_scheduler.scheduleEvent(timeInterval,
+                            ndn::bind(&Publisher::autoGenerate, this));
+  }
+  else {
+    m_scheduler.scheduleEvent(timeInterval,
+                              ndn::bind(&Publisher::generateFromFile, this));
+  }
+  m_face.processEvents(duration);
+}
+
+void
+Publisher::autoGenerate()
+{
+  Name name = dataPrefix;
+  name.appendNumber(m_range());
+  ndn::shared_ptr<Data> data = createData(name);
+  // std::cout<<"data name = "<<data->getName()<<std::endl;
+  m_face.put(*data);
+  m_scheduler.scheduleEvent(timeInterval,
+                            ndn::bind(&Publisher::autoGenerate, this));
+}
+
+void
+Publisher::generateFromFile()
+{
+  if (insertStream.eof()) {
+    m_face.getIoService().stop();
+    return;
+   }
+  std::string name;
+  getline(insertStream, name);
+  ndn::shared_ptr<Data> data = createData(Name(name));
+  m_face.put(*data);
+  m_scheduler.scheduleEvent(timeInterval,
+                            ndn::bind(&Publisher::generateFromFile, this));
+}
+
+ndn::shared_ptr<Data>
+Publisher::createData(const Name& name)
+{
+  static ndn::KeyChain keyChain;
+  static std::vector<uint8_t> content(1500, '-');
+
+  ndn::shared_ptr<ndn::Data> data = ndn::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);
+}
+
+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 (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 (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 (std::exception& e) {
+    std::cerr << "ERROR: " << e.what() << std::endl;
+    return 2;
+  }
+}
diff --git a/examples/wscript b/examples/wscript
new file mode 100644
index 0000000..03a1b93
--- /dev/null
+++ b/examples/wscript
@@ -0,0 +1,14 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+top = '..'
+
+def build(bld):
+    if bld.env['WITH_EXAMPLES']:
+        for app in bld.path.ant_glob('*.cpp'):
+            bld(features=['cxx', 'cxxprogram'],
+                target='%s' % (str(app.change_ext('', '.cpp'))),
+                source=app,
+                use='NDN_CXX',
+                includes="../src",
+                install_path=None,
+                )
diff --git a/wscript b/wscript
index ccd14d3..537a3e9 100644
--- a/wscript
+++ b/wscript
@@ -15,6 +15,8 @@
 
     ropt.add_option('--without-tools', action='store_false', default=True, dest='with_tools',
                     help='''Do not build tools''')
+    ropt.add_option('--with-examples', action='store_true', default=False, dest='with_examples',
+                    help='''Build examples''')
 
 def configure(conf):
     conf.load("compiler_c compiler_cxx gnu_dirs boost default-compiler-flags sqlite3")
@@ -28,6 +30,7 @@
         conf.env['WITH_TESTS'] = True
 
     conf.env['WITH_TOOLS'] = conf.options.with_tools
+    conf.env['WITH_EXAMPLES'] = conf.options.with_examples
 
     USED_BOOST_LIBS = ['system', 'iostreams', 'filesystem', 'random']
     if conf.env['WITH_TESTS']:
@@ -69,4 +72,6 @@
     # Tools
     bld.recurse('tools')
 
+    bld.recurse("examples")
+
     bld.install_files('${SYSCONFDIR}/ndn', 'repo-ng.conf.sample')