def testIsTrue(self): self.failUnless(common.strToBool('True')) self.failUnless(common.strToBool('true')) self.failUnless(common.strToBool('1')) self.failUnless(common.strToBool('yes')) self.failIf(common.strToBool('False')) self.failIf(common.strToBool('false')) self.failIf(common.strToBool('0')) self.failIf(common.strToBool('no')) self.failIf(common.strToBool('I am a monkey'))
def parseFeederports(self, node): """ Returns a list of feeder ports to use (possibly empty), and whether or not to use random feeder ports. @rtype: (list, bool) """ # returns a list of allowed port numbers # port := int # port-range := port "-" port # port-term := port | port-range # port-list := "" | port-term | port-term "," port-list # <feederports>port-list</feederports> random = False if node.hasAttribute('random'): random = common.strToBool(node.getAttribute('random')) ports = [] if not node.firstChild: return (ports, random) terms = str(node.firstChild.nodeValue).split(',') for term in terms: if '-' in term: (lower, upper) = [int(x) for x in term.split('-')] for port in range(lower, upper+1): if port not in ports: ports.append(port) else: port = int(term) if port not in ports: ports.append(port) return (ports, random)
def _parseNode(self, node): recordingChunk = {} try: for name in self.ELEMENTS: # Raises and IndexError if the element is missing element = node.getElementsByTagName(name)[0] # Get all the child nodes for the element, # theoretically only one containing the value we need childNodes = [x for x in element.childNodes\ if x.nodeType == Node.TEXT_NODE] if name in ['start', 'stop']: # the time must be represented in iso 8601 format, # with a second-precision and in utc (,000+0000) and # we transform it in a unix timestamp recordingChunk[name] = time.mktime(time.strptime( str(childNodes[0].nodeValue), '%Y-%m-%dT%H:%M:%S,000+0000')) elif name in ['record', 'complete']: recordingChunk[name] = strToBool(childNodes[0].nodeValue) else: recordingChunk[name] = childNodes[0].nodeValue except IndexError: self.warning("The mandatory element '%s' is missing.", name) return None except ValueError: self.warning("Could not parse element '%s'.", name) return None return recordingChunk
def parseFeederports(self, node): """ Returns a list of feeder ports to use (possibly empty), and whether or not to use random feeder ports. @rtype: (list, bool) """ # returns a list of allowed port numbers # port := int # port-range := port "-" port # port-term := port | port-range # port-list := "" | port-term | port-term "," port-list # <feederports>port-list</feederports> random = False if node.hasAttribute('random'): random = common.strToBool(node.getAttribute('random')) ports = [] if not node.firstChild: return (ports, random) terms = str(node.firstChild.nodeValue).split(',') for term in terms: if '-' in term: (lower, upper) = [int(x) for x in term.split('-')] if lower > upper: raise ConfigError("<feederports> has an invalid range: " "%s > %s " % (lower, upper)) for port in range(lower, upper+1): if port not in ports: ports.append(port) else: port = int(term) if port not in ports: ports.append(port) return (ports, random)
def boolean(v): if isinstance(v, bool): return v return common.strToBool(v)
class Index(log.Loggable): ''' Creates an index of keyframes for a file, than can be used later for seeking in non indexed formats or whithout parsing the headers. The format of the index is very similar to the AVI Index, but it can also include information about the real time of each entry in UNIX time. (see 'man aviindex') If the index is for an indexed format, the offset of the first entry will not start from 0. This offset is the size of the headers. ''' # CHK: Chunk number starting from 0 # POS: Absolute byte position of the chunk in the file # LEN: Length in bytes of the chunk # TS: Timestamp of the chunk (ns) # DUR: Duration of the chunk (ns) # KF: Whether it starts with a keyframe or not # TDT: Time and date using a UNIX timestamp (s) # TDUR: Duration of the chunk in UNIX time (s) INDEX_HEADER = "FLUIDX1 #Flumotion\n" INDEX_KEYS = ['CHK', 'POS', 'LEN', 'TS', 'DUR', 'KF', 'TDT', 'TDUR'] INDEX_EXTENSION = 'index' logCategory = "index" def __init__(self, component=None, location=None): self._index = [] self._headers_size = 0 self.comp = component self.location = location ### Public methods ### def updateStart(self, timestamp): ''' Remove entries in the index older than this timestamp ''' self.debug("Removing entries older than %s", timestamp) self._index = self._filter_index(timestamp) or [] def addEntry(self, offset, timestamp, keyframe, tdt=0, writeIndex=True): ''' Add a new entry to the the index and writes it to disk if writeIndex is True ''' if len(self._index) > 0: # Check that new entries have increasing timestamp, offset and tdt if not self._checkEntriesContinuity(offset, timestamp, tdt): return # And update the length and duration of the last entry self._updateLastEntry(offset, timestamp, tdt) # Then write the last updated index entry to disk if writeIndex and self.location: f = _openFile(self, self.comp, self.location, 'a+') if not f: return off = self._index[0]['offset'] - self._headers_size self._write_index_entry(f, self._index[-1], off, len(self._index) - 1) self._index.append({ 'offset': offset, 'length': -1, 'timestamp': timestamp, 'duration': -1, 'keyframe': keyframe, 'tdt': tdt, 'tdt-duration': -1 }) self.debug( "Added new entry to the index: offset=%s timestamp=%s " "keyframe=%s tdt=%s", offset, timestamp, keyframe, tdt) def setLocation(self, location): self.location = location def setHeadersSize(self, size): ''' Set the headers size in bytes. Multifdsink append the stream headers to each client. This size is then used to adjust the offset of the index entries ''' self._headers_size = size def getHeaders(self): ''' Return an index entry corresponding to the headers, which is a chunk with 'offset' 0 and 'length' equals to the headers size ''' if self._headers_size == 0: return None return { 'offset': 0, 'length': self._headers_size, 'timestamp': 0, 'duration': -1, 'keyframe': 0, 'tdt': 0, 'tdt-duration': -1 } def getFirstTimestamp(self): if len(self._index) == 0: return -1 return self._index[0]['timestamp'] def getFirstTDT(self): if len(self._index) == 0: return -1 return self._index[0]['tdt'] def clipTimestamp(self, start, stop): ''' Clip the current index to a start and stop time, returning all the entries matching the boundaries using the 'timestamp' ''' return self._clip('timestamp', 'duration', start, stop) def clipTDT(self, start, stop): ''' Clip the current index to a start and stop time, returning all the entries matching the boundaries using the 'tdt' ''' return self._clip('tdt', 'tdt-duration', start, stop) def clear(self): ''' Clears the index ''' self._index = [] def save(self, start=None, stop=None): ''' Saves the index in a file, using the entries from 'start' to 'stop' ''' if self.location is None: self.warning("Couldn't save the index, the location is not set.") return False f = _openFile(self, self.comp, self.location, 'w+') if not f: return False self._write_index_headers(f) if len(self._index) == 0: return True self._write_index_entries(f, self._filter_index(start, stop)) self.info("Index saved successfully. start=%s stop=%s location=%s ", start, stop, self.location) return True def loadIndexFile(self, location): ''' Loads the entries of the index from an index file ''' def invalidIndex(reason): self.warning("This file is not a valid index: %s", reason) return False if not location.endswith(self.INDEX_EXTENSION): return invalidIndex("the extension of this file is not '%s'" % self.INDEX_EXTENSION) try: self.info("Loading index file %s", location) handle = open(location, 'r') indexString = handle.readlines() handle.close() except IOError, e: return invalidIndex("error reading index file (%r)" % e) # Check if the file is not empty if len(indexString) == 0: return invalidIndex("the file is empty") # Check headers if not indexString[0].startswith('FLUIDX1 #'): return invalidIndex('header is not FLUIDX1') # Check index keys declaration keysStr = ' '.join(self.INDEX_KEYS) if indexString[1].strip('\n') != keysStr: return invalidIndex('keys definition is not: %s' % keysStr) # Add entries setHeaders = True for entryLine in indexString[2:]: e = entryLine.split(' ') if len(e) < len(self.INDEX_KEYS): return invalidIndex("one of the entries doesn't have enough " "parameters (needed=%d, provided=%d)" % (len(self.INDEX_KEYS), len(e))) try: self.addEntry(int(e[1]), int(e[3]), common.strToBool(e[5]), int(e[6])) except Exception, e: return invalidIndex("could not parse one of the entries: %r" % e) if setHeaders: self._headers_size = int(e[1]) setHeaders = False