Package flumotion :: Package component :: Package bouncers :: Package algorithms :: Module icalbouncer
[hide private]

Source Code for Module flumotion.component.bouncers.algorithms.icalbouncer

  1  # -*- Mode: Python;  test-case-name: flumotion.test.test_icalbouncer -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007 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  """ 
 23  A bouncer that only lets in during an event scheduled with an ical file. 
 24  """ 
 25   
 26  from datetime import datetime, timedelta 
 27   
 28  from twisted.internet import defer 
 29   
 30  from flumotion.common import keycards, messages, errors 
 31  from flumotion.common import log, documentation 
 32  from flumotion.common import eventcalendar 
 33  from flumotion.common.i18n import N_, gettexter 
 34  from flumotion.component.base import scheduler 
 35  from flumotion.component.bouncers.algorithms import base 
 36   
 37  __all__ = ['IcalBouncerAlgorithm'] 
 38  __version__ = "$Rev$" 
 39  T_ = gettexter() 
 40   
 41   
42 -class IcalBouncerAlgorithm(base.BouncerAlgorithm):
43 44 logCategory = 'icalbouncer' 45 events = [] 46 maxKeyCardDuration = timedelta(days=1) 47
48 - def get_namespace(self):
49 return 'icalbouncer'
50
51 - def start(self, component):
52 self.props = self.args['properties'] 53 self.iCalScheduler = None 54 self.subscriptionToken = None 55 self.check_properties(component) 56 self.setup(component)
57
58 - def check_properties(self, component):
59 60 def missingModule(moduleName): 61 m = messages.Error(T_(N_( 62 "To use the iCalendar bouncer you need to have " 63 "the '%s' module installed.\n"), moduleName), 64 mid='error-python-%s' % moduleName) 65 documentation.messageAddPythonInstall(m, moduleName) 66 component.addMessage(m)
67 68 if not eventcalendar.HAS_ICALENDAR: 69 missingModule('icalendar') 70 if not eventcalendar.HAS_DATEUTIL: 71 missingModule('dateutil')
72
73 - def setup(self, component):
74 self._icsfile = self.props['file'] 75 76 try: 77 handle = open(self._icsfile, 'r') 78 except IOError, e: 79 m = messages.Error(T_(N_( 80 "Failed to open iCalendar file '%s'. " 81 "Check permissions on that file."), self._icsfile), 82 mid='error-icalbouncer-file') 83 component.addMessage(m) 84 raise errors.ComponentSetupHandledError() 85 86 try: 87 self.iCalScheduler = scheduler.ICalScheduler(handle) 88 except (ValueError, IndexError, KeyError), e: 89 m = messages.Error(T_(N_( 90 "Error parsing ical file '%s'."), self._icsfile), 91 debug=log.getExceptionMessage(e), 92 mid="error-icalbouncer-file") 93 component.addMessage(m) 94 raise errors.ComponentSetupHandledError() 95 self.subscriptionToken = \ 96 self.iCalScheduler.subscribe(self._do_nothing, self._eventEnded)
97
98 - def authenticate(self, keycard):
99 self.debug('authenticating keycard') 100 101 # need to check if inside an event time 102 cal = self.iCalScheduler.getCalendar() 103 now = datetime.now(eventcalendar.UTC) 104 eventInstances = cal.getActiveEventInstances() 105 if not eventInstances: 106 keycard.state = keycards.REFUSED 107 self.info("failed in authentication, outside hours") 108 return None 109 last_end = now 110 while eventInstances: 111 # decorate-sort-undecorate to get the event ending last 112 instance = max([(ev.end, ev) for ev in eventInstances])[1] 113 duration = instance.end - now 114 115 if duration > self.maxKeyCardDuration: 116 duration = self.maxKeyCardDuration 117 break 118 if last_end == instance.end: 119 break 120 eventInstances = cal.getActiveEventInstances(instance.end) 121 last_end = instance.end 122 123 durationSecs = duration.days * 86400 + duration.seconds 124 keycard.duration = durationSecs 125 keycard.state = keycards.AUTHENTICATED 126 self.info("authenticated login, duration %d seconds", 127 durationSecs) 128 return keycard
129
130 - def stop(self, component):
131 # we might not have an iCalScheduler, if something went wrong 132 # during do_setup or do_check 133 if self.iCalScheduler: 134 self.iCalScheduler.cleanup() 135 if self.subscriptionToken: 136 self.iCalScheduler.unsubscribe(self.subscriptionToken) 137 self.subscriptionToken = None
138
139 - def _eventEnded(self, event):
140 self.debug("_eventEnded") 141 if not event.start < datetime.now(eventcalendar.UTC) < event.end: 142 return 143 cal = self.iCalScheduler.getCalendar() 144 eventInstances = cal.getActiveEventInstances() 145 if not eventInstances: 146 self.debug("We're now outside hours, revoking all keycards") 147 self._expire_all_keycards()
148
149 - def _expire_all_keycards(self):
150 self.expire(self.keycards.keys())
151
152 - def _do_nothing(self, _):
153 pass
154