From 0d52b048c0c0731caa800bea67e4ddd6f1653471 Mon Sep 17 00:00:00 2001
From: Roman Bazalevsky <rvb@rvb.name>
Date: Tue, 3 Nov 2015 19:29:07 +0300
Subject: [PATCH] =?utf8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5?=
 =?utf8?q?=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?=
 =?utf8?q?=D0=B0=20=D0=B7=D0=B0=D0=B2=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D1=8F?=
 =?utf8?q?=20VLC.=20=D0=98=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B0?=
 =?utf8?q?=20=D0=BF=D0=BE=D0=BF=D1=8B=D1=82=D0=BA=D0=B0=20=D0=BF=D0=BE?=
 =?utf8?q?=D0=B2=D1=82=D0=BE=D1=80=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BE=D1=82?=
 =?utf8?q?=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D1=8F=20=D1=83=D0=B6=D0=B5=20?=
 =?utf8?q?=D0=B0=D0=BA=D1=82=D0=B8=D0=B2=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BF?=
 =?utf8?q?=D0=BE=D1=82=D0=BE=D0=BA=D0=B0.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit

---
 vlcclient/vlcclient.py |  7 ++++++
 vphttp.py              | 55 +++++++++++++++++++++++++++++++++++-------
 2 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/vlcclient/vlcclient.py b/vlcclient/vlcclient.py
index 1fa5e43..f1e5733 100644
--- a/vlcclient/vlcclient.py
+++ b/vlcclient/vlcclient.py
@@ -186,6 +186,13 @@ class VlcClient(object):
         self.stopBroadcast(stream)
       self._resultlock.release()
 
+    def check_stream(self,stream_name):
+      if stream_name in self.streams:
+        self.streams[stream_name]=time.time()
+        return True
+      else:
+        return False  
+
     def pauseBroadcast(self, stream_name):
         return self._write(VlcMessage.request.pauseBroadcast(stream_name))
 
diff --git a/vphttp.py b/vphttp.py
index 040e94c..33da300 100644
--- a/vphttp.py
+++ b/vphttp.py
@@ -234,15 +234,21 @@ class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
         # then somebody is waiting in the videodestroydelay state
 
         # Check if we are first client
-        if VPStuff.clientcounter.get(self.reqtype+'/'+self.path_unquoted)==1:
-            logger.debug("First client, should create VLC session")
-            shouldcreatevp = True
-        else:
-            logger.debug("Can reuse existing session")
-            shouldcreatevp = False
 
         self.vlcid = hashlib.md5(self.reqtype+'/'+self.path_unquoted).hexdigest()
 
+        try:
+            if not VPStuff.vlcclient.check_stream(self.vlcid):
+                logger.debug("First client, should create VLC session")
+                shouldcreatevp = True
+            else:
+                logger.debug("Can reuse existing session")
+                shouldcreatevp = False
+        except Exception as e:
+            logger.error('Plugin exception: ' + repr(e))
+            logger.error(traceback.format_exc())
+            self.dieWithError()            
+
         # Send fake headers if this User-Agent is in fakeheaderuas tuple
         if fakeua:
             logger.debug(
@@ -329,7 +335,12 @@ class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
             # Waiting until hangDetector is joined
             self.hanggreenlet.join()
             logger.debug("Request handler finished")
-
+        except (vlcclient.VlcException) as e:
+            logger.error("Exception: " + repr(e))
+            VPStuff.vlcerrors = VPStuff.vlcerrors + 1
+            logger.error("%s error(s) communicating VLC")
+            self.errorhappened = True
+            self.dieWithError()            
         except (vpclient.VPException, vlcclient.VlcException, urllib2.URLError) as e:
             logger.error("Exception: " + repr(e))
             self.errorhappened = True
@@ -360,6 +371,7 @@ class VPStuff(object):
     Inter-class interaction class
     '''
     vlcclient=None
+    vlcerrors=0
 
 # taken from http://stackoverflow.com/questions/2699907/dropping-root-permissions-in-python
 def drop_privileges(uid_name, gid_name='nogroup'):
@@ -442,6 +454,7 @@ DEVNULL = open(os.devnull, 'wb')
 def spawnVLC(cmd, delay = 0):
     try:
         VPStuff.vlc = psutil.Popen(cmd) #, stdout=DEVNULL, stderr=DEVNULL)
+        VPStuff.vlcerrors = 0
         gevent.sleep(delay)
         return True
     except:
@@ -487,7 +500,18 @@ def clean_proc():
         gevent.sleep(1)
     if isRunning(VPStuff.vlc):
         # or not :)
-        VPStuff.vlc.kill()
+        VPStuff.vlc.terminate()
+        gevent.sleep(1)
+        if isRunning(VPStuff.vlc):
+            VPStuff.vlc.kill()
+    del VPStuff.vlc
+
+def restartVLC(cmd, delay = 0):
+    clean_proc()
+    if spawnVLC(cmd, delay):
+        if connectVLC():
+            return True
+    return False
 
 # This is what we call to stop the server completely
 def shutdown(signum = 0, frame = 0):
@@ -520,7 +544,8 @@ sched = BackgroundScheduler()
 sched.start()
 
 def clean_streams():
-  VPStuff.vlcclient.clean_streams(VPConfig.videodestroydelay)
+  if VPStuff.vlcclient:
+    VPStuff.vlcclient.clean_streams(VPConfig.videodestroydelay)
 
 job = sched.add_job(clean_streams, 'interval', seconds=15)
 
@@ -546,7 +571,9 @@ try:
     logger.info("Using VLC %s" % VPStuff.vlcclient._vlcver)
     logger.info("Server started.")
     while True:
+
         if not isRunning(VPStuff.vlc):
+
             del VPStuff.vlc
             if spawnVLC(VPStuff.vlcProc, VPConfig.vlcspawntimeout) and connectVLC():
                 logger.info("VLC died, respawned it with pid " + str(VPStuff.vlc.pid))
@@ -554,8 +581,18 @@ try:
                 logger.error("Cannot spawn VLC!")
                 clean_proc()
                 sys.exit(1)
+
         # Return to our server tasks
         server.handle_request()
+
+        if VPStuff.vlcerrors>5:
+            if restartVLC(VPStuff.vlcProc, VPConfig.vlcspawntimeout):
+                logger.info("VLC hung, respawned it with pid " + str(VPStuff.vlc.pid))
+            else:
+                logger.error("Cannot spawn VLC!")
+                clean_proc()
+                sys.exit(1)
+                                                                
 except (KeyboardInterrupt, SystemExit):
     sched.shutdown()
     shutdown()
-- 
2.34.1