Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Lars Kruse
aura-engine
Commits
3e7594e5
Commit
3e7594e5
authored
Jul 08, 2021
by
david
Browse files
Fix for preloading. #78
parent
a9d38e79
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/control.py
View file @
3e7594e5
...
...
@@ -184,21 +184,23 @@ class EngineExecutor(Timer):
Primarily used for automations performed by the scheduler.
"""
_lock
=
None
timer_store
:
dict
=
{}
logger
=
logging
.
getLogger
(
"AuraEngine"
)
initialized
=
None
timer_store
=
{}
parent_timer
=
None
child_timer
=
None
direct_exec
=
None
timer_id
=
None
timer_type
=
None
EVENT_ON_READY
=
"on_ready"
_lock
=
None
direct_exec
:
bool
=
None
parent_timer
:
Timer
=
None
child_timer
:
Timer
=
None
timer_id
:
str
=
None
timer_type
:
str
=
None
func
=
None
param
=
None
diff
=
None
dt
=
None
def
__init__
(
self
,
timer_type
=
"BASE"
,
parent_timer
=
None
,
due_time
=
None
,
func
=
None
,
param
=
None
):
def
__init__
(
self
,
timer_type
:
str
=
"BASE"
,
parent_timer
:
Timer
=
None
,
due_time
=
None
,
func
=
None
,
param
=
None
):
"""
Constructor
...
...
@@ -209,7 +211,6 @@ class EngineExecutor(Timer):
func (function): The function to be called
param (object): Parameter passt to the function
"""
self
.
initialized
=
False
self
.
_lock
=
Lock
()
from
src.engine
import
Engine
now_unix
=
Engine
.
engine_time
()
...
...
@@ -224,9 +225,8 @@ class EngineExecutor(Timer):
self
.
timer_type
=
timer_type
self
.
timer_id
=
f
"
{
timer_type
}
:
{
func
.
__name__
}
:
{
due_time
}
"
if
not
due_time
:
diff
=
0
else
:
diff
=
0
if
due_time
:
diff
=
due_time
-
now_unix
self
.
diff
=
diff
...
...
@@ -240,32 +240,22 @@ class EngineExecutor(Timer):
else
:
if
diff
<
0
:
msg
=
f
"Timer '
{
self
.
timer_id
}
' is due in the past. Executing immediately ..."
self
.
logger
.
error
(
SU
.
red
(
msg
))
self
.
logger
.
warn
(
SU
.
yellow
(
msg
))
self
.
exec_now
()
elif
diff
==
0
:
self
.
logger
.
info
(
f
"Timer '
{
self
.
timer_id
}
' to be executed immediately"
)
self
.
logger
.
debug
(
f
"Timer '
{
self
.
timer_id
}
' to be executed immediately"
)
self
.
exec_now
()
else
:
self
.
logger
.
debug
(
f
"Timer '
{
self
.
timer_id
}
' to be executed in default manner"
)
self
.
exec_timed
()
self
.
start
()
def
on_ready
(
self
,
func
):
"""
Calls the passed function `func` when the timer is ready.
"""
while
self
.
initialized
==
False
:
timer
.
sleep
(
0.001
)
self
.
logger
.
info
(
SU
.
orange
(
"Waiting until the EngineExecutor is done with initialization..."
))
if
not
self
.
direct_exec
:
#TODO Evaluate if we should join for direct exec too
self
.
join
()
func
()
def
wait_for_parent
(
self
):
"""
Child timers are dependend on their parents. So let's wait until parents are done with their stuff.
@private
Child timers are dependend on their parents. So let's wait until parents are done with their stuff => finished execution.
Checks the parent state to be finished every 0.2 seconds.
"""
if
self
.
parent_timer
:
while
self
.
parent_timer
.
is_alive
():
...
...
@@ -275,22 +265,27 @@ class EngineExecutor(Timer):
def
exec_now
(
self
):
"""
@private
Immediate execution within a thread. It's not stored in the timer store.
A
ssigns the `timer_id` as the thread name.
It also a
ssigns the `timer_id` as the thread name.
"""
self
.
direct_exec
=
True
self
.
wait_for_parent
()
thread
=
Thread
(
name
=
self
.
timer_id
,
target
=
self
.
func
,
args
=
(
self
.
param
,))
time
.
sleep
(
0.2
)
thread
.
start
()
self
.
initialized
=
True
def
exec_timed
(
self
):
"""
Timed execution in a thread.
@private
Assigns the `timer_id` as the thread name.
Timed execution in a thread. This method instroduces a slight delay to ensure
the thread is properly initialized before starting it.
It also assigns the `timer_id` as the thread name.
"""
def
wrapper_func
(
param
=
None
):
self
.
wait_for_parent
()
...
...
@@ -298,18 +293,22 @@ class EngineExecutor(Timer):
else
:
self
.
func
()
super
().
__init__
(
self
.
diff
,
wrapper_func
,
(
self
.
param
,))
self
.
_name
=
self
.
timer_id
self
.
initialized
=
True
time
.
sleep
(
0.2
)
self
.
start
()
def
update_store
(
self
):
"""
@private
Adds the instance to the store and cancels any previously existing commands.
If a timer with the given ID is already existing but also already executed,
then it is not added to the store. In such case the method returns `False`.
Returns:
(Boolean): True if the timer has been added to the store
(Boolean): True if the timer has been added to the store. False if the
timer is already existing but dead.
"""
with
self
.
_lock
:
existing_command
=
None
...
...
@@ -337,6 +336,8 @@ class EngineExecutor(Timer):
def
is_alive
(
self
):
"""
@private
Returns true if the command is still due to be executed.
"""
if
self
.
direct_exec
==
True
:
...
...
@@ -346,7 +347,7 @@ class EngineExecutor(Timer):
def
__str__
(
self
):
"""
String represenation of the timer.
String represen
t
ation of the timer.
"""
return
f
"[
{
self
.
timer_id
}
] exec at
{
str
(
self
.
dt
)
}
(alive:
{
self
.
is_alive
()
}
)"
...
...
@@ -372,7 +373,7 @@ class EngineExecutor(Timer):
@
staticmethod
def
log_commands
():
"""
Prints a list of recent active and inactive timers.
Prints a list of recent active and inactive timers
to the logger
.
"""
msg
=
SU
.
blue
(
"
\n
[ ENGINE COMMAND QUEUE ]
\n
"
)
EngineExecutor
.
remove_stale_timers
()
...
...
@@ -383,7 +384,7 @@ class EngineExecutor(Timer):
else
:
for
timer
in
timers
:
if
not
timer
.
parent_timer
:
line
=
f
" =>
{
str
(
timer
)
}
\n
"
#
line
=
f
" =>
{
str
(
timer
)
}
\n
"
if
timer
.
is_alive
():
line
=
SU
.
green
(
line
)
msg
+=
line
...
...
src/scheduling/scheduler.py
View file @
3e7594e5
...
...
@@ -45,17 +45,16 @@ class AuraScheduler(threading.Thread):
- Executes engine actions in an automated fashion
"""
config
=
None
config
:
AuraConfig
=
None
logger
=
None
engine
=
None
exit_event
=
None
timeslot_renderer
=
None
programme
=
None
engine
:
Engine
=
None
exit_event
:
threading
.
Event
=
None
timeslot_renderer
:
TimeslotRenderer
=
None
programme
:
ProgrammeService
=
None
message_timer
=
[]
fallback
=
None
is_initialized
=
None
is_initialized
=
None
is_initialized
:
bool
=
None
is_engine_ready
:
bool
=
None
def
__init__
(
self
,
engine
,
fallback_manager
):
...
...
@@ -407,10 +406,11 @@ class TimeslotCommand(EngineExecutor):
"""
Command for triggering start and end of timeslot events.
"""
engine
=
None
config
=
None
engine
:
Engine
=
None
config
:
AuraConfig
=
None
def
__init__
(
self
,
engine
,
timeslot
):
def
__init__
(
self
,
engine
:
Engine
,
timeslot
):
"""
Constructor
...
...
@@ -421,12 +421,15 @@ class TimeslotCommand(EngineExecutor):
self
.
config
=
AuraConfig
()
self
.
engine
=
engine
now_unix
=
SU
.
timestamp
()
fade_out_time
=
float
(
self
.
config
.
get
(
"fade_out_time"
))
start_fade_out
=
timeslot
.
end_unix
-
fade_out_time
self
.
logger
.
info
(
f
"Fading out timeslot in
{
start_fade_out
}
seconds at
{
timeslot
.
timeslot_end
}
| Timeslot:
{
timeslot
}
"
)
# Initialize the "fade in" EngineExecuter and instatiate a connected child EngineExecuter for "fade out" when the parent is ready
start_fade_in
=
timeslot
.
start_unix
-
now_unix
start_fade_out
=
timeslot
.
end_unix
-
now_unix
-
fade_out_time
self
.
logger
.
debug
(
f
"Fading in timeslot in
{
start_fade_in
}
seconds at
{
SU
.
fmt_time
(
timeslot
.
start_unix
)
}
| Timeslot:
{
timeslot
}
"
)
self
.
logger
.
debug
(
f
"Fading out timeslot in
{
start_fade_out
}
seconds at
{
SU
.
fmt_time
(
timeslot
.
end_unix
-
fade_out_time
)
}
| Timeslot:
{
timeslot
}
"
)
# Initialize the "fade in" EngineExecuter and instantiate a connected child EngineExecuter for "fade out" when the parent is ready
super
().
__init__
(
"TIMESLOT"
,
None
,
timeslot
.
start_unix
,
self
.
do_start_timeslot
,
timeslot
)
self
.
on_ready
(
lambda
:
EngineExecutor
(
"TIMESLOT"
,
self
,
start_
fade_out
,
self
.
do_end_timeslot
,
timeslot
)
)
EngineExecutor
(
"TIMESLOT"
,
self
,
timeslot
.
end_unix
-
fade_out
_time
,
self
.
do_end_timeslot
,
timeslot
)
def
do_start_timeslot
(
self
,
timeslot
):
...
...
@@ -456,10 +459,11 @@ class PlayCommand(EngineExecutor):
"""
Command for triggering timed preloading and playing as a child command.
"""
engine
=
None
config
=
None
engine
:
Engine
=
None
config
:
AuraConfig
=
None
def
__init__
(
self
,
engine
,
entries
):
def
__init__
(
self
,
engine
:
Engine
,
entries
):
"""
Constructor
...
...
@@ -470,11 +474,13 @@ class PlayCommand(EngineExecutor):
self
.
config
=
AuraConfig
()
self
.
engine
=
engine
start_preload
=
entries
[
0
].
start_unix
-
self
.
config
.
get
(
"preload_offset"
)
preload_offset
=
self
.
config
.
get
(
"preload_offset"
)
start_preload
=
entries
[
0
].
start_unix
-
preload_offset
start_play
=
entries
[
0
].
start_unix
self
.
logger
.
debug
(
f
"Preloading entries at
{
SU
.
fmt_time
(
start_preload
)
}
,
{
preload_offset
}
seconds before playing it at
{
SU
.
fmt_time
(
start_play
)
}
"
)
# Initialize the "preload" EngineExecuter and attach a child `PlayCommand` to the "on_ready" event handler
preload_timer
=
super
().
__init__
(
"PRELOAD"
,
None
,
start_preload
,
self
.
do_preload
,
entries
)
self
.
on_ready
(
lambda
:
EngineExecutor
(
"PLAY"
,
self
,
start_play
,
self
.
do_play
,
entries
)
)
super
().
__init__
(
"PRELOAD"
,
None
,
start_preload
,
self
.
do_preload
,
entries
)
EngineExecutor
(
"PLAY"
,
self
,
start_play
,
self
.
do_play
,
entries
)
def
do_preload
(
self
,
entries
):
...
...
@@ -504,7 +510,7 @@ class PlayCommand(EngineExecutor):
# Let 'em play anyway ...
self
.
logger
.
critical
(
SU
.
red
(
"PLAY: The entry/entries are not yet ready to be played (Entries: %s)"
%
ResourceUtil
.
get_entries_string
(
entries
)))
while
(
entries
[
-
1
].
status
!=
EntryPlayState
.
READY
):
self
.
logger
.
info
(
"PLAY: Wait a little until preloading is done ..."
)
self
.
logger
.
info
(
"PLAY: Wait a little
bit
until preloading is done ..."
)
time
.
sleep
(
2
)
self
.
engine
.
player
.
play
(
entries
[
0
],
TransitionType
.
FADE
)
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment