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