webplot: ctrl-c to terminate webplot

This patch handles the ctrl-c keyboard interrupt properly by
notifying the clients to quit. If there is no client connection,
just shutdown the cherrypy engine.

BUG=chromium:475168
TEST=Launch a webplot server on a chromebook
$ webplot
Without any client browser connection, press ctrl-c and observe
that webplot terminates properly.

Change-Id: I0af78c33691b1c15f3ea2e12b5c94f82e6776e43
Reviewed-on: https://chromium-review.googlesource.com/264899
Reviewed-by: Charlie Mooney <charliemooney@chromium.org>
Commit-Queue: Shyh-In Hwang <josephsih@chromium.org>
Tested-by: Shyh-In Hwang <josephsih@chromium.org>
diff --git a/webplot/webplot.py b/webplot/webplot.py
index b5a85ea..4bba3b2 100755
--- a/webplot/webplot.py
+++ b/webplot/webplot.py
@@ -197,6 +197,13 @@
       self.shutdown_timer.start()
     self.lock.release()
 
+  def ShutdownWhenNoConnections(self):
+    """Shutdown cherrypy server when there is no client connection."""
+    self.lock.acquire()
+    if self.count == 0 and self.shutdown_timer is None:
+      self.Shutdown()
+    self.lock.release()
+
   def Shutdown(self):
     """Shutdown the cherrypy server."""
     cherrypy.log('Shutdown timer expires. Cherrypy server for Webplot exits.')
@@ -395,15 +402,23 @@
     cherrypy.log('Start getting the live stream snapshots....')
     with open(self._saved_file, 'w') as f:
       while True:
-        snapshot = self.GetSnapshot()
-        if not snapshot:
-          cherrypy.log('webplot is terminated.')
-          break
-        # TODO: get the raw events from the sanpshot
-        events = []
-        f.write('\n'.join(events) + '\n')
-        f.flush()
-        self.AddSnapshot(snapshot)
+        try:
+          snapshot = self.GetSnapshot()
+          if not snapshot:
+            cherrypy.log('webplot is terminated.')
+            break
+          # TODO: get the raw events from the sanpshot
+          events = []
+          f.write('\n'.join(events) + '\n')
+          f.flush()
+          self.AddSnapshot(snapshot)
+        except KeyboardInterrupt:
+          cherrypy.log('Keyboard Interrupt accepted')
+          cherrypy.log('webplot is being terminated...')
+          # Notify the clients to quit.
+          self.Publish('quit')
+          # If there is no client connection, the cherrypy server just exits.
+          state.ShutdownWhenNoConnections()
 
   def Publish(self, msg):
     """Publish a message to clients."""