update: Refactor to use ndn-cxx dispatcher for prefix update/readvertise

refs: #3728

Change-Id: I3186433ed460850753f033a1d03fe27fd1fe889c
diff --git a/src/update/prefix-update-processor.cpp b/src/update/prefix-update-processor.cpp
index ad1f9a6..6146441 100644
--- a/src/update/prefix-update-processor.cpp
+++ b/src/update/prefix-update-processor.cpp
@@ -20,60 +20,84 @@
  **/
 
 #include "prefix-update-processor.hpp"
-
 #include "lsdb.hpp"
 #include "nlsr.hpp"
-#include "prefix-update-commands.hpp"
-
 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
+#include <ndn-cxx/tag.hpp>
+#include <ndn-cxx/util/io.hpp>
 
 namespace nlsr {
 namespace update {
 
 INIT_LOGGER("PrefixUpdateProcessor");
 
-const ndn::Name::Component PrefixUpdateProcessor::MODULE_COMPONENT = ndn::Name::Component("prefix-update");
-const ndn::Name::Component PrefixUpdateProcessor::ADVERTISE_VERB = ndn::Name::Component("advertise");
-const ndn::Name::Component PrefixUpdateProcessor::WITHDRAW_VERB  = ndn::Name::Component("withdraw");
+/** \brief an Interest tag to indicate command signer
+ */
+using SignerTag = ndn::SimpleTag<ndn::Name, 20>;
 
-PrefixUpdateProcessor::PrefixUpdateProcessor(ndn::Face& face,
+/** \brief obtain signer from SignerTag attached to Interest, if available
+ */
+static ndn::optional<std::string>
+getSignerFromTag(const ndn::Interest& interest)
+{
+  shared_ptr<SignerTag> signerTag = interest.getTag<SignerTag>();
+  if (signerTag == nullptr) {
+    return ndn::nullopt;
+  }
+  else {
+    return signerTag->get().toUri();
+  }
+}
+
+PrefixUpdateProcessor::PrefixUpdateProcessor(ndn::mgmt::Dispatcher& dispatcher,
+                                             ndn::Face& face,
                                              NamePrefixList& namePrefixList,
                                              Lsdb& lsdb,
                                              const ndn::Name broadcastPrefix,
                                              ndn::KeyChain& keyChain,
                                              std::shared_ptr<ndn::CertificateCacheTtl> certificateCache,
                                              security::CertificateStore& certStore)
-  : m_face(face)
-  , m_namePrefixList(namePrefixList)
-  , m_lsdb(lsdb)
-  , m_keyChain(keyChain)
-  , m_validator(m_face, broadcastPrefix, certificateCache, certStore)
-  , m_isEnabled(false)
-  , COMMAND_PREFIX(ndn::Name(Nlsr::LOCALHOST_PREFIX).append(MODULE_COMPONENT))
+  : CommandManagerBase(dispatcher, namePrefixList, lsdb, "prefix-update")
+  , m_validator(face, broadcastPrefix, certificateCache, certStore)
 {
+  _LOG_DEBUG("Setting dispatcher to capture Interests for: "
+    << ndn::Name(Nlsr::LOCALHOST_PREFIX).append("prefix-update"));
+
+  m_dispatcher.addControlCommand<ndn::nfd::ControlParameters>(makeRelPrefix("advertise"),
+    makeAuthorization(),
+    std::bind(&PrefixUpdateProcessor::validateParameters<AdvertisePrefixCommand>,
+                this, _1),
+    std::bind(&PrefixUpdateProcessor::advertiseAndInsertPrefix, this, _1, _2, _3, _4));
+
+  m_dispatcher.addControlCommand<ndn::nfd::ControlParameters>(makeRelPrefix("withdraw"),
+    makeAuthorization(),
+    std::bind(&PrefixUpdateProcessor::validateParameters<WithdrawPrefixCommand>,
+                this, _1),
+    std::bind(&PrefixUpdateProcessor::withdrawAndRemovePrefix, this, _1, _2, _3, _4));
 }
 
-void
-PrefixUpdateProcessor::startListening()
+ndn::mgmt::Authorization
+PrefixUpdateProcessor::makeAuthorization()
 {
-  _LOG_DEBUG("Setting Interest filter for: " << COMMAND_PREFIX);
+  return [=] (const ndn::Name& prefix, const ndn::Interest& interest,
+              const ndn::mgmt::ControlParameters* params,
+              const ndn::mgmt::AcceptContinuation& accept,
+              const ndn::mgmt::RejectContinuation& reject) {
+    m_validator.validate(interest,
+      [accept] (const std::shared_ptr<const ndn::Interest>& request) {
 
-  m_face.setInterestFilter(COMMAND_PREFIX, std::bind(&PrefixUpdateProcessor::onInterest, this, _2));
-}
-
-void
-PrefixUpdateProcessor::onInterest(const ndn::Interest& request)
-{
-  _LOG_TRACE("Received Interest: " << request);
-
-  if (!m_isEnabled) {
-    sendNack(request);
-    return;
-  }
-
-  m_validator.validate(request,
-                       std::bind(&PrefixUpdateProcessor::onCommandValidated, this, _1),
-                       std::bind(&PrefixUpdateProcessor::onCommandValidationFailed, this, _1, _2));
+        auto signer1 = getSignerFromTag(*request);
+        std::string signer = signer1.value_or("*");
+        _LOG_DEBUG("accept " << request->getName() << " signer=" << signer);
+        accept(signer);
+      },
+      [reject] (const std::shared_ptr<const ndn::Interest>& request,
+                const std::string& failureInfo) {
+        _LOG_DEBUG("reject " << request->getName() << " signer=" <<
+                      getSignerFromTag(*request).value_or("?") << ' ' << failureInfo);
+        reject(ndn::mgmt::RejectReply::STATUS403);
+      });
+  };
 }
 
 void
@@ -83,140 +107,5 @@
   m_validator.load(section, filename);
 }
 
-void
-PrefixUpdateProcessor::onCommandValidated(const std::shared_ptr<const ndn::Interest>& request)
-{
-  const ndn::Name& command = request->getName();
-  const ndn::Name::Component& verb = command[COMMAND_PREFIX.size()];
-  const ndn::Name::Component& parameterComponent = command[COMMAND_PREFIX.size() + 1];
-
-  if (verb == ADVERTISE_VERB || verb == WITHDRAW_VERB) {
-    ndn::nfd::ControlParameters parameters;
-
-    if (!extractParameters(parameterComponent, parameters)) {
-      sendResponse(request, 400, "Malformed command");
-      return;
-    }
-
-    if (verb == ADVERTISE_VERB) {
-      advertise(request, parameters);
-    }
-    else if (verb == WITHDRAW_VERB) {
-      withdraw(request, parameters);
-    }
-
-    sendResponse(request, 200, "Success");
-  }
-  else {
-    sendResponse(request, 501, "Unsupported command");
-  }
-}
-
-void
-PrefixUpdateProcessor::onCommandValidationFailed(const std::shared_ptr<const ndn::Interest>& request,
-                                                 const std::string& failureInfo)
-{
-  sendResponse(request, 403, failureInfo);
-}
-
-bool
-PrefixUpdateProcessor::extractParameters(const ndn::Name::Component& parameterComponent,
-                                         ndn::nfd::ControlParameters& extractedParameters)
-{
-  try {
-    ndn::Block rawParameters = parameterComponent.blockFromValue();
-    extractedParameters.wireDecode(rawParameters);
-  }
-  catch (const ndn::tlv::Error&) {
-    return false;
-  }
-
-  return true;
-}
-
-void
-PrefixUpdateProcessor::advertise(const std::shared_ptr<const ndn::Interest>& request,
-                                 const ndn::nfd::ControlParameters& parameters)
-{
-  AdvertisePrefixCommand command;
-
-  if (!validateParameters(command, parameters)) {
-    sendResponse(request, 400, "Malformed command");
-    return;
-  }
-
-  _LOG_INFO("Advertising name: " << parameters.getName());
-
-  if (m_namePrefixList.insert(parameters.getName())) {
-    // Only build a Name LSA if the added name is new
-    m_lsdb.buildAndInstallOwnNameLsa();
-  }
-}
-
-void
-PrefixUpdateProcessor::withdraw(const std::shared_ptr<const ndn::Interest>& request,
-                                const ndn::nfd::ControlParameters& parameters)
-{
-  WithdrawPrefixCommand command;
-
-  if (!validateParameters(command, parameters)) {
-    sendResponse(request, 400, "Malformed command");
-    return;
-  }
-
-  _LOG_INFO("Withdrawing name: " << parameters.getName());
-
-  if (m_namePrefixList.remove(parameters.getName())) {
-    // Only build a Name LSA if a name was actually removed
-    m_lsdb.buildAndInstallOwnNameLsa();
-  }
-}
-
-bool
-PrefixUpdateProcessor::validateParameters(const ndn::nfd::ControlCommand& command,
-                                          const ndn::nfd::ControlParameters& parameters)
-{
-  try {
-    command.validateRequest(parameters);
-  }
-  catch (const ndn::nfd::ControlCommand::ArgumentError&) {
-    return false;
-  }
-
-  return true;
-}
-
-void
-PrefixUpdateProcessor::sendNack(const ndn::Interest& request)
-{
-  ndn::MetaInfo metaInfo;
-  metaInfo.setType(ndn::tlv::ContentType_Nack);
-
-  std::shared_ptr<ndn::Data> responseData = std::make_shared<ndn::Data>(request.getName());
-  responseData->setMetaInfo(metaInfo);
-
-  m_keyChain.sign(*responseData);
-  m_face.put(*responseData);
-}
-
-void
-PrefixUpdateProcessor::sendResponse(const std::shared_ptr<const ndn::Interest>& request,
-                                    uint32_t code,
-                                    const std::string& text)
-{
-  if (request == nullptr) {
-    return;
-  }
-
-  ndn::nfd::ControlResponse response(code, text);
-  const ndn::Block& encodedControl = response.wireEncode();
-
-  std::shared_ptr<ndn::Data> responseData = std::make_shared<ndn::Data>(request->getName());
-  responseData->setContent(encodedControl);
-
-  m_keyChain.sign(*responseData);
-  m_face.put(*responseData);
-}
-
 } // namespace update
 } // namespace nlsr