msmith - in flumotion/trunk: . flumotion/component/consumers/httpstreamer

flumotion-commit at lists.fluendo.com flumotion-commit at lists.fluendo.com
Fri May 11 18:56:08 CEST 2007


Author: msmith
Date: Fri May 11 18:56:02 2007
New Revision: 4934

Modified:
   flumotion/trunk/ChangeLog
   flumotion/trunk/flumotion/component/consumers/httpstreamer/http.py
   flumotion/trunk/flumotion/component/consumers/httpstreamer/http.xml
   flumotion/trunk/flumotion/component/consumers/httpstreamer/resources.py
Log:
        * flumotion/component/consumers/httpstreamer/http.py:
        * flumotion/component/consumers/httpstreamer/http.xml:
        * flumotion/component/consumers/httpstreamer/resources.py:
          Implement bandwidth-limit in http streamer.
          Implement redirecting clients to a different location when the
          server is full (hitting either bandwidth limit or client limit)



Modified: flumotion/trunk/ChangeLog
==============================================================================
--- flumotion/trunk/ChangeLog	(original)
+++ flumotion/trunk/ChangeLog	Fri May 11 18:56:02 2007
@@ -1,3 +1,12 @@
+2007-05-11  Michael Smith <msmith at fluendo.com>
+
+	* flumotion/component/consumers/httpstreamer/http.py:
+	* flumotion/component/consumers/httpstreamer/http.xml:
+	* flumotion/component/consumers/httpstreamer/resources.py:
+	  Implement bandwidth-limit in http streamer.
+	  Implement redirecting clients to a different location when the
+	  server is full (hitting either bandwidth limit or client limit)
+
 2007-05-10  Sebastien Merle  <sebastien at fluendo.com>
 
 	* flumotion/common/enum.py: 

Modified: flumotion/trunk/flumotion/component/consumers/httpstreamer/http.py
==============================================================================
--- flumotion/trunk/flumotion/component/consumers/httpstreamer/http.py	(original)
+++ flumotion/trunk/flumotion/component/consumers/httpstreamer/http.py	Fri May 11 18:56:02 2007
@@ -50,6 +50,9 @@
 T_ = messages.gettexter('flumotion')
 
 __all__ = ['HTTPMedium', 'MultifdSinkStreamer']
+
+
+STATS_POLL_INTERVAL = 10
     
 # FIXME: generalize this class and move it out here ?
 class Stats:
@@ -66,6 +69,8 @@
         self.load_deltas = [0, 0]
         self._load_deltas_period = 10 # seconds
         self._load_deltas_ongoing = [time.time(), 0, 0]
+        self._currentBitrate = -1 # not known yet
+        self._lastBytesReceived = -1 # not known yet
 
         # keep track of average clients by tracking last average and its time
         self.average_client_number = 0
@@ -123,9 +128,25 @@
         self.load_deltas = [(add-oldadd)/diff, (remove-oldremove)/diff]
         self._load_deltas_ongoing = [now, add, remove]
 
+        bytesReceived = self.getBytesReceived()
+        if self._lastBytesReceived >= 0:
+            self._currentBitrate = ((bytesReceived - self._lastBytesReceived) *
+                 8 / STATS_POLL_INTERVAL)
+            self._lastBytesReceived = bytesReceived
+            
+        self._currentBitrate = -1 # not known yet
+        self._lastBytesSent = -1 # not known yet
+
         self.update_ui_state()
 
-        self._updateCallLaterId = reactor.callLater(10, self._updateStats)
+        self._updateCallLaterId = reactor.callLater(STATS_POLL_INTERVAL, 
+            self._updateStats)
+
+    def getCurrentBitrate(self):
+        if self._currentBitrate >= 0:
+            return self._currentBitrate
+        else:
+            return self.getBytesReceived() * 8 / self.getUptime()
 
     def getBytesSent(self):
         return self.sink.get_property('bytes-served')
@@ -445,6 +466,13 @@
         if properties.has_key('client-limit'):
             self.resource.setUserLimit(int(properties['client-limit']))
 
+        if properties.has_key('bandwidth-limit'):
+            self.resource.setBandwidthLimit(int(properties['bandwidth-limit']))
+
+        if properties.has_key('redirect-on-overflow'):
+            self.resource.setRedirectionOnLimits(
+                properties['redirect-on-overflow'])
+
         if properties.has_key('bouncer'):
             self.resource.setBouncerName(properties['bouncer'])
 

Modified: flumotion/trunk/flumotion/component/consumers/httpstreamer/http.xml
==============================================================================
--- flumotion/trunk/flumotion/component/consumers/httpstreamer/http.xml	(original)
+++ flumotion/trunk/flumotion/component/consumers/httpstreamer/http.xml	Fri May 11 18:56:02 2007
@@ -49,10 +49,14 @@
                   description="Server's host name to display" />
         <property name="domain" type="string"
                   description="Domain of server for authentication" />
+
         <property name="client-limit" type="int"
                   description="Maximum number of clients allowed" />
         <property name="bandwidth-limit" type="int"
-                  description="Maximum bandwidth usage allowed (not implemented)" />
+                  description="Maximum bandwidth usage allowed in bits per second" />
+        <property name="redirect-on-overflow" type="string"
+                  description="A URL to redirect clients to if either of the above limits have been reached" />
+
         <property name="duration" type="float"
                   description="How long to keep clients connected for (in seconds) "/>
 

Modified: flumotion/trunk/flumotion/component/consumers/httpstreamer/resources.py
==============================================================================
--- flumotion/trunk/flumotion/component/consumers/httpstreamer/resources.py	(original)
+++ flumotion/trunk/flumotion/component/consumers/httpstreamer/resources.py	Fri May 11 18:56:02 2007
@@ -85,6 +85,10 @@
         self._requests = {}            # request fd -> Request
         
         self.maxclients = self.getMaxAllowedClients(-1)
+        self.maxbandwidth = -1 # not limited by default
+
+        # If set, a URL to redirect a user to when the limits above are reached
+        self._redirectOnFull = None
         
         self.loggers = \
             streamer.plugs['flumotion.component.plugs.loggers.Logger']
@@ -150,6 +154,13 @@
         # Log what we actually managed to set it to.
         self.info('set maxclients to %d' % self.maxclients)
 
+    def setBandwidthLimit(self, limit):
+        self.maxbandwidth = limit
+        self.info("set maxbandwidth to %d", self.maxbandwidth)
+
+    def setRedirectionOnLimits(self, url):
+        self._redirectOnFull = url
+
     # FIXME: rename to writeHeaders
     """
     Write out the HTTP headers for the incoming HTTP request.
@@ -249,8 +260,14 @@
         else:
             return softmax - self.__reserve_fds__
 
-    def reachedMaxClients(self):
-        return len(self._requests) >= self.maxclients and self.maxclients >= 0
+    def reachedServerLimits(self):
+        if self.maxclients >= 0 and len(self._requests) >= self.maxclients:
+            return True
+        elif self.maxbandwidth >= 0:
+            if (len(self._requests) * self.streamer.getCurrentBitrate() >= 
+                    self.maxbandwidth):
+                return True
+        return False
     
     def _addClient(self, request):
         """
@@ -338,8 +355,8 @@
 
         if not self.isReady():
             return self._handleNotReady(request)
-        elif self.reachedMaxClients():
-            return self._handleMaxClients(request)
+        elif self.reachedServerLimits():
+            return self._handleServerFull(request)
 
         self.debug('_render(): asked for (possible) authentication')
         d = self.startAuthentication(request)
@@ -358,14 +375,20 @@
         self.debug('Not sending data, it\'s not ready')
         return server.NOT_DONE_YET
         
-    def _handleMaxClients(self, request):
-        self.debug('Refusing clients, client limit %d reached' %
-            self.maxclients)
+    def _handleServerFull(self, request):
+        if self._redirectOnFull:
+            self.debug("Redirecting client, client limit %d reached", 
+                self.maxclients)
+            error_code = http.FOUND
+            request.setHeader('location', self._redirectOnFull)
+        else:
+            self.debug('Refusing clients, client limit %d reached' %
+                self.maxclients)
+            error_code = http.SERVICE_UNAVAILABLE
 
         request.setHeader('content-type', 'text/html')
-        request.setHeader('server', HTTP_VERSION)
         
-        error_code = http.SERVICE_UNAVAILABLE
+        request.setHeader('server', HTTP_VERSION)
         request.setResponseCode(error_code)
         
         return ERROR_TEMPLATE % {'code': error_code,


More information about the flumotion-commit mailing list