Package flumotion :: Package admin :: Package assistant :: Module models
[hide private]

Source Code for Module flumotion.admin.assistant.models

  1  # -*- Mode: Python; test-case-name: flumotion.test.test_wizard_models -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008,2009 Fluendo, S.L. 
  6  # Copyright (C) 2010,2011 Flumotion Services, S.A. 
  7  # All rights reserved. 
  8  # 
  9  # This file may be distributed and/or modified under the terms of 
 10  # the GNU Lesser General Public License version 2.1 as published by 
 11  # the Free Software Foundation. 
 12  # This file is distributed without any warranty; without even the implied 
 13  # warranty of merchantability or fitness for a particular purpose. 
 14  # See "LICENSE.LGPL" in the source distribution for more information. 
 15  # 
 16  # Headers in this file shall remain intact. 
 17   
 18   
 19  """model objects used by the configuration assistant steps""" 
 20   
 21  import random 
 22   
 23  from flumotion.common import log 
 24  from flumotion.common.errors import ComponentValidationError 
 25  from flumotion.common.fraction import fractionFromValue 
 26   
 27  __version__ = "$Rev$" 
28 29 30 -def _generateRandomString(numchars):
31 """Generate a random US-ASCII string of length numchars 32 """ 33 s = "" 34 chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 35 for unused in range(numchars): 36 s += chars[random.randint(0, len(chars)-1)] 37 38 return s
39
40 41 -class Properties(dict):
42 """I am a special dictionary which you also can treat as an instance. 43 Setting and getting an attribute works. 44 This is suitable for using in a kiwi proxy. 45 >>> p = Properties() 46 >>> p.attr = 'value' 47 >>> p 48 <Properties {'attr': 'value'}> 49 50 Note that you cannot insert the attributes which has the same name 51 as dictionary methods, such as 'keys', 'values', 'items', 'update'. 52 53 Underscores are converted to dashes when setting attributes, eg: 54 55 >>> p.this_is_outrageous = True 56 >>> p 57 <Properties {'this-is-outrageous': True}> 58 """ 59
60 - def __setitem__(self, attr, value):
61 if attr in dict.__dict__: 62 raise AttributeError( 63 "Cannot set property %r, it's a dictionary attribute" 64 % (attr, )) 65 dict.__setitem__(self, attr, value)
66
67 - def __setattr__(self, attr, value):
68 self[attr.replace('_', '-')] = value
69
70 - def __getattr__(self, attr):
71 attr = attr.replace('_', '-') 72 try: 73 return self[attr] 74 except KeyError: 75 raise AttributeError( 76 "%r object has no attribute %r" % ( 77 self, attr))
78
79 - def __delattr__(self, attr):
80 del self[attr.replace('_', '-')]
81
82 - def __contains__(self, value):
83 return dict.__contains__(self, value.replace('_', '-'))
84
85 - def __repr__(self):
86 return '<Properties %r>' % (dict.__repr__(self), )
87
88 89 -class Component(object, log.Loggable):
90 """I am a Component. 91 A component has a name which identifies it and must be unique 92 within a flow. 93 A component has a list of feeders and a list of eaters and must 94 belong to a worker. The feeder list or the eater list can be empty, 95 but not both at the same time. 96 @cvar eaterType: restrict the eaters which can be linked with this 97 component to this type 98 @cvar feederType: restrict the feeders which can be linked with this 99 component to this type 100 @cvar componentType: the type of the component, such as ogg-muxer, 101 this is not mandatory in the class, can also be set in the instance. 102 @cvar isAtmosphereComponent: if this component should live in 103 the atmosphere instead of in a flow 104 @ivar name: name of the component 105 @ivar exists: if the component already exists, if this is set to true, 106 a configuration saver or validator might chose to ignore this component 107 """ 108 eaterType = None 109 feederType = None 110 componentType = None 111 isAtmosphereComponent = False 112
113 - def __init__(self, worker=None):
114 self.name = None 115 self.worker = worker 116 self.feeders = [] 117 self.eaters = [] 118 self.properties = Properties() 119 self.plugs = [] 120 self.exists = False
121
122 - def __repr__(self):
123 return '<%s.%s name=%r>' % (self.__class__.__module__, 124 self.__class__.__name__, self.name)
125
126 - def __eq__(self, other):
127 if not isinstance(other, Component): 128 return False 129 130 return (self.worker == other.worker and 131 self.componentType == other.componentType)
132
133 - def __ne__(self, other):
134 return not self.__eq__(other)
135 136 # Backwards compatibility 137 138 @property
139 - def component_type(self):
140 import warnings 141 warnings.warn('Use %s.componentType' % (self.__class__.__name, ), 142 DeprecationWarning, stacklevel=2) 143 return self.componentType
144
145 - def validate(self):
146 if not self.worker: 147 raise ComponentValidationError( 148 "component %s must have a worker set" % (self.name, ))
149
150 - def getWorker(self):
151 return self.worker
152
153 - def getProperties(self):
154 return Properties(self.properties)
155
156 - def getPlugs(self):
157 return self.plugs
158
159 - def addPlug(self, plug):
160 """ 161 Add a plug to the component 162 @param plug: the plug 163 @type plug: L{Plug} 164 """ 165 self.plugs.append(plug)
166
167 - def delPlug(self, plug):
168 plug in self.plugs and self.plugs.remove(plug)
169 180 192
193 - def getEaters(self):
194 """Get the names of all the eaters for this component 195 @returns: feeder names 196 """ 197 198 # Figure out the feeder names to use. 199 # Ask the feeder component which name it wants us to use 200 for source in self.eaters: 201 feederName = source.getFeederName(self) 202 if feederName is None: 203 feederName = '' 204 else: 205 feederName = ':' + feederName 206 207 yield source.name + feederName
208
209 - def getFeederName(self, component):
210 """Get the feeder name a component should use to link to 211 @param component: the component who links to this 212 @type component: L{Component} subclass 213 @returns: feeder name 214 @rtype: string 215 """
216
217 218 -class Plug(object):
219 """I am a Plug. 220 A plug has a name which identifies it and must be unique 221 within a flow. 222 @cvar plugType: the type of the plug, such as cortado, 223 this is not mandatory in the class, can also be set in the instance. 224 """ 225
226 - def __init__(self):
227 self.properties = Properties()
228
229 - def getProperties(self):
230 return Properties(self.properties)
231
232 233 -class Producer(Component):
234 """I am a component which produces data. 235 """ 236
237 - def validate(self):
238 super(Producer, self).validate() 239 240 if self.eaters: 241 raise ComponentValidationError( 242 "producer component %s can not have any eaters" % 243 (self.name, )) 244 245 if not self.feeders: 246 log.debug("component-validation", 247 "producer component %s doesn't have any feeder" % 248 (self.name, ))
249
250 - def getProperties(self):
251 properties = super(Producer, self).getProperties() 252 if 'framerate' in properties: 253 # Convert framerate to fraction 254 try: 255 framerate = fractionFromValue(properties['framerate']) 256 except ValueError: 257 pass 258 else: 259 properties['framerate'] = "%d/%d" % framerate 260 return properties
261
262 263 -class Encoder(Component):
264 """I am a component which encodes data 265 """ 266
267 - def validate(self):
268 super(Encoder, self).validate() 269 270 if not self.eaters: 271 raise ComponentValidationError( 272 "encoder component %s must have at least one eater" % 273 (self.name, )) 274 275 if not self.feeders: 276 log.debug("component-validation", 277 "encoder component %s doesn't have any feeder" % 278 (self.name, ))
279
280 281 -class Muxer(Component):
282 """I am a component which muxes data from different components together. 283 """ 284
285 - def validate(self):
286 super(Muxer, self).validate() 287 288 if not self.eaters: 289 raise ComponentValidationError( 290 "muxer component %s must have at least one eater" % 291 (self.name, )) 292 293 if not self.feeders: 294 log.debug("component-validation", 295 "muxer component %s doesn't have any feeder" % 296 (self.name, ))
297
298 299 -class Consumer(Component):
300 eaterType = Muxer 301 requiresPorter = False 302 prefix = "consumer" 303
304 - def __init__(self, worker=None):
305 Component.__init__(self, worker) 306 self._porter = None
307
308 - def validate(self):
309 super(Consumer, self).validate() 310 311 if not self.isAtmosphereComponent: 312 if not self.eaters: 313 raise ComponentValidationError( 314 "consumer component %s must have at least one eater" % 315 (self.name, )) 316 if self.feeders: 317 raise ComponentValidationError( 318 "consumer component %s cannot have feeders" % 319 (self.name, ))
320
321 - def setPorter(self, porter):
322 self._porter = porter
323
324 - def getPorter(self):
325 return self._porter
326
327 328 -class AudioProducer(Producer):
329 """I am a component which produces audio 330 """ 331
332 - def getSamplerate(self):
333 """Get the samplerate audio producer 334 @returns: the samplerate 335 @rtype: int 336 """ 337 return self.getProperties().samplerate
338
339 340 -class VideoProducer(Producer):
341 """I am a component which produces video 342 """ 343
344 - def getFramerate(self):
345 """Get the framerate video producer 346 @returns: the framerate 347 @rtype: fraction: 2 sized tuple of two integers 348 """ 349 return fractionFromValue(self.getProperties().framerate)
350
351 - def getWidth(self):
352 """Get the width of the video producer 353 @returns: the width 354 @rtype: integer 355 """ 356 return self.getProperties().width
357
358 - def getHeight(self):
359 """Get the height of the video producer 360 @returns: the height 361 @rtype: integer 362 """ 363 return self.getProperties().height
364
365 366 -class VideoConverter(Component):
367 """I am a component which converts video 368 """
369
370 371 -class AudioEncoder(Encoder):
372 """I am a component which encodes audio 373 """ 374 375 eaterType = AudioProducer
376
377 378 -class VideoEncoder(Encoder):
379 """I am a component which encodes video 380 """ 381 382 eaterType = VideoProducer
383
384 385 -class HTTPServer(Component):
386 componentType = 'http-server' 387 isAtmosphereComponent = True 388
389 - def __init__(self, worker, mountPoint):
390 """ 391 @param mountPoint: 392 @type mountPoint: 393 """ 394 super(HTTPServer, self).__init__(worker=worker) 395 396 self.properties.mount_point = mountPoint
397
398 399 -class HTTPPlug(Plug):
400
401 - def __init__(self, server, streamer, audioProducer, videoProducer):
402 """ 403 @param server: server 404 @type server: L{HTTPServer} subclass 405 @param streamer: streamer 406 @type streamer: L{HTTPStreamer} 407 @param audioProducer: audio producer 408 @type audioProducer: L{flumotion.admin.assistant.models.AudioProducer} 409 subclass or None 410 @param videoProducer: video producer 411 @type videoProducer: L{flumotion.admin.assistant.models.VideoProducer} 412 subclass or None 413 """ 414 super(HTTPPlug, self).__init__() 415 self.server = server 416 self.streamer = streamer 417 self.audioProducer = audioProducer 418 self.videoProducer = videoProducer
419
420 421 -class Porter(Component):
422 """I am a model representing the configuration file for a 423 porter component. 424 """ 425 componentType = 'porter' 426 isAtmosphereComponent = True 427
428 - def __init__(self, worker, port, username=None, password=None, 429 socketPath=None):
430 super(Porter, self).__init__(worker=worker) 431 432 self.properties.port = port 433 if username is None: 434 username = _generateRandomString(12) 435 self.properties.username = username 436 437 if password is None: 438 password = _generateRandomString(12) 439 self.properties.password = password 440 441 if socketPath is None: 442 socketPath = 'flu-%s.socket' % (_generateRandomString(6), ) 443 self.properties.socket_path = socketPath
444 445 # Public API 446
447 - def getPort(self):
448 return self.properties.port
449
450 - def getSocketPath(self):
451 return self.properties.socket_path
452
453 - def getUsername(self):
454 return self.properties.username
455
456 - def getPassword(self):
457 return self.properties.password
458 459 # Component 460
461 - def getProperties(self):
462 properties = super(Porter, self).getProperties() 463 properties.port = int(properties.port) 464 return properties
465