tools: nfdc face show command
refs #3864
Change-Id: Ibee7b082681edc35e8c272b2363436dbc7eaf9c0
diff --git a/tools/nfdc/available-commands.cpp b/tools/nfdc/available-commands.cpp
index 23d55e3..cc6cecc 100644
--- a/tools/nfdc/available-commands.cpp
+++ b/tools/nfdc/available-commands.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2014-2016, Regents of the University of California,
+ * Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,6 +26,7 @@
#include "available-commands.hpp"
#include "help.hpp"
#include "status.hpp"
+#include "face-module.hpp"
#include "legacy-status.hpp"
#include "legacy-nfdc.hpp"
@@ -38,6 +39,8 @@
{
registerHelpCommand(parser);
registerStatusCommands(parser);
+ FaceModule::registerCommands(parser);
+
registerLegacyStatusCommand(parser);
struct LegacyNfdcCommandDefinition
diff --git a/tools/nfdc/execute-command.cpp b/tools/nfdc/execute-command.cpp
new file mode 100644
index 0000000..639fd19
--- /dev/null
+++ b/tools/nfdc/execute-command.cpp
@@ -0,0 +1,43 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2017, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD 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.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "execute-command.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfdc {
+
+Controller::DatasetFailCallback
+ExecuteContext::makeDatasetFailureHandler(const std::string& datasetName)
+{
+ return [=] (uint32_t code, const std::string& reason) {
+ this->exitCode = 1;
+ this->err << "Error " << code << " when fetching " << datasetName << ": " << reason << '\n';
+ };
+}
+
+} // namespace nfdc
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfdc/execute-command.hpp b/tools/nfdc/execute-command.hpp
index c8ea5d2..644c70b 100644
--- a/tools/nfdc/execute-command.hpp
+++ b/tools/nfdc/execute-command.hpp
@@ -28,6 +28,7 @@
#include "command-arguments.hpp"
#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/mgmt/nfd/controller.hpp>
#include <ndn-cxx/security/key-chain.hpp>
namespace nfd {
@@ -36,11 +37,20 @@
using ndn::Face;
using ndn::KeyChain;
+using ndn::nfd::Controller;
/** \brief context for command execution
*/
-struct ExecuteContext
+class ExecuteContext
{
+public:
+ /** \brief handler for dataset retrieval failure
+ * \param datasetName dataset name used in error message
+ */
+ Controller::DatasetFailCallback
+ makeDatasetFailureHandler(const std::string& datasetName);
+
+public:
const std::string& noun;
const std::string& verb;
const CommandArguments& args;
@@ -52,11 +62,12 @@
Face& face;
KeyChain& keyChain;
///\todo validator
+ Controller& controller;
};
/** \brief a function to execute a command
*/
-typedef std::function<void(ExecuteContext& ctx)> ExecuteCommand;
+using ExecuteCommand = std::function<void(ExecuteContext& ctx)>;
} // namespace nfdc
} // namespace tools
diff --git a/tools/nfdc/face-module.cpp b/tools/nfdc/face-module.cpp
index 076b7af..721a56f 100644
--- a/tools/nfdc/face-module.cpp
+++ b/tools/nfdc/face-module.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2014-2016, Regents of the University of California,
+ * Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -23,26 +23,6 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \todo
- * #2542 plans to merge nfd-status with nfdc.
- * FaceModule class should be changed as follows:
- * (1) move into ndn::nfd::nfdc namespace
- * (2) assuming command syntax is similar to Windows NT \p netsh ,
- * this class can handle command argument parsing as soon as
- * 'face' sub-command is detected
- * (3) introduce methods to create and destroy faces, and update face attributes
- *
- * \todo
- * #3444 aims at improving output texts of nfdc.
- * Assuming it's worked with or after #2542:
- * (1) introduce an \p style parameter on formatItemText method to specify desired text style,
- * such as human friendly style vs. porcelain style for script consumption
- * (2) upon successful command execute, convert the command result into FaceStatus type,
- * and use formatItemText to render the result, so that output from status retrieval
- * and command execution have consistent styles
- * }
- */
-
#include "face-module.hpp"
#include "format-helpers.hpp"
@@ -51,6 +31,38 @@
namespace nfdc {
void
+FaceModule::registerCommands(CommandParser& parser)
+{
+ CommandDefinition defFaceShow("face", "show");
+ defFaceShow
+ .setTitle("show face information")
+ .addArg("id", ArgValueType::UNSIGNED, Required::YES, Positional::YES);
+ parser.addCommand(defFaceShow, &FaceModule::show);
+}
+
+void
+FaceModule::show(ExecuteContext& ctx)
+{
+ uint64_t faceId = ctx.args.get<uint64_t>("id");
+
+ ndn::nfd::FaceQueryFilter filter;
+ filter.setFaceId(faceId);
+ ctx.controller.fetch<ndn::nfd::FaceQueryDataset>(
+ filter,
+ [faceId, &ctx] (const std::vector<FaceStatus>& result) {
+ if (result.size() != 1) {
+ ctx.exitCode = 3;
+ ctx.err << "Face " << faceId << " not found.\n";
+ return;
+ }
+ formatItemText(ctx.out, result.front(), true);
+ },
+ ctx.makeDatasetFailureHandler("face information"));
+
+ ctx.face.processEvents();
+}
+
+void
FaceModule::fetchStatus(Controller& controller,
const function<void()>& onSuccess,
const Controller::DatasetFailCallback& onFailure,
@@ -128,43 +140,48 @@
{
os << "Faces:\n";
for (const FaceStatus& item : m_status) {
- this->formatItemText(os, item);
+ os << " ";
+ formatItemText(os, item, false);
+ os << '\n';
}
}
void
-FaceModule::formatItemText(std::ostream& os, const FaceStatus& item) const
+FaceModule::formatItemText(std::ostream& os, const FaceStatus& item, bool wantMultiLine)
{
- os << " faceid=" << item.getFaceId();
- os << " remote=" << item.getRemoteUri();
- os << " local=" << item.getLocalUri();
+ text::ItemAttributes ia(wantMultiLine, 8);
+
+ os << ia("faceid") << item.getFaceId();
+ os << ia("remote") << item.getRemoteUri();
+ os << ia("local") << item.getLocalUri();
if (item.hasExpirationPeriod()) {
- os << " expires=" << text::formatDuration(item.getExpirationPeriod());
+ os << ia("expires") << text::formatDuration(item.getExpirationPeriod());
}
- os << " counters={in={"
+ os << ia("counters")
+ << "{in={"
<< item.getNInInterests() << "i "
<< item.getNInDatas() << "d "
<< item.getNInNacks() << "n "
- << item.getNInBytes() << "B} ";
- os << "out={"
+ << item.getNInBytes() << "B} "
+ << "out={"
<< item.getNOutInterests() << "i "
<< item.getNOutDatas() << "d "
<< item.getNOutNacks() << "n "
<< item.getNOutBytes() << "B}}";
- os << " " << item.getFaceScope();
- os << " " << item.getFacePersistency();
- os << " " << item.getLinkType();
-
- os << " flags={";
+ os << ia("flags") << '{';
+ text::Separator flagSep("", " ");
+ os << flagSep << item.getFaceScope();
+ os << flagSep << item.getFacePersistency();
+ os << flagSep << item.getLinkType();
if (item.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)) {
- os << "local-fields";
+ os << flagSep << "local-fields";
}
- os << "}";
+ os << '}';
- os << "\n";
+ os << ia.end();
}
} // namespace nfdc
diff --git a/tools/nfdc/face-module.hpp b/tools/nfdc/face-module.hpp
index 27c089b..92c29b4 100644
--- a/tools/nfdc/face-module.hpp
+++ b/tools/nfdc/face-module.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2014-2016, Regents of the University of California,
+ * Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,6 +27,7 @@
#define NFD_TOOLS_NFDC_FACE_MODULE_HPP
#include "module.hpp"
+#include "command-parser.hpp"
namespace nfd {
namespace tools {
@@ -40,13 +41,23 @@
class FaceModule : public Module, noncopyable
{
public:
- virtual void
+ /** \brief register 'face show', 'face create', 'face destroy' commands
+ */
+ static void
+ registerCommands(CommandParser& parser);
+
+ /** \brief the 'face show' command
+ */
+ static void
+ show(ExecuteContext& ctx);
+
+ void
fetchStatus(Controller& controller,
const function<void()>& onSuccess,
const Controller::DatasetFailCallback& onFailure,
const CommandOptions& options) override;
- virtual void
+ void
formatStatusXml(std::ostream& os) const override;
/** \brief format a single status item as XML
@@ -56,15 +67,16 @@
void
formatItemXml(std::ostream& os, const FaceStatus& item) const;
- virtual void
+ void
formatStatusText(std::ostream& os) const override;
/** \brief format a single status item as text
* \param os output stream
* \param item status item
+ * \param wantMultiLine use multi-line style
*/
- void
- formatItemText(std::ostream& os, const FaceStatus& item) const;
+ static void
+ formatItemText(std::ostream& os, const FaceStatus& item, bool wantMultiLine);
private:
std::vector<FaceStatus> m_status;
diff --git a/tools/nfdc/format-helpers.cpp b/tools/nfdc/format-helpers.cpp
index 942a9f1..b6b8258 100644
--- a/tools/nfdc/format-helpers.cpp
+++ b/tools/nfdc/format-helpers.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2014-2016, Regents of the University of California,
+ * Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -118,6 +118,45 @@
return os << sep.m_subsequent;
}
+ItemAttributes::ItemAttributes(bool wantMultiLine, int maxAttributeWidth)
+ : m_wantMultiLine(wantMultiLine)
+ , m_maxAttributeWidth(maxAttributeWidth)
+ , m_count(0)
+{
+}
+
+ItemAttributes::Attribute
+ItemAttributes::operator()(const std::string& attribute)
+{
+ ++m_count;
+ if (m_wantMultiLine) {
+ return {m_count > 1,
+ {m_maxAttributeWidth - static_cast<int>(attribute.size())},
+ attribute};
+ }
+ else {
+ return {false,
+ {m_count > 1 ? 1 : 0},
+ attribute};
+ }
+}
+
+std::string
+ItemAttributes::end() const
+{
+ return m_wantMultiLine ? "\n" : "";
+}
+
+std::ostream&
+operator<<(std::ostream& os, const ItemAttributes::Attribute& attr)
+{
+ if (attr.wantNewline) {
+ os << '\n';
+ }
+ return os << attr.spaces << attr.attribute << '=';
+}
+
+
std::string
formatSeconds(time::seconds d, bool isLong)
{
diff --git a/tools/nfdc/format-helpers.hpp b/tools/nfdc/format-helpers.hpp
index 4c7badd..4fd2c38 100644
--- a/tools/nfdc/format-helpers.hpp
+++ b/tools/nfdc/format-helpers.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2014-2016, Regents of the University of California,
+ * Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -87,7 +87,7 @@
* // prints: 1,2,3
* \endcode
*/
-class Separator
+class Separator : noncopyable
{
public:
Separator(const std::string& first, const std::string& subsequent);
@@ -112,6 +112,54 @@
std::ostream&
operator<<(std::ostream& os, Separator& sep);
+/** \brief print attributes of an item
+ *
+ * \code
+ * ItemAttributes ia(wantMultiLine, 3);
+ * os << ia("id") << 500
+ * << ia("uri") << "udp4://192.0.2.1:6363"
+ * << ia.end();
+ *
+ * // prints in single-line style (wantMultiLine==false):
+ * // id=500 uri=udp4://192.0.2.1:6363 [no-newline]
+ *
+ * // prints in multi-line style (wantMultiLine==true):
+ * // id=500
+ * // uri=udp4://192.0.2.1:6363 [newline]
+ * \endcode
+ */
+class ItemAttributes : noncopyable
+{
+public:
+ /** \brief constructor
+ * \param wantMultiLine true to select multi-line style, false to use single-line style
+ * \param maxAttributeWidth maximum width of attribute names, for alignment in multi-line style
+ */
+ explicit
+ ItemAttributes(bool wantMultiLine = false, int maxAttributeWidth = 0);
+
+ struct Attribute
+ {
+ bool wantNewline;
+ Spaces spaces;
+ std::string attribute;
+ };
+
+ Attribute
+ operator()(const std::string& attribute);
+
+ std::string
+ end() const;
+
+private:
+ bool m_wantMultiLine;
+ int m_maxAttributeWidth;
+ int m_count;
+};
+
+std::ostream&
+operator<<(std::ostream& os, const ItemAttributes::Attribute& attr);
+
std::string
formatSeconds(time::seconds d, bool isLong = false);
diff --git a/tools/nfdc/main.cpp b/tools/nfdc/main.cpp
index 1f96c83..a7469a9 100644
--- a/tools/nfdc/main.cpp
+++ b/tools/nfdc/main.cpp
@@ -61,9 +61,10 @@
}
try {
- ndn::Face face;
- ndn::KeyChain keyChain;
- ExecuteContext ctx{noun, verb, ca, 0, std::cout, std::cerr, face, keyChain};
+ Face face;
+ KeyChain keyChain;
+ Controller controller(face, keyChain);
+ ExecuteContext ctx{noun, verb, ca, 0, std::cout, std::cerr, face, keyChain, controller};
execute(ctx);
return ctx.exitCode;
}