Package flumotion :: Package wizard :: Module models
[hide private]

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