face-monitor: added a generic face notification subscriber.
refs #1331
Change-Id: I7fee01949ae5392aba3fc452fe12e5d6bfbcdffc
diff --git a/src/face-monitor.cpp b/src/face-monitor.cpp
new file mode 100644
index 0000000..f4143a9
--- /dev/null
+++ b/src/face-monitor.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2014 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "common.hpp"
+#include "face-monitor.hpp"
+#include <ndn-cpp-dev/management/nfd-face-event-notification.hpp>
+
+
+namespace ndn {
+
+using namespace nfd;
+
+FaceMonitor::FaceMonitor(Face& face)
+ : m_face(face)
+ , m_isStopped(true)
+{
+}
+
+FaceMonitor::~FaceMonitor()
+{
+}
+
+void
+FaceMonitor::removeAllSubscribers()
+{
+ m_notificationCallbacks.clear();
+ m_timeoutCallbacks.clear();
+ stopNotifications();
+}
+
+void
+FaceMonitor::stopNotifications()
+{
+ if (static_cast<bool>(m_lastInterestId))
+ m_face.removePendingInterest(m_lastInterestId);
+ m_isStopped = true;
+}
+
+void
+FaceMonitor::startNotifications()
+{
+ if (m_isStopped == false)
+ return; // Notifications cycle has been started.
+ m_isStopped = false;
+
+ Interest interest("/localhost/nfd/faces/events");
+ interest
+ .setMustBeFresh(true)
+ .setChildSelector(1)
+ .setInterestLifetime(time::seconds(60))
+ ;
+
+ //todo: add logging support.
+ std::cout << "startNotification: Interest Sent: " << interest << std::endl;
+
+ m_lastInterestId = m_face.expressInterest(interest,
+ bind(&FaceMonitor::onNotification, this, _2),
+ bind(&FaceMonitor::onTimeout, this));
+}
+
+void
+FaceMonitor::addSubscriber(const NotificationCallback& notificationCallback)
+{
+ addSubscriber(notificationCallback, TimeoutCallback());
+}
+
+void
+FaceMonitor::addSubscriber(const NotificationCallback& notificationCallback,
+ const TimeoutCallback& timeoutCallback)
+{
+ if (static_cast<bool>(notificationCallback))
+ m_notificationCallbacks.push_back(notificationCallback);
+
+ if (static_cast<bool>(timeoutCallback))
+ m_timeoutCallbacks.push_back(timeoutCallback);
+}
+
+void
+FaceMonitor::onTimeout()
+{
+ if (m_isStopped)
+ return;
+
+ std::vector<TimeoutCallback>::iterator it;
+ for (it = m_timeoutCallbacks.begin();
+ it != m_timeoutCallbacks.end(); ++it) {
+ (*it)();
+ //One of the registered callbacks has cleared the vector,
+ //return now as the iterator has been invalidated and
+ //the vector is empty.
+ if (m_timeoutCallbacks.empty()) {
+ return;
+ }
+ }
+
+ Interest newInterest("/localhost/nfd/faces/events");
+ newInterest
+ .setMustBeFresh(true)
+ .setChildSelector(1)
+ .setInterestLifetime(time::seconds(60))
+ ;
+
+ //todo: add logging support.
+ std::cout << "In onTimeout, sending interest: " << newInterest << std::endl;
+
+ m_lastInterestId = m_face.expressInterest(newInterest,
+ bind(&FaceMonitor::onNotification, this, _2),
+ bind(&FaceMonitor::onTimeout, this));
+}
+
+void
+FaceMonitor::onNotification(const Data& data)
+{
+ if (m_isStopped)
+ return;
+
+ m_lastSequence = data.getName().get(-1).toSegment();
+ ndn::nfd::FaceEventNotification notification(data.getContent().blockFromValue());
+
+ std::vector<NotificationCallback>::iterator it;
+ for (it = m_notificationCallbacks.begin();
+ it != m_notificationCallbacks.end(); ++it) {
+ (*it)(notification);
+ if (m_notificationCallbacks.empty()) {
+ //One of the registered callbacks has cleared the vector.
+ //return back, as no one is interested in notifications anymore.
+ return;
+ }
+ }
+
+ //Setting up next notification
+ Name nextNotification("/localhost/nfd/faces/events");
+ nextNotification.appendSegment(m_lastSequence + 1);
+
+ Interest interest(nextNotification);
+ interest.setInterestLifetime(time::seconds(60));
+
+ //todo: add logging support.
+ std::cout << "onNotification: Interest sent: " << interest << std::endl;
+
+ m_lastInterestId = m_face.expressInterest(interest,
+ bind(&FaceMonitor::onNotification, this, _2),
+ bind(&FaceMonitor::onTimeout, this));
+}
+
+}//namespace ndn
+
diff --git a/src/face-monitor.hpp b/src/face-monitor.hpp
new file mode 100644
index 0000000..e0eeaa6
--- /dev/null
+++ b/src/face-monitor.hpp
@@ -0,0 +1,72 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2014 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+#ifndef FACE_MONITOR_HPP
+#define FACE_MONITOR_HPP
+
+#include "common.hpp"
+#include <ndn-cpp-dev/management/nfd-face-event-notification.hpp>
+#include <ndn-cpp-dev/management/nrd-controller.hpp>
+
+namespace ndn {
+
+class FaceMonitor
+{
+public:
+ typedef function<void(const nfd::FaceEventNotification&)> NotificationCallback;
+ typedef function<void()> TimeoutCallback;
+
+ typedef std::vector<NotificationCallback> NotificationCallbacks;
+ typedef std::vector<TimeoutCallback> TimeoutCallbacks;
+
+ explicit
+ FaceMonitor(Face& face);
+
+ ~FaceMonitor();
+
+ /** \brief Stops all notifications. This method doesn't remove registered callbacks.
+ */
+ void
+ stopNotifications();
+
+ /** \brief Resumes notifications for added subscribers.
+ */
+ void
+ startNotifications();
+
+ /** \brief Removes all notification subscribers.
+ */
+ void
+ removeAllSubscribers();
+
+ /** \brief Adds a notification subscriber. This method doesn't return on timeouts.
+ */
+ void
+ addSubscriber(const NotificationCallback& notificationCallback);
+
+ /** \brief Adds a notification subscriber.
+ */
+ void
+ addSubscriber(const NotificationCallback& notificationCallback,
+ const TimeoutCallback& timeoutCallback);
+
+private:
+ void
+ onTimeout();
+
+ void
+ onNotification(const Data& data);
+
+private:
+ Face& m_face;
+ uint64_t m_lastSequence;
+ bool m_isStopped;
+ NotificationCallbacks m_notificationCallbacks;
+ TimeoutCallbacks m_timeoutCallbacks;
+ const PendingInterestId* m_lastInterestId;
+};
+
+}//namespace ndn
+#endif //FACE_MONITOR_HPP