diff options
Diffstat (limited to 'helpers/action.py')
-rw-r--r-- | helpers/action.py | 102 |
1 files changed, 87 insertions, 15 deletions
diff --git a/helpers/action.py b/helpers/action.py index ec8fcb6..a6c48e9 100644 --- a/helpers/action.py +++ b/helpers/action.py | |||
@@ -1,10 +1,11 @@ | |||
1 | import threading | 1 | import threading |
2 | import time | 2 | import time |
3 | 3 | ||
4 | from . import debug_print | 4 | from transitions.extensions import HierarchicalMachine as Machine |
5 | from . import debug_print, error_print | ||
5 | 6 | ||
6 | class Action: | 7 | class Action: |
7 | action_types = [ | 8 | ACTION_TYPES = [ |
8 | 'command', | 9 | 'command', |
9 | 'interrupt_wait', | 10 | 'interrupt_wait', |
10 | 'pause', | 11 | 'pause', |
@@ -17,40 +18,106 @@ class Action: | |||
17 | 'wait', | 18 | 'wait', |
18 | ] | 19 | ] |
19 | 20 | ||
21 | STATES = [ | ||
22 | 'initial', | ||
23 | 'loading', | ||
24 | 'failed', | ||
25 | { | ||
26 | 'name': 'loaded', | ||
27 | 'children': ['running'] | ||
28 | } | ||
29 | ] | ||
30 | |||
31 | TRANSITIONS = [ | ||
32 | { | ||
33 | 'trigger': 'load', | ||
34 | 'source': 'initial', | ||
35 | 'dest': 'loading' | ||
36 | }, | ||
37 | { | ||
38 | 'trigger': 'fail', | ||
39 | 'source': 'loading', | ||
40 | 'dest': 'failed' | ||
41 | }, | ||
42 | { | ||
43 | 'trigger': 'success', | ||
44 | 'source': 'loading', | ||
45 | 'dest': 'loaded' | ||
46 | }, | ||
47 | { | ||
48 | 'trigger': 'run', | ||
49 | 'source': 'loaded', | ||
50 | 'dest': 'loaded_running', | ||
51 | 'after': 'finish_action' | ||
52 | }, | ||
53 | { | ||
54 | 'trigger': 'interrupt', | ||
55 | 'source': 'loaded_running', | ||
56 | 'dest': 'loaded', | ||
57 | 'before': 'trigger_interrupt' | ||
58 | }, | ||
59 | { | ||
60 | 'trigger': 'finish_action', | ||
61 | 'source': 'loaded_running', | ||
62 | 'dest': 'loaded' | ||
63 | } | ||
64 | ] | ||
65 | |||
20 | def __init__(self, action, key, **kwargs): | 66 | def __init__(self, action, key, **kwargs): |
21 | if action in self.action_types: | 67 | Machine(model=self, states=self.STATES, |
22 | self.action = action | 68 | transitions=self.TRANSITIONS, initial='initial', |
23 | else: | 69 | ignore_invalid_triggers=True, queued=True) |
24 | raise Exception("Unknown action {}".format(action)) | ||
25 | 70 | ||
71 | self.action = action | ||
26 | self.key = key | 72 | self.key = key |
27 | self.mapping = key.parent | 73 | self.mapping = key.parent |
28 | self.arguments = kwargs | 74 | self.arguments = kwargs |
29 | self.sleep_event = None | 75 | self.sleep_event = None |
76 | self.waiting_music = None | ||
77 | self.load() | ||
30 | 78 | ||
31 | def ready(self): | 79 | def ready(self): |
32 | if 'music' in self.arguments: | 80 | return self.is_loaded(allow_substates=True) |
33 | return self.arguments['music'].is_loaded(allow_substates=True) | 81 | |
82 | def callback_loaded(self, success): | ||
83 | if success: | ||
84 | self.success() | ||
85 | else: | ||
86 | self.fail() | ||
87 | |||
88 | # Machine states / events | ||
89 | def on_enter_loading(self): | ||
90 | if self.action in self.ACTION_TYPES: | ||
91 | if 'music' in self.arguments: | ||
92 | self.arguments['music'].subscribe_loaded(self.callback_loaded) | ||
93 | else: | ||
94 | self.success() | ||
34 | else: | 95 | else: |
35 | return True | 96 | error_print("Unknown action {}".format(self.action)) |
97 | self.fail() | ||
98 | |||
36 | 99 | ||
37 | def run(self): | 100 | def on_enter_loaded_running(self): |
38 | debug_print(self.description()) | 101 | debug_print(self.description()) |
39 | getattr(self, self.action)(**self.arguments) | 102 | getattr(self, self.action)(**self.arguments) |
40 | 103 | ||
41 | def description(self): | 104 | def trigger_interrupt(self): |
42 | return getattr(self, self.action + "_print")(**self.arguments) | ||
43 | |||
44 | def interrupt(self): | ||
45 | if getattr(self, self.action + "_interrupt", None): | 105 | if getattr(self, self.action + "_interrupt", None): |
46 | return getattr(self, self.action + "_interrupt")(**self.arguments) | 106 | return getattr(self, self.action + "_interrupt")(**self.arguments) |
47 | 107 | ||
108 | # Helpers | ||
48 | def music_list(self, music): | 109 | def music_list(self, music): |
49 | if music is not None: | 110 | if music is not None: |
50 | return [music] | 111 | return [music] |
51 | else: | 112 | else: |
52 | return self.mapping.open_files.values() | 113 | return self.mapping.open_files.values() |
53 | 114 | ||
115 | def description(self): | ||
116 | if getattr(self, self.action + "_print", None): | ||
117 | return getattr(self, self.action + "_print")(**self.arguments) | ||
118 | else: | ||
119 | return "unknown action {}".format(self.action) | ||
120 | |||
54 | # Actions | 121 | # Actions |
55 | def command(self, command="", **kwargs): | 122 | def command(self, command="", **kwargs): |
56 | # FIXME: todo | 123 | # FIXME: todo |
@@ -104,6 +171,7 @@ class Action: | |||
104 | music.stop(fade_out=fade_out) | 171 | music.stop(fade_out=fade_out) |
105 | 172 | ||
106 | if previous is not None: | 173 | if previous is not None: |
174 | self.waiting_music = previous | ||
107 | previous.stop( | 175 | previous.stop( |
108 | fade_out=fade_out, | 176 | fade_out=fade_out, |
109 | wait=wait, | 177 | wait=wait, |
@@ -254,10 +322,14 @@ class Action: | |||
254 | 322 | ||
255 | return message | 323 | return message |
256 | 324 | ||
257 | # Interruptions | 325 | # Interruptions (only for non-"atomic" actions) |
258 | def wait_interrupt(self, duration=0, music=None, **kwargs): | 326 | def wait_interrupt(self, duration=0, music=None, **kwargs): |
259 | if self.sleep_event is not None: | 327 | if self.sleep_event is not None: |
260 | self.sleep_event.set() | 328 | self.sleep_event.set() |
261 | if music is not None: | 329 | if music is not None: |
262 | music.wait_event.set() | 330 | music.wait_event.set() |
263 | 331 | ||
332 | def stop_interrupt(self, music=None, fade_out=0, wait=False, | ||
333 | set_wait_id=None, **kwargs): | ||
334 | if self.waiting_music is not None: | ||
335 | self.waiting_music.wait_event.set() | ||