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