util: make DummyClientFace public API

refs #2164

Change-Id: I4a21b70faab1fc1f5cde8430ef602f2425150df9
diff --git a/src/util/dummy-client-face.cpp b/src/util/dummy-client-face.cpp
new file mode 100644
index 0000000..a7ab505
--- /dev/null
+++ b/src/util/dummy-client-face.cpp
@@ -0,0 +1,185 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "dummy-client-face.hpp"
+#include "../transport/transport.hpp"
+#include "../management/nfd-controller.hpp"
+#include "../management/nfd-control-response.hpp"
+
+namespace ndn {
+namespace util {
+
+const DummyClientFace::Options DummyClientFace::DEFAULT_OPTIONS { true, false };
+
+class DummyClientFace::Transport : public ndn::Transport
+{
+public:
+  void
+  receive(const Block& block)
+  {
+    if (static_cast<bool>(m_receiveCallback))
+      m_receiveCallback(block);
+  }
+
+  virtual void
+  close()
+  {
+  }
+
+  virtual void
+  pause()
+  {
+  }
+
+  virtual void
+  resume()
+  {
+  }
+
+  virtual void
+  send(const Block& wire)
+  {
+    if (wire.type() == tlv::Interest) {
+      shared_ptr<Interest> interest = make_shared<Interest>(wire);
+      (*m_onInterest)(*interest);
+    }
+    else if (wire.type() == tlv::Data) {
+      shared_ptr<Data> data = make_shared<Data>(wire);
+      (*m_onData)(*data);
+    }
+  }
+
+  virtual void
+  send(const Block& header, const Block& payload)
+  {
+    this->send(payload);
+  }
+
+  boost::asio::io_service&
+  getIoService()
+  {
+    return *m_ioService;
+  }
+
+private:
+  friend class DummyClientFace;
+  EventEmitter<Interest>* m_onInterest;
+  EventEmitter<Data>* m_onData;
+};
+
+DummyClientFace::DummyClientFace(const Options& options, shared_ptr<Transport> transport)
+  : Face(transport)
+  , m_transport(transport)
+{
+  this->construct(options);
+}
+
+DummyClientFace::DummyClientFace(const Options& options, shared_ptr<Transport> transport,
+                                 boost::asio::io_service& ioService)
+  : Face(transport, ioService)
+  , m_transport(transport)
+{
+  this->construct(options);
+}
+
+void
+DummyClientFace::construct(const Options& options)
+{
+  m_transport->m_onInterest = &onInterest;
+  m_transport->m_onData     = &onData;
+
+  if (options.enablePacketLogging)
+    this->enablePacketLogging();
+
+  if (options.enableRegistrationReply)
+    this->enableRegistrationReply();
+}
+
+void
+DummyClientFace::enablePacketLogging()
+{
+  onInterest += [this] (const Interest& interest) { this->sentInterests.push_back(interest); };
+  onData     += [this] (const Data& data)         { this->sentDatas.push_back(data); };
+}
+
+void
+DummyClientFace::enableRegistrationReply()
+{
+  onInterest += [this] (const Interest& interest) {
+    static const Name localhostRegistration("/localhost/nfd/rib");
+    if (!localhostRegistration.isPrefixOf(interest.getName()))
+      return;
+
+    nfd::ControlParameters params(interest.getName().get(-5).blockFromValue());
+    params.setFaceId(1);
+    params.setOrigin(0);
+    if (interest.getName().get(3) == name::Component("register")) {
+      params.setCost(0);
+    }
+
+    nfd::ControlResponse resp;
+    resp.setCode(200);
+    resp.setBody(params.wireEncode());
+
+    shared_ptr<Data> data = make_shared<Data>(interest.getName());
+    data->setContent(resp.wireEncode());
+
+    KeyChain keyChain;
+    keyChain.signWithSha256(*data);
+
+    this->getIoService().post([this, data] { this->receive(*data); });
+  };
+}
+
+template<typename Packet>
+void
+DummyClientFace::receive(const Packet& packet)
+{
+  m_transport->receive(packet.wireEncode());
+}
+
+template void
+DummyClientFace::receive<Interest>(const Interest& packet);
+
+template void
+DummyClientFace::receive<Data>(const Data& packet);
+
+
+shared_ptr<DummyClientFace>
+makeDummyClientFace(const DummyClientFace::Options& options)
+{
+  // cannot use make_shared<DummyClientFace> before DummyClientFace constructor is private
+  return shared_ptr<DummyClientFace>(
+         new DummyClientFace(options, make_shared<DummyClientFace::Transport>()));
+}
+
+shared_ptr<DummyClientFace>
+makeDummyClientFace(boost::asio::io_service& ioService,
+                    const DummyClientFace::Options& options)
+{
+  // cannot use make_shared<DummyClientFace> before DummyClientFace constructor is private
+  return shared_ptr<DummyClientFace>(
+         new DummyClientFace(options, make_shared<DummyClientFace::Transport>(),
+                             ref(ioService)));
+}
+
+} // namespace util
+} // namespace ndn