Ejemplo n.º 1
0
    def handle(self, fmt=None):
        logger = logging.getLogger("ClientHandler")

        if not self.ace._state.wait(timeout=5.0): # STATE 1 (PREBUFFERING)
            self.handler.dieWithError(500, 'Video stream not opened in 5sec - disconnecting')
            return

        self.connectionTime = time.time()

        remaining = self.connectionTime + AceConfig.videostartbuffertime
        while  remaining >= time.time():
           gevent.sleep()
           if self.queue.qsize() >= self.ace._streamReaderQueue.maxsize: break

        # Sending videostream headers to client
        if self.handler.connection:
            response_headers = {'Connection': 'Keep-Alive', 'Keep-Alive': 'timeout=15, max=100', 'Content-Type': 'application/octet-stream', 'Access-Control-Allow-Origin': '*'}
            self.handler.send_response(200)
            logger.debug('Sending HTTPAceProxy headers to client: %s' % response_headers)
            for k,v in list(response_headers.items()): self.handler.send_header(k,v)
            self.handler.end_headers()

        transcoder = None
        out = self.handler.wfile

        if fmt and AceConfig.osplatform != 'Windows':
            if fmt in AceConfig.transcodecmd:
                stderr = None if AceConfig.loglevel == logging.DEBUG else DEVNULL
                popen_params = { 'bufsize': requests.models.CONTENT_CHUNK_SIZE,
                                 'stdin'  : gevent.subprocess.PIPE,
                                 'stdout' : self.handler.wfile,
                                 'stderr' : stderr,
                                 'shell'  : False }

                transcoder = gevent.subprocess.Popen(AceConfig.transcodecmd[fmt], **popen_params)
                out = transcoder.stdin
                logger.warning('Ffmpeg transcoding started')
            else:
                logger.error("Can't found fmt key. Ffmpeg transcoding not started!")

        logger.info('Streaming "%s" to %s started. Start buffer size: %s' % \
                 (self.channelName, self.handler.clientip, AceConfig.bytes2human(self.queue.qsize()*requests.models.CONTENT_CHUNK_SIZE)))

        while self.handler.connection:
            gevent.sleep()
            try: out.write(self.queue.get(timeout=AceConfig.videotimeout))
            except gevent.queue.Empty:
                logger.warning('No data received from StreamReader for %ssec - disconnecting "%s"' % (AceConfig.videotimeout,self.channelName))
                break
            except: break

        if transcoder is not None:
           try: transcoder.kill(); logger.warning('Ffmpeg transcoding stoped')
           except: pass
        self.destroy()
        return
Ejemplo n.º 2
0
    def do_GET(self):
        '''
        GET request handler
        '''
        self.handlerGreenlet = gevent.getcurrent() # Current greenlet
        self.clientip = self.headers.get('X-Forwarded-For', self.address_string()) # Connected client IP address
        logging.info(unquote('[{clientip}]: {command} {request_version} request for: {path}'.format(**self.__dict__)))
        logging.debug('[%s]: Request headers: %s' % (self.clientip, dict(self.headers)))

        if AceConfig.firewall and not checkFirewall(self.clientip):
           self.send_error(401, '[{clientip}]: Dropping connection due to firewall rules'.format(**self.__dict__), logging.ERROR)

        self.path, _, self.query = self.path.partition('?')
        self.path = self.path.rstrip('/')
        # Pretend to work fine with Fake or HEAD request.
        if self.command == 'HEAD' or AceConfig.isFakeRequest(self.path, self.query, self.headers):
           # Return 200 and exit
           if self.command != 'HEAD': self.command = 'FAKE'
           logging.debug('[{clientip}]: {command} request: send headers and close the connection'.format(**self.__dict__))
           self.send_response(200)
           self.send_header('Content-Type', 'video/mp2t')
           self.send_header('Connection', 'Close')
           self.end_headers()
           return

        try:
           self.splittedpath = self.path.split('/')
           self.reqtype = self.splittedpath[1].lower()
           AceProxy.pluginshandlers[self.reqtype].handle(self) # If request should be handled by plugin
           raise IndexError()

        except (IndexError, KeyError):
           self.reqtype = {'torrent': 'url', 'pid': 'content_id'}.get(self.reqtype, self.reqtype) # For backward compatibility
           if self.reqtype in {'content_id', 'url', 'infohash', 'direct_url', 'data', 'efile_url'}:
              # Limit on the number of connected clients
              if 0 < AceConfig.maxconns <= len(AceProxy.clientcounter.getAllClientsList()):
                 self.send_error(403, "[{clientip}]: Maximum client connections reached, can't serve request".format(**self.__dict__), logging.ERROR)
              # Check if third path parameter is exists /{reqtype}/{reqtype_value}/.../.../video.mpg
              #                                                                           |_________|
              # And if it ends with regular video extension
              if not self.splittedpath[-1].endswith(('.avi', '.flv', '.m2ts', '.mkv', '.mpeg', '.mpeg4', '.mpegts',
                                                     '.mpg4', '.mp4', '.mpg', '.mov', '.mpv', '.qt', '.ts', '.wmv')):
                    self.send_error(501, '[{clientip}]: request seems like valid but no valid video extension was provided'.format(**self.__dict__), logging.ERROR)
              else:
                 self.handleRequest()
           elif self.reqtype not in AceProxy.pluginshandlers:
              self.send_error(400, '[{clientip}]: Bad Request'.format(**self.__dict__), logging.WARNING)  # 400 Bad Request

        except Exception as e:
           logging.error('Unexpected exception: %s' % repr(e))
           logging.error(traceback.format_exc())
Ejemplo n.º 3
0
    def handleRequest(self,
                      headers_only,
                      channelName=None,
                      channelIcon=None,
                      fmt=None):
        logger = logging.getLogger('handleRequest')
        logger.debug("Headers:\n" + str(self.headers))
        self.requrl = urlparse.urlparse(self.path)
        self.reqparams = urlparse.parse_qs(self.requrl.query)
        self.path = self.requrl.path[:-1] if self.requrl.path.endswith(
            '/') else self.requrl.path

        # Check if third parameter exists
        # …/pid/blablablablabla/video.mpg
        #                      |_________|
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(
                ('.3gp', '.avi', '.flv', '.mkv', '.mov', '.mp4', '.mpeg',
                 '.mpg', '.ogv', '.ts')):
                logger.error(
                    "Request seems like valid but no valid video extension was provided"
                )
                self.dieWithError(400)
                return
        except IndexError:
            self.dieWithError(400)  # 400 Bad Request
            return

        # Limit concurrent connections
        if 0 < AceConfig.maxconns <= AceStuff.clientcounter.total:
            logger.debug("Maximum connections reached, can't serve this")
            self.dieWithError(503)  # 503 Service Unavailable
            return

        # Pretend to work fine with Fake or HEAD request.
        if headers_only or AceConfig.isFakeRequest(self.path, self.reqparams,
                                                   self.headers):
            # Return 200 and exit
            if headers_only:
                logger.debug("Sending headers and closing connection")
            else:
                logger.debug("Fake request - closing connection")
            self.send_response(200)
            self.send_header("Content-Type", "video/mpeg")
            self.end_headers()
            self.closeConnection()
            return

        # Make list with parameters
        self.params = list()
        for i in xrange(3, 8):
            try:
                self.params.append(int(self.splittedpath[i]))
            except (IndexError, ValueError):
                self.params.append('0')

        self.url = None
        self.video = None
        self.path_unquoted = urllib2.unquote(self.splittedpath[2])
        contentid = self.getCid(self.reqtype, self.path_unquoted)
        cid = contentid if contentid else self.path_unquoted
        logger.debug("CID: " + cid)
        self.client = Client(cid, self, channelName, channelIcon)
        self.vlcid = urllib2.quote(cid, '')
        shouldStart = AceStuff.clientcounter.add(cid, self.client) == 1

        try:
            # Initializing AceClient
            if shouldStart:
                if contentid:
                    self.client.ace.START('PID', {'content_id': contentid})
                elif self.reqtype == 'pid':
                    self.client.ace.START(
                        self.reqtype, {
                            'content_id': self.path_unquoted,
                            'file_indexes': self.params[0]
                        })
                elif self.reqtype == 'torrent':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_TORRENT,
                            self.params))
                    paramsdict['url'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict)
                logger.debug("START done")
                # Getting URL
                self.url = self.client.ace.getUrl(AceConfig.videotimeout)
                # Rewriting host for remote Ace Stream Engine
                self.url = self.url.replace('127.0.0.1', AceConfig.acehost)

            self.errorhappened = False

            if shouldStart:
                logger.debug("Got url " + self.url)
                # If using VLC, add this url to VLC
                if AceConfig.vlcuse:
                    # Force ffmpeg demuxing if set in config
                    if AceConfig.vlcforceffmpeg:
                        self.vlcprefix = 'http/ffmpeg://'
                    else:
                        self.vlcprefix = ''

                    self.client.ace.pause()
                    # Sleeping videodelay
                    gevent.sleep(AceConfig.videodelay)
                    self.client.ace.play()

                    AceStuff.vlcclient.startBroadcast(
                        self.vlcid, self.vlcprefix + self.url,
                        AceConfig.vlcmux, AceConfig.vlcpreaccess)
                    # Sleep a bit, because sometimes VLC doesn't open port in
                    # time
                    gevent.sleep(0.5)

            self.hanggreenlet = gevent.spawn(self.hangDetector)
            logger.debug("hangDetector spawned")
            gevent.sleep()

            # Building new VLC url
            if AceConfig.vlcuse:
                self.url = 'http://' + AceConfig.vlchost + \
                    ':' + str(AceConfig.vlcoutport) + '/' + self.vlcid
                logger.debug("VLC url " + self.url)

                # Sending client headers to videostream
                self.video = urllib2.Request(self.url)
                for key in self.headers.dict:
                    self.video.add_header(key, self.headers.dict[key])

                self.video = urllib2.urlopen(self.video)

                # Sending videostream headers to client
                if not self.headerssent:
                    self.send_response(self.video.getcode())
                    if self.video.info().dict.has_key('connection'):
                        del self.video.info().dict['connection']
                    if self.video.info().dict.has_key('server'):
                        del self.video.info().dict['server']
                    if self.video.info().dict.has_key('transfer-encoding'):
                        del self.video.info().dict['transfer-encoding']
                    if self.video.info().dict.has_key('keep-alive'):
                        del self.video.info().dict['keep-alive']

                    for key in self.video.info().dict:
                        self.send_header(key, self.video.info().dict[key])
                    # End headers. Next goes video data
                    self.end_headers()
                    logger.debug("Headers sent")

                # Run proxyReadWrite
                self.proxyReadWrite()
            else:
                if not fmt:
                    fmt = self.reqparams.get(
                        'fmt')[0] if self.reqparams.has_key('fmt') else None
                self.client.handle(shouldStart, self.url, fmt)

        except (aceclient.AceException, vlcclient.VlcException,
                urllib2.URLError) as e:
            logger.error("Exception: " + repr(e))
            self.errorhappened = True
            self.dieWithError()
        except gevent.GreenletExit:
            # hangDetector told us about client disconnection
            pass
        except Exception:
            # Unknown exception
            logger.error(traceback.format_exc())
            self.errorhappened = True
            self.dieWithError()
        finally:
            if AceConfig.videodestroydelay and not self.errorhappened and AceStuff.clientcounter.count(
                    cid) == 1:
                # If no error happened and we are the only client
                try:
                    logger.debug("Sleeping for " +
                                 str(AceConfig.videodestroydelay) + " seconds")
                    gevent.sleep(AceConfig.videodestroydelay)
                except:
                    pass

            try:
                remaining = AceStuff.clientcounter.delete(cid, self.client)
                self.client.destroy()
                self.ace = None
                self.client = None
                if AceConfig.vlcuse and remaining == 0:
                    try:
                        AceStuff.vlcclient.stopBroadcast(self.vlcid)
                    except:
                        pass
                logger.debug("END REQUEST")
            except:
                logger.error(traceback.format_exc())
Ejemplo n.º 4
0
    def handleRequest(self, headers_only, channelName=None, channelIcon=None, fmt=None):
        logger = logging.getLogger('handleRequest')
        logger.debug("Headers:\n" + str(self.headers))
        self.requrl = urlparse.urlparse(self.path)
        self.reqparams = urlparse.parse_qs(self.requrl.query)
        self.path = self.requrl.path[:-1] if self.requrl.path.endswith('/') else self.requrl.path
        
        # Check if third parameter exists
        # …/pid/blablablablabla/video.mpg
        #                      |_________|
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(('.3gp', '.avi', '.flv', '.mkv', '.mov', '.mp4', '.mpeg', '.mpg', '.ogv', '.ts')):
                logger.error("Request seems like valid but no valid video extension was provided")
                self.dieWithError(400)
                return
        except IndexError:
            self.dieWithError(400)  # 400 Bad Request
            return

        # Limit concurrent connections
        if 0 < AceConfig.maxconns <= AceStuff.clientcounter.total:
            logger.debug("Maximum connections reached, can't serve this")
            self.dieWithError(503)  # 503 Service Unavailable
            return

        # Pretend to work fine with Fake or HEAD request.
        if headers_only or AceConfig.isFakeRequest(self.path, self.reqparams, self.headers):
            # Return 200 and exit
            if headers_only:
                logger.debug("Sending headers and closing connection")
            else:
                logger.debug("Fake request - closing connection")
            self.send_response(200)
            self.send_header("Content-Type", "video/mpeg")
            self.end_headers()
            self.closeConnection()
            return

        # Make list with parameters
        self.params = list()
        for i in xrange(3, 8):
            try:
                self.params.append(int(self.splittedpath[i]))
            except (IndexError, ValueError):
                self.params.append('0')
        
        self.url = None
        self.video = None
        self.path_unquoted = urllib2.unquote(self.splittedpath[2])
        contentid = self.getCid(self.reqtype, self.path_unquoted)
        cid = contentid if contentid else self.path_unquoted
        logger.debug("CID: " + cid)
        self.client = Client(cid, self, channelName, channelIcon)
        self.vlcid = urllib2.quote(cid, '')
        shouldStart = AceStuff.clientcounter.add(cid, self.client) == 1

        try:
            # Initializing AceClient
            if shouldStart:
                if contentid:
                    self.client.ace.START('PID', {'content_id': contentid})
                elif self.reqtype == 'pid':
                    self.client.ace.START(
                        self.reqtype, {'content_id': self.path_unquoted, 'file_indexes': self.params[0]})
                elif self.reqtype == 'torrent':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_TORRENT, self.params))
                    paramsdict['url'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict)
                logger.debug("START done")
                # Getting URL
                self.url = self.client.ace.getUrl(AceConfig.videotimeout)
                # Rewriting host for remote Ace Stream Engine
                self.url = self.url.replace('127.0.0.1', AceConfig.acehost)

            self.errorhappened = False

            if shouldStart:
                logger.debug("Got url " + self.url)
                # If using VLC, add this url to VLC
                if AceConfig.vlcuse:
                    # Force ffmpeg demuxing if set in config
                    if AceConfig.vlcforceffmpeg:
                        self.vlcprefix = 'http/ffmpeg://'
                    else:
                        self.vlcprefix = ''

                    self.client.ace.pause()
                    # Sleeping videodelay
                    gevent.sleep(AceConfig.videodelay)
                    self.client.ace.play()

                    AceStuff.vlcclient.startBroadcast(
                        self.vlcid, self.vlcprefix + self.url, AceConfig.vlcmux, AceConfig.vlcpreaccess)
                    # Sleep a bit, because sometimes VLC doesn't open port in
                    # time
                    gevent.sleep(0.5)
            
            self.hanggreenlet = gevent.spawn(self.hangDetector)
            logger.debug("hangDetector spawned")
            gevent.sleep()

            # Building new VLC url
            if AceConfig.vlcuse:
                self.url = 'http://' + AceConfig.vlchost + \
                    ':' + str(AceConfig.vlcoutport) + '/' + self.vlcid
                logger.debug("VLC url " + self.url)
                
                # Sending client headers to videostream
                self.video = urllib2.Request(self.url)
                for key in self.headers.dict:
                    self.video.add_header(key, self.headers.dict[key])
    
                self.video = urllib2.urlopen(self.video)
    
                # Sending videostream headers to client
                if not self.headerssent:
                    self.send_response(self.video.getcode())
                    if self.video.info().dict.has_key('connection'):
                        del self.video.info().dict['connection']
                    if self.video.info().dict.has_key('server'):
                        del self.video.info().dict['server']
                    if self.video.info().dict.has_key('transfer-encoding'):
                        del self.video.info().dict['transfer-encoding']
                    if self.video.info().dict.has_key('keep-alive'):
                        del self.video.info().dict['keep-alive']
    
                    for key in self.video.info().dict:
                        self.send_header(key, self.video.info().dict[key])
                    # End headers. Next goes video data
                    self.end_headers()
                    logger.debug("Headers sent")
    
                # Run proxyReadWrite
                self.proxyReadWrite()
            else:
                if not fmt:
                    fmt = self.reqparams.get('fmt')[0] if self.reqparams.has_key('fmt') else None
                self.client.handle(shouldStart, self.url, fmt)

        except (aceclient.AceException, vlcclient.VlcException, urllib2.URLError) as e:
            logger.error("Exception: " + repr(e))
            self.errorhappened = True
            self.dieWithError()
        except gevent.GreenletExit:
            # hangDetector told us about client disconnection
            pass
        except Exception:
            # Unknown exception
            logger.error(traceback.format_exc())
            self.errorhappened = True
            self.dieWithError()
        finally:
            if AceConfig.videodestroydelay and not self.errorhappened and AceStuff.clientcounter.count(cid) == 1:
                # If no error happened and we are the only client
                try:
                    logger.debug("Sleeping for " + str(AceConfig.videodestroydelay) + " seconds")
                    gevent.sleep(AceConfig.videodestroydelay)
                except:
                    pass
                
            try:
                remaining = AceStuff.clientcounter.delete(cid, self.client)
                self.client.destroy()
                self.ace = None
                self.client = None
                if AceConfig.vlcuse and remaining == 0:
                    try:
                        AceStuff.vlcclient.stopBroadcast(self.vlcid)
                    except:
                        pass
                logger.debug("END REQUEST")
            except:
                logger.error(traceback.format_exc())
Ejemplo n.º 5
0
    def handleRequest(self,
                      headers_only,
                      channelName=None,
                      channelIcon=None,
                      fmt=None):
        logger = logging.getLogger('HandleRequest')
        self.reqparams, self.path = parse_qs(
            self.query), self.path[:-1] if self.path.endswith(
                '/') else self.path

        self.videoextdefaults = ('.3gp', '.aac', '.ape', '.asf', '.avi', '.dv',
                                 '.divx', '.flac', '.flc', '.flv', '.m2ts',
                                 '.m4a', '.mka', '.mkv', '.mpeg', '.mpeg4',
                                 '.mpegts', '.mpg4', '.mp3', '.mp4', '.mpg',
                                 '.mov', '.m4v', '.ogg', '.ogm', '.ogv',
                                 '.oga', '.ogx', '.qt', '.rm', '.swf', '.ts',
                                 '.vob', '.wmv', '.wav', '.webm')

        # Limit on the number of connected clients
        if 0 < AceConfig.maxconns <= AceProxy.clientcounter.totalClients():
            self.dieWithError(
                501,
                "Maximum client connections reached, can't serve request from %s"
                % self.clientip, logging.ERROR)
            return
        # Check if third parameter exists…/self.reqtype/blablablablabla/video.mpg
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(self.videoextdefaults):
                self.dieWithError(
                    501,
                    'Request seems like valid but no valid video extension was provided',
                    logging.ERROR)
                return
        except IndexError:
            self.dieWithError(400, 'Bad Request',
                              logging.WARNING)  # 400 Bad Request
            return
        # Pretend to work fine with Fake or HEAD request.
        if headers_only or AceConfig.isFakeRequest(self.path, self.query,
                                                   self.headers):
            # Return 200 and exit
            if headers_only:
                logger.debug('Sending headers and closing connection')
            else:
                logger.debug('Fake request - closing connection')
            self.send_response(200)
            self.send_header('Content-Type', 'video/mp2t')
            self.send_header('Connection', 'Close')
            self.end_headers()
            return
        # Check is AceEngine alive
        checkAce()
        # Make dict with parameters
        # [file_indexes, developer_id, affiliate_id, zone_id, stream_id]
        paramsdict = {}.fromkeys(aceclient.acemessages.AceConst.START_PARAMS,
                                 '0')
        for i in range(3, len(self.splittedpath)):
            paramsdict[aceclient.acemessages.AceConst.START_PARAMS[
                i - 3]] = self.splittedpath[i] if self.splittedpath[i].isdigit(
                ) else '0'
        paramsdict[self.reqtype] = unquote(
            self.splittedpath[2])  #self.path_unquoted
        #End parameters dict
        CID = NAME = None
        if not AceConfig.new_api:
            try:
                if not AceProxy.clientcounter.idleAce:
                    logger.debug('Create connection to AceEngine.....')
                    AceProxy.clientcounter.idleAce = aceclient.AceClient(
                        AceProxy.clientcounter, AceConfig.ace,
                        AceConfig.aceconntimeout, AceConfig.aceresulttimeout)
                    AceProxy.clientcounter.idleAce.aceInit(
                        AceConfig.acesex, AceConfig.aceage, AceConfig.acekey,
                        AceConfig.videoseekback, AceConfig.videotimeout)
                CID, NAME = AceProxy.clientcounter.idleAce.GETINFOHASH(
                    self.reqtype, paramsdict[self.reqtype],
                    paramsdict['file_indexes'])
            except aceclient.AceException as e:
                self.dieWithError(503, '%s' % repr(e), logging.ERROR)
                AceProxy.clientcounter.idleAce = None
                return
        else:
            try:
                with requests.session() as s:
                    s.stream = s.verify = False
                    url = 'http://%s:%s/ace/%s' % (
                        AceConfig.ace['aceHostIP'],
                        AceConfig.ace['aceHTTPport'], 'manifest.m3u8'
                        if AceConfig.acestreamtype['output_format'] == 'hls'
                        else 'getstream')
                    params = {
                        'id' if self.reqtype in ('cid', 'content_id') else self.reqtype:
                        paramsdict[self.reqtype],
                        'format':
                        'json',
                        'pid':
                        str(uuid4()),
                        '_idx':
                        paramsdict['file_indexes']
                    }
                    if AceConfig.acestreamtype['output_format'] == 'hls':
                        params.update(AceConfig.acestreamtype)
                        del params['output_format']
                    self.cmd = s.get(
                        url,
                        params=params,
                        timeout=(5, AceConfig.videotimeout)).json()['response']
                    CID = urlparse(self.cmd['playback_url']).path.split('/')[3]
                    url = 'http://%s:%s/server/api' % (
                        AceConfig.ace['aceHostIP'],
                        AceConfig.ace['aceHTTPport'])
                    params = {
                        'method': 'get_media_files',
                        self.reqtype: paramsdict[self.reqtype]
                    }
                    NAME = s.get(url,
                                 params=params,
                                 timeout=(5, AceConfig.aceresulttimeout)).json(
                                 )['result'][paramsdict['file_indexes']]
            except Exception as e:
                self.dieWithError(503, '%s' % repr(e), logging.ERROR)
                return

        self.connectionTime = gevent.time.time()
        self.channelName = NAME if not channelName else channelName
        self.channelIcon = 'http://static.acestream.net/sites/acestream/img/ACE-logo.png' if not channelIcon else channelIcon
        self.clientInfo = self.transcoder = None
        try:
            self.connectGreenlet = gevent.spawn(
                self.connectDetector)  # client disconnection watchdog
            self.out = self.wfile
            # If &fmt transcode key present in request
            fmt = self.reqparams.get('fmt', [''])[0]
            if fmt and AceConfig.osplatform != 'Windows':
                if fmt in AceConfig.transcodecmd:
                    stderr = None if AceConfig.loglevel == logging.DEBUG else DEVNULL
                    popen_params = {
                        'bufsize': 1048576,
                        'stdin': gevent.subprocess.PIPE,
                        'stdout': self.wfile,
                        'stderr': stderr,
                        'shell': False
                    }
                    try:
                        self.transcoder = gevent.event.AsyncResult()
                        gevent.spawn(lambda: psutil.Popen(
                            AceConfig.transcodecmd[fmt], **popen_params)).link(
                                self.transcoder)
                        self.transcoder = self.transcoder.get(timeout=2.0)
                        self.out = self.transcoder.stdin
                        logger.info('Transcoding for %s started' %
                                    self.clientip)
                    except:
                        logger.error(
                            'Error starting transcoding! Is Ffmpeg or VLC installed?'
                        )
                        self.transcoder = None
                        self.out = self.wfile
                else:
                    logger.error(
                        "Can't found fmt key. Transcoding not started!")

            self.response_use_chunked = False if self.transcoder is not None else AceConfig.use_chunked

            if AceProxy.clientcounter.addClient(CID, self) == 1:
                # If there is no existing broadcast we create it
                playback_url = self.cmd[
                    'playback_url'] if AceConfig.new_api else self.ace.START(
                        self.reqtype, paramsdict, AceConfig.acestreamtype)
                if not AceProxy.ace:  #Rewrite host:port for remote AceEngine
                    playback_url = urlparse(playback_url)._replace(
                        netloc='%s:%s' %
                        (AceConfig.ace['aceHostIP'],
                         AceConfig.ace['aceHTTPport'])).geturl()
                gevent.spawn(StreamReader, playback_url, CID)

            # Sending videostream headers to client
            logger.info('Streaming "%s" to %s started' %
                        (self.channelName, self.clientip))
            drop_headers = []
            proxy_headers = {
                'Connection': 'keep-alive',
                'Keep-Alive': 'timeout=15, max=100',
                'Accept-Ranges': 'none',
                'Transfer-Encoding': 'chunked',
                'Content-Type': 'application/octet-stream',
                'Cache-Control': 'max-age=0, no-cache, no-store',
                'Pragma': 'no-cache'
            }

            if not self.response_use_chunked or self.request_version == 'HTTP/1.0':
                self.protocol_version = 'HTTP/1.0'
                proxy_headers['Connection'] = 'Close'
                drop_headers.extend(
                    ['Transfer-Encoding', 'Keep-Alive', 'Cache-Control'])

            response_headers = [(k, v) for (k, v) in proxy_headers.items()
                                if k not in drop_headers]
            self.send_response(200)
            logger.debug('Sending HTTPAceProxy headers to client: %s' %
                         dict(response_headers))
            gevent.joinall([
                gevent.spawn(self.send_header, k, v)
                for (k, v) in response_headers
            ])
            self.end_headers()

            self.connectGreenlet.join(
            )  # Wait until request complite or client disconnected

        except aceclient.AceException as e:
            gevent.joinall([
                gevent.spawn(client.dieWithError, 503, '%s' % repr(e),
                             logging.ERROR)
                for client in AceProxy.clientcounter.getClientsList(CID)
            ])
            gevent.joinall([
                gevent.spawn(client.connectGreenlet.kill)
                for client in AceProxy.clientcounter.getClientsList(CID)
            ])
        except gevent.GreenletExit:
            pass  # Client disconnected
        except Exception as e:
            self.dieWithError(500, 'Unexpected error: %s' % repr(e))
        finally:
            logging.info('Streaming "%s" to %s finished' %
                         (self.channelName, self.clientip))
            if self.transcoder:
                try:
                    self.transcoder.kill()
                    logging.info('Transcoding for %s stoped' % self.clientip)
                except:
                    pass
            if AceProxy.clientcounter.deleteClient(CID, self) == 0:
                if AceConfig.new_api:
                    with requests.get(self.cmd['command_url'],
                                      params={'method': 'stop'},
                                      timeout=5) as r:
                        logging.debug('Stop broadcast: %s' % r.json())
                logging.debug(
                    'Broadcast "%s" stoped. Last client %s disconnected' %
                    (self.channelName, self.clientip))
Ejemplo n.º 6
0
    def handleRequest(self, headers_only, channelName=None, channelIcon=None, fmt=None):
        logger = logging.getLogger('HandleRequest')
        self.reqparams, self.path = parse_qs(self.query), self.path[:-1] if self.path.endswith('/') else self.path

        self.videoextdefaults = ('.3gp', '.aac', '.ape', '.asf', '.avi', '.dv', '.divx', '.flac', '.flc', '.flv', '.m2ts', '.m4a', '.mka', '.mkv',
                                 '.mpeg', '.mpeg4', '.mpegts', '.mpg4', '.mp3', '.mp4', '.mpg', '.mov', '.m4v', '.ogg', '.ogm', '.ogv', '.oga',
                                 '.ogx', '.qt', '.rm', '.swf', '.ts', '.vob', '.wmv', '.wav', '.webm')

        # If firewall enabled
        if AceConfig.firewall and not checkFirewall(self.clientip):
           self.dieWithError(403, 'Dropping connection from %s due to firewall rules' % self.clientip, logging.ERROR)  # 403 Forbidden
           return

        # Check if third parameter exists…/self.reqtype/blablablablabla/video.mpg
        #                                                     |_________|
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(self.videoextdefaults):
                self.dieWithError(400, 'Request seems like valid but no valid video extension was provided', logging.ERROR)
                return
        except IndexError: self.dieWithError(400, 'Bad Request', logging.WARNING); return  # 400 Bad Request

        # Limit concurrent connections
        if 0 < AceConfig.maxconns <= AceStuff.clientcounter.total:
            self.dieWithError(503, "Maximum client connections reached, can't serve request from %" % self.clientip, logging.ERROR)  # 503 Service Unavailable
            return

        # Pretend to work fine with Fake or HEAD request.
        if headers_only or AceConfig.isFakeRequest(self.path, self.reqparams, self.headers):
            # Return 200 and exit
            if headers_only: logger.debug('Sending headers and closing connection')
            else: logger.debug('Fake request - closing connection')
            self.send_response(200)
            self.send_header('Content-Type', 'video/mpeg')
            self.send_header('Connection', 'Close')
            self.end_headers()
            return

        # Make dict with parameters
        # [file_indexes, developer_id, affiliate_id, zone_id, stream_id]
        paramsdict = {}.fromkeys(aceclient.acemessages.AceConst.START_PARAMS, '0')
        for i in range(3, len(self.splittedpath)):
            paramsdict[aceclient.acemessages.AceConst.START_PARAMS[i-3]] = self.splittedpath[i] if self.splittedpath[i].isdigit() else '0'
        paramsdict[self.reqtype] = requests.compat.unquote(self.splittedpath[2]) #self.path_unquoted
        #End parameters dict
        self.client = None
        try:
            CID, NAME = self.getINFOHASH(self.reqtype, paramsdict[self.reqtype], paramsdict['file_indexes'])
            if not channelName: channelName = NAME
            if not channelIcon: channelIcon = 'http://static.acestream.net/sites/acestream/img/ACE-logo.png'
            # Create client
            self.client = Client(self, CID, channelName, channelIcon)
            # If there is no existing broadcast we create it
            if AceStuff.clientcounter.add(CID, self.client) == 1:
                logger.warning('Create a broadcast "%s"' % self.client.channelName)
                # Send START commands to AceEngine and Getting URL from engine
                url = self.client.ace.START(self.reqtype, paramsdict, AceConfig.acestreamtype)
                # Rewriting host:port for remote Ace Stream Engine
                if not AceStuff.ace:
                  url = requests.compat.urlparse(url)._replace(netloc='%s:%s' % (AceConfig.ace['aceHostIP'], AceConfig.ace['aceHTTPport'])).geturl()
                # Start streamreader for broadcast
                gevent.spawn(self.client.ace.StreamReader, url, CID, AceStuff.clientcounter)
                logger.warning('Broadcast "%s" created' % self.client.channelName)

        except aceclient.AceException as e: self.dieWithError(500, 'AceClient exception: %s' % repr(e))
        except Exception as e: self.dieWithError(500, 'Unkonwn exception: %s' % repr(e))
        else:
            # streaming to client
            self.client.handle(self.reqparams.get('fmt', [''])[0])
            logger.info('Streaming "%s" to %s finished' % (self.client.channelName, self.clientip))
        finally:
            if self.client and AceStuff.clientcounter.delete(CID, self.client) == 0:
                logger.warning('Broadcast "%s" stoped. Last client disconnected' % self.client.channelName)
        return
Ejemplo n.º 7
0
    def handleRequest(self,
                      headers_only,
                      channelName=None,
                      channelIcon=None,
                      fmt=None):

        logger = logging.getLogger('HandleRequest')
        self.reqparams, self.path = parse_qs(
            self.query), self.path[:-1] if self.path.endswith(
                '/') else self.path

        videoextdefaults = ('.avi', '.flv', '.m2ts', '.mkv', '.mpeg', '.mpeg4',
                            '.mpegts', '.mpg4', '.mp4', '.mpg', '.mov', '.mpv',
                            '.qt', '.ts', '.wmv')

        # Limit on the number of connected clients
        if 0 < AceConfig.maxconns <= len(
                AceProxy.clientcounter.getAllClientsList()):
            self.dieWithError(
                403,
                "Maximum client connections reached, can't serve request from %s"
                % self.clientip, logging.ERROR)
            return
        # Check if third parameter exists…/pid/blablablablabla/video.mpg
        #                                                     |_________|
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(videoextdefaults):
                self.dieWithError(
                    501,
                    'Request seems like valid but no valid video extension was provided',
                    logging.ERROR)
                return
        except IndexError:
            self.dieWithError(400, 'Bad Request',
                              logging.WARNING)  # 400 Bad Request
            return
        # Pretend to work fine with Fake or HEAD request.
        if headers_only or AceConfig.isFakeRequest(self.path, self.query,
                                                   self.headers):
            # Return 200 and exit
            if headers_only:
                logger.debug('Sending headers and closing connection')
            else:
                logger.debug('Fake request - closing connection')
            self.send_response(200)
            self.send_header('Content-Type', 'video/mp2t')
            self.send_header('Connection', 'Close')
            self.end_headers()
            self.closeConnection()
            return

        # Make dict with parameters
        # [file_indexes, developer_id, affiliate_id, zone_id, stream_id]
        paramsdict = {}.fromkeys(aceclient.acemessages.AceConst.START_PARAMS,
                                 '0')
        for i in range(3, len(self.splittedpath)):
            paramsdict[aceclient.acemessages.AceConst.START_PARAMS[
                i - 3]] = self.splittedpath[i] if self.splittedpath[i].isdigit(
                ) else '0'
        paramsdict[self.reqtype] = unquote(
            self.splittedpath[2])  #self.path_unquoted
        #End parameters dict

        self.connectionTime = gevent.time.time()
        self.sessionID = str(uuid4().int)[:8]
        self.clientInfo = self.transcoder = None
        self.channelIcon = 'http://static.acestream.net/sites/acestream/img/ACE-logo.png' if channelIcon is None else channelIcon

        try:
            if not AceProxy.clientcounter.idleAce:
                logger.debug('Create connection to AceEngine.....')
                AceProxy.clientcounter.idleAce = aceclient.AceClient(
                    AceProxy.clientcounter, AceConfig.ace,
                    AceConfig.aceconntimeout, AceConfig.aceresulttimeout)
                AceProxy.clientcounter.idleAce.aceInit(AceConfig.acesex,
                                                       AceConfig.aceage,
                                                       AceConfig.acekey,
                                                       AceConfig.videoseekback,
                                                       AceConfig.videotimeout)
            self.CID, self.channelName = AceProxy.clientcounter.idleAce.GETINFOHASH(
                self.reqtype, paramsdict[self.reqtype], self.sessionID,
                paramsdict['file_indexes'])
        except aceclient.AceException as e:
            AceProxy.clientcounter.idleAce = None
            self.dieWithError(404, '%s' % repr(e), logging.ERROR)
            return
        mimetype = mimetypes.guess_type(self.channelName)[0]
        try:
            gevent.spawn(wrap_errors(
                gevent.socket.error, self.rfile.read)).link(
                    lambda x: self.finish())  # Client disconection watchdog
            self.q = gevent.queue.Queue(maxsize=AceConfig.videotimeout)
            self.out = self.wfile
            # If &fmt transcode key present in request
            if fmt is None: fmt = self.reqparams.get('fmt', [''])[0]
            if fmt and AceConfig.osplatform != 'Windows':
                if fmt in AceConfig.transcodecmd:
                    stderr = None if AceConfig.loglevel == logging.DEBUG else DEVNULL
                    popen_params = {
                        'bufsize': 1048576,
                        'stdin': gevent.subprocess.PIPE,
                        'stdout': self.wfile,
                        'stderr': stderr,
                        'shell': False
                    }
                    try:
                        self.transcoder = gevent.event.AsyncResult()
                        AceProxy.spawn(lambda: psutil.Popen(
                            AceConfig.transcodecmd[fmt], **popen_params)).link(
                                self.transcoder)
                        self.transcoder = self.transcoder.get(timeout=2.0)
                        self.out = self.transcoder.stdin
                        logger.info('Transcoding for %s started' %
                                    self.clientip)
                    except:
                        logger.error(
                            'Error starting transcoding! Is Ffmpeg or VLC installed?'
                        )
                        self.transcoder = None
                        self.out = self.wfile
                else:
                    logger.error(
                        "Can't found fmt key. Transcoding not started!")

            # Start broadcast if it does not exist
            if AceProxy.clientcounter.addClient(self) == 1:
                playback_url = self.ace.START(self.reqtype, paramsdict,
                                              AceConfig.acestreamtype)
                AceProxy.pool.spawn(
                    StreamReader, playback_url,
                    self.CID).link(lambda x: logging.debug(
                        'Broadcast "%s" stoped. Last client disconnected' %
                        self.channelName))

            logger.info('Streaming "%s" to %s started' %
                        (self.channelName, self.clientip))
            # Sending videostream headers to client
            self.response_use_chunked = False if (
                self.transcoder is not None or self.request_version
                == 'HTTP/1.0') else AceConfig.use_chunked
            drop_headers = []
            proxy_headers = {
                'Connection': 'keep-alive',
                'Keep-Alive': 'timeout=15, max=100',
                'Accept-Ranges': 'none',
                'Transfer-Encoding': 'chunked',
                'Content-Type': 'video/MP2T' if mimetype is None else mimetype,
                'Pragma': 'no-cache',
                'Cache-Control': 'max-age=0, no-cache, no-store'
            }

            if not self.response_use_chunked:
                self.protocol_version = 'HTTP/1.0'
                proxy_headers['Connection'] = 'Close'
                drop_headers.extend(
                    ['Transfer-Encoding', 'Keep-Alive', 'Cache-Control'])

            response_headers = [(k, v) for (k, v) in proxy_headers.items()
                                if k not in drop_headers]
            self.send_response(200)
            logger.debug('Sending HTTPAceProxy headers to client: %s' %
                         dict(response_headers))
            gevent.joinall([
                gevent.spawn(self.send_header, k, v)
                for (k, v) in response_headers
            ])
            self.end_headers()
            # write data to client while he is alive
            for chunk in self.q:
                self.out.write(chunk)

        except aceclient.AceException as e:
            AceProxy.pool.map(
                lambda x: x.dieWithError(500, repr(e), logging.ERROR),
                AceProxy.clientcounter.getClientsList(self.CID))
        except (gevent.GreenletExit, gevent.socket.error):
            pass  # Client disconnected
        finally:
            AceProxy.clientcounter.deleteClient(self)
            logging.info('Streaming "%s" to %s finished' %
                         (self.channelName, self.clientip))
            if self.transcoder:
                try:
                    self.transcoder.kill()
                    logging.info('Transcoding for %s stoped' % self.clientip)
                except:
                    pass
            self.closeConnection()
Ejemplo n.º 8
0
    def handleRequest(self, headers_only, channelName=None, channelIcon=None, fmt=None):
        logger = logging.getLogger('HandleRequest')
        self.reqparams, self.path = parse_qs(self.query), self.path[:-1] if self.path.endswith('/') else self.path

        # Limit on the number of clients connected to broadcasts
        if 0 < AceConfig.maxconns <= AceStuff.clientcounter.totalClients():
            self.dieWithError(503, "Maximum client connections reached, can't serve request from %s" % self.clientip, logging.ERROR)  # 503 Service Unavailable
            return

        self.videoextdefaults = ('.3gp', '.aac', '.ape', '.asf', '.avi', '.dv', '.divx', '.flac', '.flc', '.flv', '.m2ts', '.m4a', '.mka', '.mkv',
                                 '.mpeg', '.mpeg4', '.mpegts', '.mpg4', '.mp3', '.mp4', '.mpg', '.mov', '.m4v', '.ogg', '.ogm', '.ogv', '.oga',
                                 '.ogx', '.qt', '.rm', '.swf', '.ts', '.vob', '.wmv', '.wav', '.webm')
        # Check if third parameter exists…/self.reqtype/blablablablabla/video.mpg
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(self.videoextdefaults):
                self.dieWithError(400, 'Request seems like valid but no valid video extension was provided', logging.ERROR)
                return
        except IndexError: self.dieWithError(400, 'Bad Request', logging.WARNING); return  # 400 Bad Request
        # Pretend to work fine with Fake or HEAD request.
        if headers_only or AceConfig.isFakeRequest(self.path, self.query, self.headers):
            # Return 200 and exit
            if headers_only: logger.debug('Sending headers and closing connection')
            else: logger.debug('Fake request - closing connection')
            self.send_response(200)
            self.send_header('Content-Type', 'video/mpeg')
            self.send_header('Connection', 'Close')
            self.end_headers()
            return

        # Make dict with parameters
        # [file_indexes, developer_id, affiliate_id, zone_id, stream_id]
        paramsdict = {}.fromkeys(aceclient.acemessages.AceConst.START_PARAMS, '0')
        for i in range(3, len(self.splittedpath)):
            paramsdict[aceclient.acemessages.AceConst.START_PARAMS[i-3]] = self.splittedpath[i] if self.splittedpath[i].isdigit() else '0'
        paramsdict[self.reqtype] = requests.compat.unquote(self.splittedpath[2]) #self.path_unquoted
        #End parameters dict
        self.connectionTime = gevent.time.time()
        CID = NAME = None
        try:
            if not AceStuff.clientcounter.idleAce:
               logger.debug('Create connection to AceEngine.....')
               AceStuff.clientcounter.idleAce = aceclient.AceClient(AceStuff.clientcounter, AceConfig.ace, AceConfig.aceconntimeout, AceConfig.aceresulttimeout)
               AceStuff.clientcounter.idleAce.aceInit(AceConfig.acesex, AceConfig.aceage, AceConfig.acekey, AceConfig.videoseekback, AceConfig.videotimeout)
            if self.reqtype not in ('direct_url', 'efile_url'):
               CID, NAME = AceStuff.clientcounter.idleAce.GETINFOHASH(self.reqtype, paramsdict[self.reqtype], paramsdict['file_indexes'])
            self.channelName = NAME if not channelName else channelName
            self.channelIcon = 'http://static.acestream.net/sites/acestream/img/ACE-logo.png' if not channelIcon else channelIcon
            # If there is no existing broadcast we create it
            if AceStuff.clientcounter.addClient(CID, self) == 1:
                logger.warning('Create a broadcast "%s"' % self.channelName)
                # Send START commands to AceEngine and Getting URL from engine
                url = self.ace.START(self.reqtype, paramsdict, AceConfig.acestreamtype)
                # Rewriting host:port for remote Ace Stream Engine
                if not AceStuff.ace:
                  url = requests.compat.urlparse(url)._replace(netloc='%s:%s' % (AceConfig.ace['aceHostIP'], AceConfig.ace['aceHTTPport'])).geturl()
                # Start streamreader for broadcast
                gevent.spawn(self.ace.AceStreamReader, url, CID)
                #except: pass
                logger.warning('Broadcast "%s" created' % self.channelName)

        except aceclient.AceException as e: self.dieWithError(500, 'AceClient exception: %s' % repr(e))
        except Exception as e: self.dieWithError(500, 'Unkonwn exception: %s' % repr(e))
        else:
            # streaming to client
            self.transcoder = None
            self.out = self.wfile
            if fmt and AceConfig.osplatform != 'Windows':
                if fmt in AceConfig.transcodecmd:
                    stderr = None if AceConfig.loglevel == logging.DEBUG else DEVNULL
                    popen_params = { 'bufsize': 1048576, 'stdin': gevent.subprocess.PIPE,
                                     'stdout': self.wfile, 'stderr': stderr, 'shell': False }
                    self.transcoder = gevent.subprocess.Popen(AceConfig.transcodecmd[fmt], **popen_params)
                    self.out = self.transcoder.stdin
                    logger.warning('Ffmpeg transcoding started')
                else:
                    logger.error("Can't found fmt key. Ffmpeg transcoding not started!")

            logger.info('Streaming "%s" to %s started' % (self.channelName, self.clientip))
            # Sending videostream headers to client
            headers = { 'Connection': 'Keep-Alive', 'Keep-Alive': 'timeout=15, max=100', 'Accept-Ranges': 'none',
                        'Content-Type': 'application/octet-stream', 'Transfer-Encoding': 'chunked' }
            drop_headers = []

            if self.transcoder: drop_headers.extend(['Transfer-Encoding'])

            response_headers = [ (k,v) for (k,v) in headers.items() if k not in drop_headers ]
            self.send_response(200)
            logger.debug('Sending HTTPAceProxy headers to client: %s' % dict(response_headers))
            for (k,v) in response_headers: self.send_header(k,v)
            self.end_headers()

            while self.connection: gevent.sleep(0.5) # Stream data to client from AceStreamReader

            if self.transcoder is not None:
                try: self.transcoder.kill(); logger.warning('Ffmpeg transcoding stoped')
                except: pass
            logger.info('Streaming "%s" to %s finished' % (self.channelName, self.clientip))

        finally:
            if CID and AceStuff.clientcounter.deleteClient(CID, self) == 0:
                logger.warning('Broadcast "%s" stoped. Last client disconnected' % self.channelName)
        return
Ejemplo n.º 9
0
    def handleRequest(self, **params):
        '''
        :params: dict() with keys: headers_only, channelName, channelIcon
        '''

        logger = logging.getLogger('HandleRequest')
        self.path = self.path[:-1] if self.path.endswith('/') else self.path

        # Limit on the number of connected clients
        if 0 < AceConfig.maxconns <= len(
                AceProxy.clientcounter.getAllClientsList()):
            self.dieWithError(
                403,
                "Maximum client connections reached, can't serve request from %s"
                % self.clientip, logging.ERROR)
            return
        # Check if third parameter exists…/pid/blablablablabla/video.mpg
        #                                                     |_________|
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(
                ('.avi', '.flv', '.m2ts', '.mkv', '.mpeg', '.mpeg4', '.mpegts',
                 '.mpg4', '.mp4', '.mpg', '.mov', '.mpv', '.qt', '.ts',
                 '.wmv')):
                self.dieWithError(
                    501,
                    'Request seems like valid but no valid video extension was provided',
                    logging.ERROR)
                return
        except IndexError:
            self.dieWithError(400, 'Bad Request',
                              logging.WARNING)  # 400 Bad Request
            return
        # Pretend to work fine with Fake or HEAD request.
        if params.get('headers_only') or AceConfig.isFakeRequest(
                self.path, self.query, self.headers):
            # Return 200 and exit
            if params.get('headers_only'):
                logger.debug('Sending headers and closing connection')
            else:
                logger.debug('Fake request - closing connection')
            self.send_response(200)
            self.send_header('Content-Type', 'video/mp2t')
            self.send_header('Connection', 'Close')
            self.end_headers()
            self.closeConnection()
            return

        # Make parameters dict
        params.update({self.reqtype:
                       unquote(self.splittedpath[2])})  # {command: value}
        params.update(
            {}.fromkeys(aceclient.acemessages.AceConst.START_PARAMS, '0')
        )  # [file_indexes, developer_id, affiliate_id, zone_id, stream_id]
        params.update({
            k: v
            for (k, v) in
            [(aceclient.acemessages.AceConst.START_PARAMS[i - 3],
              self.splittedpath[i] if self.splittedpath[i].isdigit() else '0')
             for i in range(3, len(self.splittedpath))]
        })
        params.update({
            'stream_type':
            ' '.join([
                '{}={}'.format(k, v)
                for k, v in AceConfig.acestreamtype.items()
            ])
        })  # request http or hls from AceEngine
        params['request_id'] = self.sessionID = str(uuid4().int)[:8]
        # End parameters dict

        self.connectionTime = gevent.time.time()
        self.clientInfo = None
        self.channelIcon = params.get('channelIcon')
        if self.channelIcon is None:
            self.channelIcon = 'http://static.acestream.net/sites/acestream/img/ACE-logo.png'

        try:
            if not AceProxy.clientcounter.idleAce:
                logger.debug(
                    'Create connection with AceStream on {aceHostIP}:{aceAPIport}'
                    .format(**AceConfig.ace))
                AceProxy.clientcounter.idleAce = aceclient.AceClient(
                    AceConfig.ace, AceConfig.aceconntimeout,
                    AceConfig.aceresulttimeout)
                AceProxy.clientcounter.idleAce.GetAUTH(AceConfig.acesex,
                                                       AceConfig.aceage,
                                                       AceConfig.acekey,
                                                       AceConfig.videoseekback,
                                                       AceConfig.videotimeout)
            if self.reqtype not in ('direct_url', 'efile_url'):
                self.CID, self.channelName = AceProxy.clientcounter.idleAce.GetCONTENTINFO(
                    params)
            else:
                self.channelName = params.get('channelName')
                if self.channelName is None: self.channelName = 'NoNameChannel'
                self.CID = requests.auth.hashlib.sha1(
                    self.channelName.encode('utf-8')).hexdigest()
        except aceclient.AceException as e:
            AceProxy.clientcounter.idleAce = None
            self.dieWithError(404, '%s' % repr(e), logging.ERROR)
            return
        ext = self.channelName[self.channelName.rfind('.') + 1:]
        if ext == self.channelName:
            ext = parse_qs(self.query).get('ext', ['ts'])[0]
        mimetype = mimetypes.guess_type('%s.%s' % (self.channelName, ext))[0]
        try:
            AceProxy.pool.spawn(
                wrap_errors(gevent.socket.error, self.rfile.read)).link(
                    lambda x: self.finish())  # Client disconection watchdog
            self.q = gevent.queue.Queue(maxsize=AceConfig.videotimeout)
            out = self.wfile
            # If &fmt transcode key present in request
            fmt = parse_qs(self.query).get('fmt', [''])[0]
            transcoder = gevent.event.AsyncResult()
            if fmt:
                if AceConfig.osplatform != 'Windows':
                    if fmt in AceConfig.transcodecmd:
                        stderr = None if AceConfig.loglevel == logging.DEBUG else DEVNULL
                        popen_params = {
                            'bufsize': 1048576,
                            'stdin': gevent.subprocess.PIPE,
                            'stdout': self.wfile,
                            'stderr': stderr,
                            'shell': False
                        }
                        try:
                            #transcoder = gevent.event.AsyncResult()
                            AceProxy.pool.spawn(lambda: psutil.Popen(
                                AceConfig.transcodecmd[fmt], **popen_params)
                                                ).link(transcoder)
                            out = transcoder.get(timeout=2.0).stdin
                            logger.info(
                                'Transcoding for {clientip} started'.format(
                                    **self.__dict__))
                        except:
                            logger.error(
                                'Error starting transcoding! Is Ffmpeg or VLC installed?'
                            )
                    else:
                        logger.error(
                            "Can't found fmt key. Transcoding not started!")
                elif AceConfig.osplatform == 'Windows':
                    logger.error(
                        'Not applicable in Windnows OS. Transcoding not started!'
                    )

            # Start broadcast if it does not exist
            if AceProxy.clientcounter.addClient(self) == 1:
                START = self.ace.GetBroadcastStartParams(params)
                self.broadcast = AceProxy.pool.spawn(StreamReader,
                                                     START['url'],
                                                     START['infohash'])
                self.broadcast.link(lambda x: logging.debug(
                    'Broadcast "{channelName}" stoped. Last client disconnected'
                    .format(**self.__dict__)))

            logger.info(
                'Streaming "{channelName}" to {clientip} started'.format(
                    **self.__dict__))
            # Sending videostream headers to client
            response_use_chunked = False if (
                transcoder is not None or self.request_version
                == 'HTTP/1.0') else AceConfig.use_chunked
            drop_headers = []
            proxy_headers = {
                'Connection': 'keep-alive',
                'Keep-Alive': 'timeout=%s, max=100' % AceConfig.videotimeout,
                'Accept-Ranges': 'none',
                'Transfer-Encoding': 'chunked',
                'Content-Type': 'video/MP2T' if mimetype is None else mimetype
            }

            if not response_use_chunked:
                self.protocol_version = 'HTTP/1.0'
                proxy_headers['Connection'] = 'Close'
                drop_headers.extend(['Transfer-Encoding', 'Keep-Alive'])

            response_headers = [(k, v) for (k, v) in proxy_headers.items()
                                if k not in drop_headers]
            self.send_response(200)
            logger.debug('Sending HTTPAceProxy headers to client: %s' %
                         dict(response_headers))
            gevent.joinall([
                gevent.spawn(self.send_header, k, v)
                for (k, v) in response_headers
            ])
            self.end_headers()
            # write data to client while he is alive
            for chunk in self.q:
                out.write(b'%x\r\n' % len(chunk) + chunk +
                          b'\r\n' if response_use_chunked else chunk)

        except aceclient.AceException as e:
            _ = AceProxy.pool.map(
                lambda x: x.dieWithError(500, repr(e), logging.ERROR),
                AceProxy.clientcounter.getClientsList(self.CID))
        except (gevent.GreenletExit, gevent.socket.error):
            pass  # Client disconnected
        finally:
            AceProxy.clientcounter.deleteClient(self)
            logging.info(
                'Streaming "{channelName}" to {clientip} finished'.format(
                    **self.__dict__))
            if transcoder.value:
                try:
                    transcoder.value.kill()
                    logging.info('Transcoding for {clientip} stoped'.format(
                        **self.__dict__))
                except:
                    pass
            self.closeConnection()
            return
Ejemplo n.º 10
0
    def handleRequest(self,
                      headers_only,
                      channelName=None,
                      channelIcon=None,
                      fmt=None):
        logger = logging.getLogger('HandleRequest')
        #logger.debug("Accept connected client headers :\n" + str(self.headers))
        self.requrl = urlparse.urlparse(self.path)
        self.reqparams = urlparse.parse_qs(self.requrl.query)
        self.path = self.requrl.path[:-1] if self.requrl.path.endswith(
            '/') else self.requrl.path
        self.videoextdefaults = ('.3gp', '.aac', '.ape', '.asf', '.avi', '.dv',
                                 '.divx', '.flac', '.flc', '.flv', '.m2ts',
                                 '.m4a', '.mka', '.mkv', '.mpeg', '.mpeg4',
                                 '.mpegts', '.mpg4', '.mp3', '.mp4', '.mpg',
                                 '.mov', '.m4v', '.ogg', '.ogm', '.ogv',
                                 '.oga', '.ogx', '.qt', '.rm', '.swf', '.ts',
                                 '.vob', '.wmv', '.wav', '.webm')
        # Check if third parameter exists…/pid/blablablablabla/video.mpg
        #                                                     |_________|
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(self.videoextdefaults):
                logger.error(
                    "Request seems like valid but no valid video extension was provided"
                )
                self.dieWithError(400)
                return
        except IndexError:
            self.dieWithError(400)  # 400 Bad Request
            return

        # Limit concurrent connections
        if 0 < AceConfig.maxconns <= AceStuff.clientcounter.total:
            logger.info("Maximum connections reached, can't serve this")
            self.dieWithError(503)  # 503 Service Unavailable
            return

        # Pretend to work fine with Fake or HEAD request.
        if headers_only or AceConfig.isFakeRequest(self.path, self.reqparams,
                                                   self.headers):
            # Return 200 and exit
            if headers_only:
                logger.debug("Sending headers and closing connection")
            else:
                logger.debug("Fake request - closing connection")
            self.send_response(200)
            self.send_header("Content-Type", "video/mpeg")
            self.send_header("Connection", "Close")
            self.end_headers()
            self.closeConnection()
            return

        # Make list with parameters
        # file_indexes developer_id affiliate_id zone_id stream_id
        self.params = list()
        for i in xrange(3, 8):
            try:
                self.params.append(int(self.splittedpath[i]))
            except (IndexError, ValueError):
                self.params.append('0')
        # End parameters

        self.url = None
        self.video = None

        self.path_unquoted = requests.utils.unquote(self.splittedpath[2])
        contentid = self.getCid(self.reqtype, self.path_unquoted)
        cid = contentid if contentid else self.path_unquoted

        self.vlcid = requests.utils.quote(cid, '')
        self.client = Client(cid, self, channelName, channelIcon)
        shouldStart = AceStuff.clientcounter.add(cid, self.client) == 1

        try:
            # Initializing AceClient
            if shouldStart:
                # Send commands to AceEngine
                if contentid:
                    self.client.ace.START('PID', {
                        'content_id': contentid,
                        'file_indexes': self.params[0]
                    })
                elif self.reqtype == 'pid':
                    self.client.ace.START(
                        self.reqtype, {
                            'content_id': self.path_unquoted,
                            'file_indexes': self.params[0]
                        })
                elif self.reqtype == 'torrent':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_PARAMS,
                            self.params))
                    paramsdict['url'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict)
                elif self.reqtype == 'infohash':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_PARAMS,
                            self.params))
                    paramsdict['infohash'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict)
                elif self.reqtype == 'url':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_PARAMS,
                            self.params))
                    paramsdict['direct_url'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict)
                elif self.reqtype == 'raw':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_PARAMS,
                            self.params))
                    paramsdict['data'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict)
                elif self.reqtype == 'efile':
                    self.client.ace.START(self.reqtype,
                                          {'efile_url': self.path_unquoted})

                logger.debug("START %s done" % (self.reqtype))

                # Getting URL from engine
                if self.reqtype == 'infohash' or self.reqtype == 'torrent':
                    self.url = self.client.ace.getUrl(AceConfig.videotimeout *
                                                      2)
                else:
                    self.url = self.client.ace.getUrl(AceConfig.videotimeout)
                # Rewriting host:port for remote Ace Stream Engine
                p = urlparse.urlsplit(self.url)
                p = p._replace(netloc=AceConfig.acehost + ':' +
                               str(AceConfig.aceHTTPport))
                self.url = urlparse.urlunsplit(p)

                logger.debug("Successfully get url %s from AceEngine!" %
                             (self.url))
                self.errorhappened = False

            if shouldStart:
                # If using VLC, add this url to VLC
                if AceConfig.vlcuse:
                    # Force ffmpeg demuxing if set in config
                    if AceConfig.vlcforceffmpeg:
                        self.vlcprefix = 'http/ffmpeg://'
                    else:
                        self.vlcprefix = ''

                    AceStuff.vlcclient.startBroadcast(
                        self.vlcid, self.vlcprefix + self.url,
                        AceConfig.vlcmux, AceConfig.vlcpreaccess)
                    # Sleep a bit, because sometimes VLC doesn't open port in time
                    gevent.sleep(0.5)

            self.client.ace.play()

            self.hanggreenlet = gevent.spawn(self.hangDetector)
            logger.debug("hangDetector spawned")
            gevent.sleep()

            if AceConfig.vlcuse:
                # Building new VLC url
                self.url = 'http://' + AceConfig.vlchost + \
                    ':' + str(AceConfig.vlcoutport) + '/' + self.vlcid
                logger.debug("VLC output url: " + self.url)

                # Sending client headers to videostream
                if self.headers.has_key('range'):
                    del self.headers['range']

                logger.debug('Sending client headers to VLC broadcast: %s' %
                             self.headers.dict)

                self.video = requests.get(self.url,
                                          headers=self.headers.dict,
                                          stream=True)
                logger.debug('Got headers from VLC broadcast: %s' %
                             self.video.headers)

                # Sending videostream headers to client
                self.send_response(self.video.status_code)
                if self.video.headers.get('server'):
                    del self.video.headers['server']
                if self.video.headers.get('data'):
                    del self.video.headers['data']
                if self.video.headers.get('transfer-encoding'):
                    del self.video.headers['transfer-encoding']
                if self.video.headers.get('accept-ranges'):
                    del self.video.headers['accept-ranges']

                for key in self.video.headers:
                    self.send_header(key, self.video.headers.get(key))
                self.end_headers()
                logger.debug('Sending HTTPAceProxy headers to client: %s' %
                             self.video.headers)

                # Run proxyReadWrite
                self.proxyReadWrite()
            else:
                if not fmt:
                    fmt = self.reqparams.get(
                        'fmt')[0] if self.reqparams.has_key('fmt') else None
                # Start translation
                self.client.handle(shouldStart, self.url, fmt,
                                   self.headers.dict)

        except (aceclient.AceException, vlcclient.VlcException,
                requests.exceptions.ConnectionError) as e:
            logger.error("Exception: " + repr(e))
            self.errorhappened = True
            self.dieWithError()
        except gevent.GreenletExit:
            # hangDetector told us about client disconnection
            logger.debug('greenletExit')
            pass
        except Exception:
            # Unknown exception
            logger.error(traceback.format_exc())
            self.errorhappened = True
            self.dieWithError()
        finally:
            if not self.errorhappened and AceStuff.clientcounter.count(
                    cid) == 1:
                # If no error happened and we are the only client
                try:
                    gevent.sleep()  #VIDEO_DESTROY_DELAY
                except:
                    pass
            try:
                remaining = AceStuff.clientcounter.delete(cid, self.client)
                if self.client:
                    self.client.destroy()
                self.ace = None
                self.client = None
                if AceConfig.vlcuse and remaining == 0:
                    try:
                        AceStuff.vlcclient.stopBroadcast(self.vlcid)
                    except:
                        pass
                logger.debug("END REQUEST")
            except:
                logger.error(traceback.format_exc())
Ejemplo n.º 11
0
    def handleRequest(self,
                      headers_only,
                      channelName=None,
                      channelIcon=None,
                      fmt=None):
        logger = logging.getLogger('HandleRequest')
        self.requrl = requests.utils.urlparse(self.path)
        self.reqparams = parse_qs(self.query)
        self.path = self.requrl.path[:-1] if self.requrl.path.endswith(
            '/') else self.requrl.path
        self.videoextdefaults = ('.3gp', '.aac', '.ape', '.asf', '.avi', '.dv',
                                 '.divx', '.flac', '.flc', '.flv', '.m2ts',
                                 '.m4a', '.mka', '.mkv', '.mpeg', '.mpeg4',
                                 '.mpegts', '.mpg4', '.mp3', '.mp4', '.mpg',
                                 '.mov', '.m4v', '.ogg', '.ogm', '.ogv',
                                 '.oga', '.ogx', '.qt', '.rm', '.swf', '.ts',
                                 '.vob', '.wmv', '.wav', '.webm')

        # If firewall enabled
        if AceConfig.firewall and not checkFirewall(self.clientip):
            self.dieWithError(
                403, 'Dropping connection from %s due to firewall rules' %
                self.clientip, logging.ERROR)  # 403 Forbidden
            return

        # Check if third parameter exists…/self.reqtype/blablablablabla/video.mpg
        #                                                     |_________|
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(self.videoextdefaults):
                self.dieWithError(
                    400,
                    'Request seems like valid but no valid video extension was provided',
                    logging.ERROR)
                return
        except IndexError:
            self.dieWithError(400, 'Bad Request', logging.WARNING)
            return  # 400 Bad Request

        # Limit concurrent connections
        if 0 < AceConfig.maxconns <= AceStuff.clientcounter.total:
            self.dieWithError(
                503, "Maximum client connections reached, can't serve this",
                logging.ERROR)  # 503 Service Unavailable
            return

        # Pretend to work fine with Fake or HEAD request.
        if headers_only or AceConfig.isFakeRequest(self.path, self.reqparams,
                                                   self.headers):
            # Return 200 and exit
            if headers_only:
                logger.debug("Sending headers and closing connection")
            else:
                logger.debug("Fake request - closing connection")
            self.send_response(200)
            self.send_header("Content-Type", "video/mpeg")
            self.send_header("Connection", "Close")
            self.end_headers()
            return

        # Make dict with parameters
        # [file_indexes, developer_id, affiliate_id, zone_id, stream_id]
        paramsdict = dict()
        for i in xrange(3, 8):
            try:
                paramsdict.update({
                    aceclient.acemessages.AceConst.START_PARAMS[i - 3]:
                    int(self.splittedpath[i])
                })
            except (IndexError, ValueError):
                paramsdict.update(
                    {aceclient.acemessages.AceConst.START_PARAMS[i - 3]: '0'})
        paramsdict[self.reqtype] = requests.utils.unquote(
            self.splittedpath[2])  #self.path_unquoted
        #End parameters dict

        content_id = self.getCID(self.reqtype, paramsdict[self.reqtype])
        CID = content_id if content_id else paramsdict[self.reqtype]
        if not channelName and self.reqtype in ('content_id', 'url',
                                                'infohash'):
            try:
                headers = {
                    'User-Agent': 'Python-urllib/2.7',
                    'Content-Type': 'application/octet-stream',
                    'Connection': 'close'
                }
                url = 'http://%s:%s/server/api' % (AceConfig.acehost,
                                                   AceConfig.aceHTTPport)
                params = {
                    'method': 'get_media_files',
                    self.reqtype: paramsdict[self.reqtype]
                }
                channelName = requests.get(url,
                                           headers=headers,
                                           params=params,
                                           timeout=5).json()['result'][str(
                                               paramsdict['file_indexes'])]
            except:
                channelName = CID
        if not channelIcon:
            channelIcon = 'http://static.acestream.net/sites/acestream/img/ACE-logo.png'
        # Create client
        self.client = Client(CID, self, channelName, channelIcon)
        try:
            # If there is no existing broadcast we create it
            if AceStuff.clientcounter.add(CID, self.client) == 1:
                logger.warning('Create a broadcast "%s"' %
                               self.client.channelName)
                # Send START commands to AceEngine
                self.client.ace.START(self.reqtype, paramsdict,
                                      AceConfig.streamtype)
                # Getting URL from engine
                self.url = self.client.ace.getUrl(
                    AceConfig.videotimeout *
                    2) if self.reqtype in ('infohash', 'url',
                                           'data') else self.client.ace.getUrl(
                                               AceConfig.videotimeout)
                # Rewriting host:port for remote Ace Stream Engine
                p = requests.utils.urlparse(
                    self.url)._replace(netloc=AceConfig.acehost + ':' +
                                       str(AceConfig.aceHTTPport))
                self.url = requests.utils.urlunparse(p)
                # Start streamreader for broadcast
                gevent.spawn(self.client.ace.startStreamReader, self.url, CID,
                             AceStuff.clientcounter, self.headers.dict)
                gevent.sleep()
                logger.warning('Broadcast "%s" created' %
                               self.client.channelName)

        except aceclient.AceException as e:
            self.dieWithError(500, 'AceClient exception: %s' % repr(e))
        except Exception as e:
            self.dieWithError(500, 'Unkonwn exception: %s' % repr(e))
        else:
            if not fmt:
                fmt = self.reqparams.get(
                    'fmt')[0] if 'fmt' in self.reqparams else None
            # streaming to client
            logger.info('Streaming "%s" to %s started' %
                        (self.client.channelName, self.clientip))
            self.client.handle(fmt)
            logger.info('Streaming "%s" to %s finished' %
                        (self.client.channelName, self.clientip))
        finally:
            if AceStuff.clientcounter.delete(CID, self.client) == 0:
                logger.warning(
                    'Broadcast "%s" stoped. Last client disconnected' %
                    self.client.channelName)
            self.client.destroy()
            return
Ejemplo n.º 12
0
    def handleRequest(self,
                      headers_only,
                      channelName=None,
                      channelIcon=None,
                      fmt=None):
        logger = logging.getLogger('HandleRequest')
        self.requrl = urlparse(self.path)
        self.reqparams = parse_qs(self.requrl.query)
        self.path = self.requrl.path[:-1] if self.requrl.path.endswith(
            '/') else self.requrl.path
        self.videoextdefaults = ('.3gp', '.aac', '.ape', '.asf', '.avi', '.dv',
                                 '.divx', '.flac', '.flc', '.flv', '.m2ts',
                                 '.m4a', '.mka', '.mkv', '.mpeg', '.mpeg4',
                                 '.mpegts', '.mpg4', '.mp3', '.mp4', '.mpg',
                                 '.mov', '.m4v', '.ogg', '.ogm', '.ogv',
                                 '.oga', '.ogx', '.qt', '.rm', '.swf', '.ts',
                                 '.vob', '.wmv', '.wav', '.webm')

        # If firewall enabled
        if AceConfig.firewall and not checkFirewall(self.clientip):
            self.dieWithError(
                403, 'Dropping connection from %s due to firewall rules' %
                self.clientip, logging.ERROR)  # 403 Forbidden
            return

        # Check if third parameter exists…/pid/blablablablabla/video.mpg
        #                                                     |_________|
        # And if it ends with regular video extension
        try:
            if not self.path.endswith(self.videoextdefaults):
                self.dieWithError(
                    400,
                    'Request seems like valid but no valid video extension was provided',
                    logging.ERROR)
                return
        except IndexError:
            self.dieWithError(400, 'Bad Request', logging.WARNING)
            return  # 400 Bad Request

        # Limit concurrent connections
        if 0 < AceConfig.maxconns <= AceStuff.clientcounter.total:
            self.dieWithError(
                503, "Maximum client connections reached, can't serve this",
                logging.ERROR)  # 503 Service Unavailable
            return

        # Pretend to work fine with Fake or HEAD request.
        if headers_only or AceConfig.isFakeRequest(self.path, self.reqparams,
                                                   self.headers):
            # Return 200 and exit
            if headers_only:
                logger.debug("Sending headers and closing connection")
            else:
                logger.debug("Fake request - closing connection")
            self.send_response(200)
            self.send_header("Content-Type", "video/mpeg")
            self.send_header("Connection", "Close")
            self.end_headers()
            self.closeConnection()
            return

        # Check is AceStream engine alive before start streaming
        if self.connection: checkAce()

        # Make list with parameters
        # file_indexes developer_id affiliate_id zone_id stream_id
        self.params = list()
        for i in xrange(3, 8):
            try:
                self.params.append(int(self.splittedpath[i]))
            except (IndexError, ValueError):
                self.params.append('0')

        # End parameters
        self.url = None
        CID = self.path_unquoted = requests.utils.unquote(self.splittedpath[2])
        if self.reqtype == 'torrent':
            CID = self.getInfohash(self.reqtype, self.path_unquoted)
        if not CID: CID = self.getCid(self.reqtype, self.path_unquoted)
        if not CID: CID = self.path_unquoted
        self.client = Client(CID, self, channelName, channelIcon)
        try:
            # If there is no existing broadcast
            if AceStuff.clientcounter.add(CID, self.client) == 1:
                logger.warning('Create a broadcast.....')
                # Send commands to AceEngine
                if self.reqtype == 'pid':
                    self.client.ace.START(
                        self.reqtype, {
                            'content_id': self.path_unquoted,
                            'file_indexes': self.params[0]
                        }, AceConfig.streamtype)
                elif self.reqtype == 'torrent':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_PARAMS,
                            self.params))
                    paramsdict['url'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict,
                                          AceConfig.streamtype)
                elif self.reqtype == 'infohash':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_PARAMS,
                            self.params))
                    paramsdict['infohash'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict,
                                          AceConfig.streamtype)
                elif self.reqtype == 'url':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_PARAMS,
                            self.params))
                    paramsdict['direct_url'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict,
                                          AceConfig.streamtype)
                elif self.reqtype == 'raw':
                    paramsdict = dict(
                        zip(aceclient.acemessages.AceConst.START_PARAMS,
                            self.params))
                    paramsdict['data'] = self.path_unquoted
                    self.client.ace.START(self.reqtype, paramsdict,
                                          AceConfig.streamtype)
                elif self.reqtype == 'efile':
                    self.client.ace.START(self.reqtype,
                                          {'efile_url': self.path_unquoted},
                                          AceConfig.streamtype)

                # Getting URL from engine
                if self.reqtype == 'infohash' or self.reqtype == 'torrent':
                    self.url = self.client.ace.getUrl(AceConfig.videotimeout *
                                                      2)
                else:
                    self.url = self.client.ace.getUrl(AceConfig.videotimeout)
                # Rewriting host:port for remote Ace Stream Engine
                p = urlsplit(
                    self.url)._replace(netloc=AceConfig.acehost + ':' +
                                       str(AceConfig.aceHTTPport))
                self.url = urlunsplit(p)
                self.client.ace.play()  # send EVENT play to AceSnream Engine
                # Start streamreader for broadcast
                gevent.spawn(self.client.ace.startStreamReader, self.url, CID,
                             AceStuff.clientcounter, self.headers.dict)
                gevent.sleep()
                logger.warning('Broadcast "%s" created' %
                               (self.client.channelName
                                if self.client.channelName != None else CID))

        except aceclient.AceException as e:
            self.dieWithError(500, 'AceClient exception: %s' % repr(e))
        except Exception as e:
            self.dieWithError(500, 'Unkonwn exception: %s' % repr(e))
        else:
            if not fmt:
                fmt = self.reqparams.get(
                    'fmt')[0] if 'fmt' in self.reqparams else None
            # streaming to client
            logger.info(
                'Streaming "%s" to %s started' %
                (self.client.channelName
                 if self.client.channelName != None else CID, self.clientip))
            self.client.handle(fmt)
            logger.info(
                'Streaming "%s" to %s finished' %
                (self.client.channelName
                 if self.client.channelName != None else CID, self.clientip))
        finally:
            if AceStuff.clientcounter.delete(CID, self.client) == 0:
                logger.warning(
                    'Broadcast "%s" destroyed. Last client disconnected' %
                    (self.client.channelName
                     if self.client.channelName != None else CID))
            self.client.destroy()
            self.client = None