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: 7738 $" 
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 # Backwards compatibility 130 131 @property
132 - def component_type(self):
133 import warnings 134 warnings.warn('Use %s.componentType' % (self.__class__.__name, ), 135 DeprecationWarning, stacklevel=2) 136 return self.componentType
137
138 - def validate(self):
139 if not self.worker: 140 raise ComponentValidationError( 141 "component %s must have a worker set" % (self.name, ))
142
143 - def getWorker(self):
144 return self.worker
145
146 - def getProperties(self):
147 return Properties(self.properties)
148
149 - def getPlugs(self):
150 return self.plugs
151
152 - def addPlug(self, plug):
153 """ 154 Add a plug to the component 155 @param plug: the plug 156 @type plug: L{Plug} 157 """ 158 self.plugs.append(plug)
159 170 182
183 - def getEaters(self):
184 """Get the names of all the eaters for this component 185 @returns: feeder names 186 """ 187 188 # Figure out the feeder names to use. 189 # Ask the feeder component which name it wants us to use 190 for source in self.eaters: 191 feederName = source.getFeederName(self) 192 if feederName is None: 193 feederName = '' 194 else: 195 feederName = ':' + feederName 196 197 yield source.name + feederName
198
199 - def getFeederName(self, component):
200 """Get the feeder name a component should use to link to 201 @param component: the component who links to this 202 @type component: L{Component} subclass 203 @returns: feeder name 204 @rtype: string 205 """
206
207 208 -class Plug(object):
209 """I am a Plug. 210 A plug has a name which identifies it and must be unique 211 within a flow. 212 @cvar plugType: the type of the plug, such as cortado, 213 this is not mandatory in the class, can also be set in the instance. 214 """ 215
216 - def __init__(self):
217 self.properties = Properties()
218
219 - def getProperties(self):
220 return Properties(self.properties)
221
222 223 -class Producer(Component):
224 """I am a component which produces data. 225 """ 226
227 - def validate(self):
228 super(Producer, self).validate() 229 230 if self.eaters: 231 raise ComponentValidationError( 232 "producer component %s can not have any easters" % 233 (self.name, )) 234 235 if not self.feeders: 236 log.debug("component-validation", 237 "producer component %s doesn't have any feeder" % 238 (self.name, ))
239
240 - def getProperties(self):
241 properties = super(Producer, self).getProperties() 242 if 'framerate' in properties: 243 # Convert framerate to fraction 244 try: 245 framerate = fractionFromValue(properties['framerate']) 246 except ValueError: 247 pass 248 else: 249 properties['framerate'] = "%d/%d" % framerate 250 return properties
251
252 253 -class Encoder(Component):
254 """I am a component which encodes data 255 """ 256
257 - def validate(self):
258 super(Encoder, self).validate() 259 260 if not self.eaters: 261 raise ComponentValidationError( 262 "encoder component %s must have at least one eater" % 263 (self.name, )) 264 265 if not self.feeders: 266 log.debug("component-validation", 267 "encoder component %s doesn't have any feeder" % 268 (self.name, ))
269
270 271 -class Muxer(Component):
272 """I am a component which muxes data from different components together. 273 """ 274
275 - def validate(self):
276 super(Muxer, self).validate() 277 278 if not self.eaters: 279 raise ComponentValidationError( 280 "muxer component %s must have at least one eater" % 281 (self.name, )) 282 283 if not self.feeders: 284 log.debug("component-validation", 285 "muxer component %s doesn't have any feeder" % 286 (self.name, ))
287
288 289 -class Consumer(Component):
290 eaterType = Muxer 291
292 - def __init__(self, worker=None):
293 Component.__init__(self, worker) 294 self._porter = None
295
296 - def validate(self):
297 super(Consumer, self).validate() 298 299 if not self.isAtmosphereComponent: 300 if not self.eaters: 301 raise ComponentValidationError( 302 "consumer component %s must have at least one eater" % 303 (self.name, )) 304 if self.feeders: 305 raise ComponentValidationError( 306 "consumer component %s cannot have feeders" % 307 (self.name, ))
308
309 - def setPorter(self, porter):
310 self._porter = porter
311
312 - def getPorter(self):
313 return self._porter
314
315 316 -class AudioProducer(Producer):
317 """I am a component which produces audio 318 """
319
320 321 -class VideoProducer(Producer):
322 """I am a component which produces video 323 """ 324
325 - def getFramerate(self):
326 """Get the framerate video producer 327 @returns: the framerate 328 @rtype: fraction: 2 sized tuple of two integers 329 """ 330 return fractionFromValue(self.properties.framerate)
331
332 - def getWidth(self):
333 """Get the width of the video producer 334 @returns: the width 335 @rtype: integer 336 """ 337 return self.properties.width
338
339 - def getHeight(self):
340 """Get the height of the video producer 341 @returns: the height 342 @rtype: integer 343 """ 344 return self.properties.height
345
346 347 -class VideoConverter(Component):
348 """I am a component which converts video 349 """
350
351 352 -class AudioEncoder(Encoder):
353 """I am a component which encodes audio 354 """ 355 356 eaterType = AudioProducer
357
358 359 -class VideoEncoder(Encoder):
360 """I am a component which encodes video 361 """ 362 363 eaterType = VideoProducer
364
365 366 -class HTTPServer(Component):
367 componentType = 'http-server' 368 isAtmosphereComponent = True 369
370 - def __init__(self, worker, mountPoint):
371 """ 372 @param mountPoint: 373 @type mountPoint: 374 """ 375 super(HTTPServer, self).__init__(worker=worker) 376 377 self.properties.mount_point = mountPoint
378
379 380 -class HTTPPlug(Plug):
381
382 - def __init__(self, server, streamer, audioProducer, videoProducer):
383 """ 384 @param server: server 385 @type server: L{HTTPServer} subclass 386 @param streamer: streamer 387 @type streamer: L{HTTPStreamer} 388 @param audioProducer: audio producer 389 @type audioProducer: L{flumotion.admin.assistant.models.AudioProducer} 390 subclass or None 391 @param videoProducer: video producer 392 @type videoProducer: L{flumotion.admin.assistant.models.VideoProducer} 393 subclass or None 394 """ 395 super(HTTPPlug, self).__init__() 396 self.server = server 397 self.streamer = streamer 398 self.audioProducer = audioProducer 399 self.videoProducer = videoProducer
400
401 402 -class Porter(Component):
403 """I am a model representing the configuration file for a 404 porter component. 405 """ 406 componentType = 'porter' 407 isAtmosphereComponent = True 408
409 - def __init__(self, worker, port, username=None, password=None, 410 socketPath=None):
411 super(Porter, self).__init__(worker=worker) 412 413 self.properties.port = port 414 if username is None: 415 username = _generateRandomString(12) 416 self.properties.username = username 417 418 if password is None: 419 password = _generateRandomString(12) 420 self.properties.password = password 421 422 if socketPath is None: 423 socketPath = 'flu-%s.socket' % (_generateRandomString(6), ) 424 self.properties.socket_path = socketPath
425 426 # Public API 427
428 - def getPort(self):
429 return self.properties.port
430
431 - def getSocketPath(self):
432 return self.properties.socket_path
433
434 - def getUsername(self):
435 return self.properties.username
436
437 - def getPassword(self):
438 return self.properties.password
439 440 # Component 441
442 - def getProperties(self):
443 properties = super(Porter, self).getProperties() 444 properties.port = int(properties.port) 445 return properties
446