forked from LUG-Saar/fetapi
Fr3deric
8 years ago
3 changed files with 345 additions and 367 deletions
@ -0,0 +1,327 @@
@@ -0,0 +1,327 @@
|
||||
import threading |
||||
import Queue as queue |
||||
|
||||
class DialConfiguration(object): |
||||
def __init__(self, dial_timeout, shortcuts, blacklist): |
||||
self.dial_timeout = dial_timeout |
||||
self.shortcuts = shortcuts |
||||
self.blacklist = blacklist |
||||
|
||||
class IllegalEventError(Exception): |
||||
pass |
||||
|
||||
|
||||
""" |
||||
An abstract state, needed to define all possible events. |
||||
|
||||
""" |
||||
class AbstractState(object): |
||||
def on_registration_in_progress(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_registration_successful(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_registration_lost(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_gabelschalter_up(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_gabelschalter_down(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_incoming_call(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_call_ended(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_call_accepted(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_call_ringing(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_invalid_number(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_nummernschalter_active(self): |
||||
raise IllegalEventError() |
||||
|
||||
def on_nummernschalter_input(self, num): |
||||
raise IllegalEventError() |
||||
|
||||
def on_timeout(self): |
||||
raise IllegalEventError() |
||||
|
||||
def leave(self): |
||||
return None |
||||
|
||||
|
||||
""" |
||||
The basic state that every other state inherits from. It defines default |
||||
behaviour for some events (overriden if necessary). |
||||
|
||||
""" |
||||
class BaseState(AbstractState): |
||||
def __init__(self, controller): |
||||
self._controller = controller |
||||
|
||||
def on_registration_lost(self): |
||||
return InitState |
||||
|
||||
def on_gabelschalter_up(self): |
||||
return None |
||||
|
||||
def on_gabelschalter_down(self): |
||||
return None |
||||
|
||||
def on_incoming_call(self): |
||||
self._controller.phone.decline_call() |
||||
|
||||
def on_call_ended(self): |
||||
# When an incoming call is declined, a call_ended event occurs, which |
||||
# needs to be ignored, here. |
||||
return None |
||||
|
||||
def on_nummernschalter_active(self): |
||||
return None |
||||
|
||||
def on_nummernschalter_input(self, num): |
||||
return None |
||||
|
||||
|
||||
class InitState(BaseState): |
||||
def __init__(self, controller): |
||||
super(InitState, self).__init__(controller) |
||||
self._controller.feap.set_schauzeichen(True) |
||||
|
||||
def on_registration_in_progress(self): |
||||
print('registration in progress') |
||||
return RegisteringState |
||||
|
||||
class RegisteringState(BaseState): |
||||
def __init__(self, controller): |
||||
super(RegisteringState, self).__init__(controller) |
||||
|
||||
def on_registration_successful(self): |
||||
print('registration successful') |
||||
self._controller.feap.set_schauzeichen(False) |
||||
return IdleState |
||||
|
||||
class IdleState(BaseState): |
||||
def on_incoming_call(self): |
||||
print('incomfing call') |
||||
caller = self._controller.phone.get_remote_number() |
||||
print('From: %s' % caller) |
||||
if caller in self._controller.dialconfig.blacklist: |
||||
print('Caller on blacklist - declining') |
||||
self._controller.phone.decline_call() |
||||
return CallTerminatingState |
||||
else: |
||||
return SchelltState |
||||
|
||||
def on_gabelschalter_up(self): |
||||
print('gabel up') |
||||
return DialingState |
||||
|
||||
class SchelltState(BaseState): |
||||
def __init__(self, controller): |
||||
super(SchelltState, self).__init__(controller) |
||||
self._controller.feap.set_wecker(True) |
||||
|
||||
def leave(self): |
||||
self._controller.feap.set_wecker(False) |
||||
|
||||
def on_gabelschalter_up(self): |
||||
return AcceptingState |
||||
|
||||
def on_call_ended(self): |
||||
return IdleState |
||||
|
||||
class AcceptingState(BaseState): |
||||
def __init__(self, controller): |
||||
super(AcceptingState, self).__init__(controller) |
||||
self._controller.phone.accept_call() |
||||
|
||||
def on_call_accepted(self): |
||||
return CallRunningState |
||||
|
||||
class CallTerminatingState(BaseState): |
||||
def __init__(self, controller): |
||||
super(CallTerminatingState, self).__init__(controller) |
||||
self._controller.phone.end_call() |
||||
|
||||
def on_call_ended(self): |
||||
return IdleState |
||||
|
||||
def on_call_accepted(self): |
||||
return None |
||||
|
||||
class ForgottenState(BaseState): |
||||
def on_gabelschalter_down(self): |
||||
return IdleState |
||||
|
||||
class BusyBeepingState(BaseState): |
||||
def __init__(self, controller): |
||||
super(BusyBeepingState, self).__init__(controller) |
||||
self._controller.phone.play_busy_tone() |
||||
|
||||
def leave(self): |
||||
self._controller.phone.stop_playing() |
||||
|
||||
def on_timeout(self): |
||||
return ForgottenState |
||||
|
||||
def on_gabelschalter_down(self): |
||||
return IdleState |
||||
|
||||
class CallRunningState(BaseState): |
||||
def on_gabelschalter_down(self): |
||||
return CallTerminatingState |
||||
|
||||
def on_call_ended(self): |
||||
return BusyBeepingState |
||||
|
||||
class WecktState(BaseState): |
||||
def __init__(self, controller): |
||||
super(WecktState, self).__init__(controller) |
||||
self._controller.phone.play_ringback_tone() |
||||
|
||||
def leave(self): |
||||
self._controller.phone.stop_playing() |
||||
|
||||
def on_gabelschalter_down(self): |
||||
return CallTerminatingState |
||||
|
||||
def on_call_ended(self): |
||||
return BusyBeepingState |
||||
|
||||
def on_call_accepted(self): |
||||
return CallRunningState |
||||
|
||||
class ConnectingState(BaseState): |
||||
def on_gabelschalter_down(self): |
||||
return CallTerminatingState |
||||
|
||||
def on_call_ringing(self): |
||||
return WecktState |
||||
|
||||
def on_call_accepted(self): |
||||
return CallRunningState |
||||
|
||||
def on_invalid_number(self): |
||||
# TODO: play sound |
||||
return BusyBeepingState |
||||
|
||||
def on_call_ended(self): |
||||
return BusyBeepingState |
||||
|
||||
class DialingState(BaseState): |
||||
def __init__(self, controller): |
||||
super(DialingState, self).__init__(controller) |
||||
self._controller.phone.play_dial_tone() |
||||
self.__dial_tone = True |
||||
self.__number = '' |
||||
|
||||
def leave(self): |
||||
if self.__dial_tone: |
||||
self._controller.phone.stop_playing() |
||||
self._controller.abort_timeout() |
||||
|
||||
def on_gabelschalter_down(self): |
||||
return IdleState |
||||
|
||||
def on_nummernschalter_active(self): |
||||
self._controller.abort_timeout() |
||||
if self.__dial_tone: |
||||
self._controller.phone.stop_playing() |
||||
|
||||
def on_nummernschalter_input(self, num): |
||||
print('nummernschalter: %d' % (num)) |
||||
if self.__dial_tone: |
||||
self._controller.phone.stop_playing() |
||||
self.__number += str(num) |
||||
self._controller.abort_timeout() |
||||
self._controller.set_timeout(self._controller.dialconfig.dial_timeout * 1000) |
||||
self._controller.phone.read_text(str(num)) |
||||
|
||||
def on_timeout(self): |
||||
number = self.__number |
||||
print 'Dialing number:', number |
||||
if number in self._controller.dialconfig.shortcuts: |
||||
number = self._controller.dialconfig.shortcuts[number] |
||||
print 'shortcut resolved:', number |
||||
self._controller.phone.call(number) |
||||
return ConnectingState |
||||
|
||||
|
||||
class StateMachineController(object): |
||||
def __init__(self, phone, feap, dialconfig): |
||||
self.__phone = phone |
||||
self.__feap = feap |
||||
self.__dialconfig = dialconfig |
||||
|
||||
self.__state = InitState(self) |
||||
|
||||
self.__timeout = None |
||||
|
||||
self.__running = True |
||||
self.__evqueue = queue.Queue() |
||||
self.__evthread = threading.Thread(target=self.__event_dispatcher) |
||||
self.__evthread.start() |
||||
|
||||
def __event_dispatcher(self): |
||||
while self.__running: |
||||
(evname, evargs, evkwargs) = self.__evqueue.get() |
||||
if not evname: |
||||
return |
||||
|
||||
print('!!! event: %s' % (evname)) |
||||
handler = getattr(self.__state, 'on_%s' % (evname)) |
||||
try: |
||||
newstate = handler(*evargs, **evkwargs) |
||||
except IllegalEventError: |
||||
print('illegal event occured!!!!!!!!!!!!!!!!!!!!', self.__state.__class__.__name__) |
||||
if not newstate: |
||||
continue |
||||
|
||||
self.__state.leave() |
||||
self.abort_timeout() |
||||
|
||||
oldstate = self.__state.__class__ |
||||
print('%s -> %s' % (oldstate.__name__, newstate.__name__)) |
||||
self.__state = newstate(self) |
||||
|
||||
def queue_event(self, evname, *evargs, **evkwargs): |
||||
if not hasattr(AbstractState, 'on_%s' % (evname)): |
||||
raise ValueError('Illegal event name: %s' % (evname)) |
||||
self.__evqueue.put((evname, evargs, evkwargs)) |
||||
|
||||
def set_timeout(self, timeout): |
||||
self.__timeout = threading.Timer(timeout/1000, self.queue_event, args=['timeout']) |
||||
self.__timeout.start() |
||||
|
||||
def abort_timeout(self): |
||||
if self.__timeout: |
||||
self.__timeout.cancel() |
||||
self.__timeout = None |
||||
|
||||
@property |
||||
def phone(self): |
||||
return self.__phone |
||||
|
||||
@property |
||||
def feap(self): |
||||
return self.__feap |
||||
|
||||
@property |
||||
def dialconfig(self): |
||||
return self.__dialconfig |
||||
|
||||
def stop(self, hard=False): |
||||
if hard: |
||||
self.__running = False |
||||
self.__evqueue.put((None, None, None)) |
||||
|
Loading…
Reference in new issue