Commit 2b6ebefd authored by david's avatar david
Browse files

Merge branch 'master' into 'lars-debian-deployment'

# Conflicts:
#   docs/bare-metal-installation.md
parents 31c5f72c 9afa33f0
Pipeline #1161 passed with stage
in 1 minute and 10 seconds
...@@ -11,4 +11,4 @@ env.list ...@@ -11,4 +11,4 @@ env.list
audio audio
python python
__pycache__ __pycache__
config/engine.docker.ini config/docker.engine.ini
# Contributing
When contributing to this repository, please first read about [contributing to AURA](https://gitlab.servus.at/aura/meta/-/blob/master/docs/development/contributions.md). Then discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.
Please note we have a [code of conduct](/aura/meta/-/blob/master/docs/development/code_of_conduct.md), please follow it in all your interactions with the project.
\ No newline at end of file
...@@ -31,4 +31,4 @@ VOLUME ["/srv/socket", "/srv/logs", "/var/audio/source", "/var/audio/playlist"] ...@@ -31,4 +31,4 @@ VOLUME ["/srv/socket", "/srv/logs", "/var/audio/source", "/var/audio/playlist"]
# Start the Engine # Start the Engine
EXPOSE 1337/tcp EXPOSE 1337/tcp
ENTRYPOINT ["./run.sh"] ENTRYPOINT ["./run.sh", "prod"]
...@@ -4,30 +4,30 @@ ...@@ -4,30 +4,30 @@
<img src="https://gitlab.servus.at/autoradio/meta/-/raw/master/assets/images/aura-engine.png" width="250" align="right" /> <img src="https://gitlab.servus.at/autoradio/meta/-/raw/master/assets/images/aura-engine.png" width="250" align="right" />
Aura Engine is a scheduling and play-out engine as part of [Aura Radio Software Suite](#About), specifically build for Aura Engine is a scheduling and play-out engine as part of [Aura Radio Software Suite](#About), specifically built for
the requirements of community radio stations. the requirements of community radio stations.
<!-- TOC --> <!-- TOC -->
1. [Aura Engine](#aura-engine) 1. [Aura Engine](#aura-engine)
1. [Functionality](#functionality) 1. [Functionality](#functionality)
1. [Scheduler](#scheduler) 1. [Scheduler](#scheduler)
1. [Versatile playlists](#versatile-playlists) 1. [Versatile playlists](#versatile-playlists)
2. [Default playlists](#default-playlists) 2. [Default playlists](#default-playlists)
2. [Heartbeat Monitoring](#heartbeat-monitoring) 2. [Heartbeat Monitoring](#heartbeat-monitoring)
3. [Logging](#logging) 3. [Logging](#logging)
2. [Getting started](#getting-started) 2. [Getting started](#getting-started)
3. [Using Docker](#using-docker) 3. [Using Docker](#using-docker)
4. [Read more](#read-more) 4. [Read more](#read-more)
5. [About](#about) 5. [About](#about)
<!-- /TOC --> <!-- /TOC -->
## Functionality ## Functionality
In conjuction with other AURA components Engine provides several features: In conjunction with other AURA components Engine provides several features:
- **Scheduler** to automatically broadcast your radio programme (see [AURA Dashboard](https://gitlab.servus.at/aura/dashboard) for an user interface to do scheduling) - **Scheduler** to automatically broadcast your radio programme (see [AURA Dashboard](https://gitlab.servus.at/aura/dashboard) for a user interface to do scheduling)
- **Analog input and outputs** provided by [Engine Core](https://gitlab.servus.at/aura/engine-core) - **Analog input and outputs** provided by [Engine Core](https://gitlab.servus.at/aura/engine-core)
- **Streaming to an [Icecast](https://icecast.org/) Server including [Icy Metadata](https://cast.readme.io/docs/icy)** provided by [Engine Core](https://gitlab.servus.at/aura/engine-core) - **Streaming to an [Icecast](https://icecast.org/) Server including [Icy Metadata](https://cast.readme.io/docs/icy)** provided by [Engine Core](https://gitlab.servus.at/aura/engine-core)
- **Autonomous playout** by caching the schedule information pulled from [Steering](https://gitlab.servus.at/aura/steering) in a local database. This allows Engine be keep running, independently from any network or service outages. This enables the application of (*High Availability* infrastructure scenarios)[https://gitlab.servus.at/aura/meta/-/blob/master/docs/administration/installation-guide.md#high-availability]. - **Autonomous playout** by caching the schedule information pulled from [Steering](https://gitlab.servus.at/aura/steering) in a local database. This allows Engine be keep running, independently from any network or service outages. This enables the application of (*High Availability* infrastructure scenarios)[https://gitlab.servus.at/aura/meta/-/blob/master/docs/administration/installation-guide.md#high-availability].
...@@ -41,7 +41,7 @@ In conjuction with other AURA components Engine provides several features: ...@@ -41,7 +41,7 @@ In conjuction with other AURA components Engine provides several features:
Engine provide a scheduling functionality by polling external API endpoints frequently. Those API endpoints are provided by [Steering](https://gitlab.servus.at/aura/steering) to retrieve schedule information and [Tank](https://gitlab.servus.at/aura/tank) to retrieve playlist information. To define your schedule you'll also need [AURA Dashboard](https://gitlab.servus.at/aura/dashboard) which is an elegent web user interface to manage your shows, playlists and schedules. Engine provide a scheduling functionality by polling external API endpoints frequently. Those API endpoints are provided by [Steering](https://gitlab.servus.at/aura/steering) to retrieve schedule information and [Tank](https://gitlab.servus.at/aura/tank) to retrieve playlist information. To define your schedule you'll also need [AURA Dashboard](https://gitlab.servus.at/aura/dashboard) which is an elegent web user interface to manage your shows, playlists and schedules.
Ideally any audio is scheduled some time before the actual, planned playout to avoid timing issues with buffering and preloading. Nonetheless, playlists can also be scheduled after a given calendar timeslot has started already. In such case the playout starts as soon it's preloaded. Ideally any audio is scheduled some time before the actual, planned playout to avoid timing issues with buffering and preloading. Nonetheless, playlists can also be scheduled after a given calendar timeslot has started already. In such case the playout starts as soon it is preloaded.
If for some reason the playout is corrupted, stopped or too silent to make any sense, then this <u>triggers a fallback using the silence detector</u> (see chapter below). If for some reason the playout is corrupted, stopped or too silent to make any sense, then this <u>triggers a fallback using the silence detector</u> (see chapter below).
...@@ -49,28 +49,28 @@ If for some reason the playout is corrupted, stopped or too silent to make any s ...@@ -49,28 +49,28 @@ If for some reason the playout is corrupted, stopped or too silent to make any s
#### Versatile playlists #### Versatile playlists
It's possible to schedules playlists with music or pre-recorded shows stored on the **file system**, via external **streams** or live from an **analog input** in the studio. All types of sources can be mixed in a single playlist. It is possible to schedules playlists with music or pre-recorded shows stored on the **file system**, via external **streams** or live from an **analog input** in the studio. All types of sources can be mixed in a single playlist.
The switching between types of audio source is handled automatically, with configured fadings applied. The switching between types of audio source is handled automatically, with configured fadings applied.
> Note: Any live sources or streams not specifing a length property, are automatically expanded to the left duration of the timeslot. > Note: Any live sources or streams not specifying a length property, are automatically expanded to the left duration of the timeslot.
#### Default playlists #### Default playlists
While a timeslot can have a specific playlist assigned, it's also possible to define default playlists While a timeslot can have a specific playlist assigned, it is also possible to define default playlists
for schedules and shows: for schedules and shows:
- **Default Schedule Playlist**: This playlist is defined on the level of some recurrence rules (*Schedule*). - **Default Schedule Playlist**: This playlist is defined on the level of some recurrence rules (*Schedule*).
In case the timeslot doesn't have any specific playlist assigned, this playlist is broadcasted. In case the timeslot doesn't have any specific playlist assigned, this playlist is broadcasted.
- **Default Show Playlist**: This playlist can be assigned to some show. If neither the specific timeslot - **Default Show Playlist**: This playlist can be assigned to some show. If neither the specific timeslot
playlist nor the default schedule playlist is specificed the *default show playlist* is broadcasted. playlist nor the default schedule playlist is specified the *default show playlist* is broadcasted.
If none of these playlists have been specified the *Auto DJ* feature of [Engine Core](https://gitlab.servus.at/aura/engine-core) takes over (optional). If none of these playlists have been specified the *Auto DJ* feature of [Engine Core](https://gitlab.servus.at/aura/engine-core) takes over (optional).
### Heartbeat Monitoring ### Heartbeat Monitoring
Instead of checking all status properties, the Heartbeat only validates the vital ones required to run the engine. If all of those are valid, a network socket request is sent to a defined server. This heartbeat is sent continiously based on the configured `heartbeat_frequency`. The service receiving this heartbeat ticks can decide what to do with that information. One scenario could be switching to another Engine instance or any other custom failover scenario. Under `contrib/heartbeat-monitor` you'll find some sample application digesting these heartbeat signals. Instead of checking all status properties, the Heartbeat only validates the vital ones required to run the engine. If all of those are valid, a network socket request is sent to a defined server. This heartbeat is sent continuously based on the configured `heartbeat_frequency`. The service receiving this heartbeat ticks can decide what to do with that information. One scenario could be switching to another Engine instance or any other custom failover scenario. Under `contrib/heartbeat-monitor` you'll find some sample application digesting these heartbeat signals.
### Logging ### Logging
...@@ -84,21 +84,34 @@ For production we recommend running Engine using Docker Compose. If you want to ...@@ -84,21 +84,34 @@ For production we recommend running Engine using Docker Compose. If you want to
## Using Docker ## Using Docker
If you only want to run the single Engine Docker container, you can do this in a few, simple steps. Before getting started copy the default configuration file to `config/engine.docker.ini`: If you only want to run a single Engine Docker container, you can do this in a few, simple steps.
Before getting started copy the default configuration file to `config/engine.docker.ini`:
```shell
cp config/sample-docker.engine.ini config/docker.engine.ini
```
You'll need update a few settings:
- The password `db_pass` for the local database holding scheduling information
- The app secret `api_tank_secret` for connecting to [AURA Tank](https://gitlab.servus.at/aura/tank)
- Also check the `ENV` variables defined in the `run.sh` script.
At the moment production deployment using Docker and Docker Compose is [*work in progress*](https://gitlab.servus.at/aura/meta/-/issues/56).
If you would like to run the local codebase, starting Engine in Docker requires you to do a build first:
```shell ```shell
cp config/sample-docker.engine.ini config/engine.docker.ini ./run.sh docker:build
``` ```
You'll need to do a few configurations which are required: After your build has finished start the Engine with following command.
- The password `db_pass` for the local database holding scheduling information
- The app secret `api_tank_secret` for connecting to [AURA Tank](https://gitlab.servus.at/aura/tank)
- Also check the `ENV` variables defined in the `run.sh` script.
Now start the engine with: If no build is available it pulls the latest image from [Docker Hub](https://hub.docker.com/r/autoradio/engine).
```shell ```shell
./run.sh docker:engine ./run.sh docker:dev
``` ```
## Read more ## Read more
...@@ -112,7 +125,7 @@ Now start the engine with: ...@@ -112,7 +125,7 @@ Now start the engine with:
[<img src="https://gitlab.servus.at/autoradio/meta/-/raw/master/assets/images/aura-logo.png" width="150" />](https://gitlab.servus.at/aura/meta) [<img src="https://gitlab.servus.at/autoradio/meta/-/raw/master/assets/images/aura-logo.png" width="150" />](https://gitlab.servus.at/aura/meta)
AURA stands for Automated Radio and is a swiss army knife for community radio stations. Beside the Engine it provides Steering (Admin Interface for the radio station), Dashboard (Collaborative scheduling and programme coordination), Tank (Audio uploading, pre-processing and delivery). Read more in the [Aura Meta](https://gitlab.servus.at/aura/meta) repository or on the specific project pages. Automated Radio (AURA) is a open source software suite for community radio stations. Learn more about AURA in the [Meta repository](https://gitlab.servus.at/aura/meta).
| [<img src="https://gitlab.servus.at/aura/meta/-/raw/master/assets/images/aura-steering.png" width="150" align="left" />](https://gitlab.servus.at/aura/steering) | [<img src="https://gitlab.servus.at/aura/meta/-/raw/master/assets/images/aura-dashboard.png" width="150" align="left" />](https://gitlab.servus.at/aura/dashboard) | [<img src="https://gitlab.servus.at/aura/meta/-/raw/master/assets/images/aura-tank.png" width="150" align="left" />](https://gitlab.servus.at/aura/tank) | [<img src="https://gitlab.servus.at/aura/meta/-/raw/master/assets/images/aura-engine.png" width="150" align="left" />](https://gitlab.servus.at/aura/engine) | | [<img src="https://gitlab.servus.at/aura/meta/-/raw/master/assets/images/aura-steering.png" width="150" align="left" />](https://gitlab.servus.at/aura/steering) | [<img src="https://gitlab.servus.at/aura/meta/-/raw/master/assets/images/aura-dashboard.png" width="150" align="left" />](https://gitlab.servus.at/aura/dashboard) | [<img src="https://gitlab.servus.at/aura/meta/-/raw/master/assets/images/aura-tank.png" width="150" align="left" />](https://gitlab.servus.at/aura/tank) | [<img src="https://gitlab.servus.at/aura/meta/-/raw/master/assets/images/aura-engine.png" width="150" align="left" />](https://gitlab.servus.at/aura/engine) |
|---|---|---|---| |---|---|---|---|
......
...@@ -93,7 +93,7 @@ scheduling_window_end=60 ...@@ -93,7 +93,7 @@ scheduling_window_end=60
preload_offset=15 preload_offset=15
# Sometimes it might take longer to get a stream connected. Here you can define a viable length. # Sometimes it might take longer to get a stream connected. Here you can define a viable length.
# But note, that this may affect the preloading time (see `preload_offset`), hence affecting the # But note, that this may affect the preloading time (see `preload_offset`), hence affecting the
# overall playout, it's delays and possible fallbacks # overall playout, its delays and possible fallbacks
input_stream_retry_delay=1 input_stream_retry_delay=1
input_stream_max_retries=10 input_stream_max_retries=10
input_stream_buffer=3.0 input_stream_buffer=3.0
......
...@@ -93,7 +93,7 @@ scheduling_window_end=60 ...@@ -93,7 +93,7 @@ scheduling_window_end=60
preload_offset=15 preload_offset=15
# Sometimes it might take longer to get a stream connected. Here you can define a viable length. # Sometimes it might take longer to get a stream connected. Here you can define a viable length.
# But note, that this may affect the preloading time (see `preload_offset`), hence affecting the # But note, that this may affect the preloading time (see `preload_offset`), hence affecting the
# overall playout, it's delays and possible fallbacks # overall playout, its delays and possible fallbacks
input_stream_retry_delay=1 input_stream_retry_delay=1
input_stream_max_retries=10 input_stream_max_retries=10
input_stream_buffer=3.0 input_stream_buffer=3.0
......
...@@ -93,7 +93,7 @@ scheduling_window_end=60 ...@@ -93,7 +93,7 @@ scheduling_window_end=60
preload_offset=15 preload_offset=15
# Sometimes it might take longer to get a stream connected. Here you can define a viable length. # Sometimes it might take longer to get a stream connected. Here you can define a viable length.
# But note, that this may affect the preloading time (see `preload_offset`), hence affecting the # But note, that this may affect the preloading time (see `preload_offset`), hence affecting the
# overall playout, it's delays and possible fallbacks # overall playout, its delays and possible fallbacks
input_stream_retry_delay=1 input_stream_retry_delay=1
input_stream_max_retries=10 input_stream_max_retries=10
input_stream_buffer=3.0 input_stream_buffer=3.0
......
[program:aura-engine] [program:aura-engine]
user = engineuser user = engineuser
directory = /opt/aura/engine directory = /opt/aura/engine
command = /opt/aura/engine/run.sh engine command = /opt/aura/engine/run.sh prod
priority = 666 priority = 666
autostart = true autostart = true
......
...@@ -8,7 +8,7 @@ Requires=aura-engine-core.service ...@@ -8,7 +8,7 @@ Requires=aura-engine-core.service
Type=simple Type=simple
User=engineuser User=engineuser
WorkingDirectory=/opt/aura/engine WorkingDirectory=/opt/aura/engine
ExecStart=/opt/aura/engine/run.sh ExecStart=/opt/aura/engine/run.sh prod
Restart=always Restart=always
[Install] [Install]
......
#!/usr/bin/env python2.7 #!/usr/bin/env python3
# Copyright (c) 2001, Nicola Larosa # Copyright (c) 2001, Nicola Larosa
# All rights reserved. # All rights reserved.
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions # modification, are permitted provided that the following conditions
# are met: # are met:
# * Redistributions of source code must retain the above copyright # * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer. # notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above # * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following # copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided # disclaimer in the documentation and/or other materials provided
# with the distribution. # with the distribution.
# * Neither the name of the <ORGANIZATION> nor the names of its # * Neither the name of the <ORGANIZATION> nor the names of its
# contributors may be used to endorse or promote products derived # contributors may be used to endorse or promote products derived
# from this software without specific prior written permission. # from this software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
...@@ -34,54 +34,72 @@ clients that sent at least one packet during the run, but have ...@@ -34,54 +34,72 @@ clients that sent at least one packet during the run, but have
not sent any packet since a time longer than the definition of the timeout. not sent any packet since a time longer than the definition of the timeout.
Adjust the constant parameters as needed, or call as: Adjust the constant parameters as needed, or call as:
PyHBServer.py [timeout [udpport]]
PyHeartBeat.py [udpport [timeout]]
Set the environment variable "DEBUG" to "1" in order to emit more detailed
debug messages.
In addition "127.0.0.1" is marked as a previously active peer.
Manual heartbeat messages can be easily sent via "netcat":
echo foo | nc -q 1 -u localhost 43334
https://www.oreilly.com/library/view/python-cookbook/0596001673/ch10s13.html https://www.oreilly.com/library/view/python-cookbook/0596001673/ch10s13.html
""" """
HBPORT = 43334 import os
CHECKWAIT = 10 import socket
import sys
from socket import socket, gethostbyname, AF_INET, SOCK_DGRAM
from threading import Lock, Thread, Event from threading import Lock, Thread, Event
from time import time, ctime, sleep from time import time, ctime, sleep
import sys
DEFAULT_HEARTBEAT_PORT = 43334
DEFAULT_WAIT_PERIOD = 10
DEBUG_ENABLED = os.getenv("DEBUG", "0") == "1"
class BeatDict: class BeatDict:
"Manage heartbeat dictionary" "Manage heartbeat dictionary"
def __init__(self): def __init__(self):
self.beatDict = {} self.beatDict = {}
if __debug__: if DEBUG_ENABLED:
self.beatDict['127.0.0.1'] = time( ) self.beatDict["127.0.0.1"] = time()
self.dictLock = Lock( ) self.dictLock = Lock()
def __repr__(self): def __repr__(self):
list = '' result = ""
self.dictLock.acquire( ) self.dictLock.acquire()
for key in self.beatDict.keys( ): for key in self.beatDict.keys():
list = "%sIP address: %s - Last time: %s\n" % ( result += "IP address: %s - Last time: %s\n" % (
list, key, ctime(self.beatDict[key])) key,
self.dictLock.release( ) ctime(self.beatDict[key]),
return list )
self.dictLock.release()
return result
def update(self, entry): def update(self, entry):
"Create or update a dictionary entry" "Create or update a dictionary entry"
self.dictLock.acquire( ) self.dictLock.acquire()
self.beatDict[entry] = time( ) self.beatDict[entry] = time()
self.dictLock.release( ) self.dictLock.release()
def extractSilent(self, howPast): def extractSilent(self, howPast):
"Returns a list of entries older than howPast" "Returns a list of entries older than howPast"
silent = [] silent = []
when = time( ) - howPast when = time() - howPast
self.dictLock.acquire( ) self.dictLock.acquire()
for key in self.beatDict.keys( ): for key in self.beatDict.keys():
if self.beatDict[key] < when: if self.beatDict[key] < when:
silent.append(key) silent.append(key)
self.dictLock.release( ) self.dictLock.release()
return silent return silent
class BeatRec(Thread): class BeatRec(Thread):
"Receive UDP packets, log them in heartbeat dictionary" "Receive UDP packets, log them in heartbeat dictionary"
...@@ -90,52 +108,62 @@ class BeatRec(Thread): ...@@ -90,52 +108,62 @@ class BeatRec(Thread):
self.goOnEvent = goOnEvent self.goOnEvent = goOnEvent
self.updateDictFunc = updateDictFunc self.updateDictFunc = updateDictFunc
self.port = port self.port = port
self.recSocket = socket(AF_INET, SOCK_DGRAM) self.recSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.recSocket.bind(('', port)) self.recSocket.settimeout(0.2)
self.recSocket.bind(("", port))
def __repr__(self): def __repr__(self):
return "Heartbeat Server on port: %d\n" % self.port return f"Heartbeat Server on port: {self.port}"
def run(self): def run(self):
while self.goOnEvent.isSet( ): while self.goOnEvent.isSet():
if __debug__: if DEBUG_ENABLED:
print "Waiting to receive..." print("Waiting to receive...")
data, addr = self.recSocket.recvfrom(6) try:
if __debug__: data, addr = self.recSocket.recvfrom(6)
print "Received packet from " + `addr` except socket.timeout:
self.updateDictFunc(addr[0]) # no incoming message -> no timestamp update -> check again
pass
def main( ): else:
if DEBUG_ENABLED:
print(f"Received packet from {addr}")
self.updateDictFunc(addr[0])
def main():
"Listen to the heartbeats and detect inactive clients" "Listen to the heartbeats and detect inactive clients"
global HBPORT, CHECKWAIT if len(sys.argv) > 1:
if len(sys.argv)>1: heartbeat_port = int(sys.argv[1])
HBPORT=sys.argv[1] else:
if len(sys.argv)>2: heartbeat_port = DEFAULT_HEARTBEAT_PORT
CHECKWAIT=sys.argv[2] if len(sys.argv) > 2:
wait_period = float(sys.argv[2])
beatRecGoOnEvent = Event( ) else:
beatRecGoOnEvent.set( ) wait_period = DEFAULT_WAIT_PERIOD
beatDictObject = BeatDict( )
beatRecThread = BeatRec(beatRecGoOnEvent, beatDictObject.update, HBPORT) beatRecGoOnEvent = Event()
if __debug__: beatRecGoOnEvent.set()
print beatRecThread beatDictObject = BeatDict()
beatRecThread.start( ) beatRecThread = BeatRec(beatRecGoOnEvent, beatDictObject.update, heartbeat_port)
print "PyHeartBeat server listening on port %d" % HBPORT if DEBUG_ENABLED:
print "\n*** Press Ctrl-C to stop ***\n" print(beatRecThread)
while 1: beatRecThread.start()
print(f"PyHeartBeat server listening on port {heartbeat_port}")
print("\n*** Press Ctrl-C to stop ***\n")
while True:
try: try:
if __debug__: if DEBUG_ENABLED:
print "Beat Dictionary" print(f"Beat Dictionary: {beatDictObject}")
print `beatDictObject` silent = beatDictObject.extractSilent(wait_period)
silent = beatDictObject.extractSilent(CHECKWAIT)
if silent: if silent:
print "Silent clients" print(f"Silent clients: {' '.join(silent)}")
print `silent` sleep(wait_period)
sleep(CHECKWAIT)
except KeyboardInterrupt: except KeyboardInterrupt:
print "Exiting." print("Exiting.")
beatRecGoOnEvent.clear( ) beatRecGoOnEvent.clear()
beatRecThread.join( ) beatRecThread.join()
break
if __name__ == '__main__': if __name__ == "__main__":
main( ) main()
\ No newline at end of file
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
- [Setting up the database](#setting-up-the-database) - [Setting up the database](#setting-up-the-database)
- [Configuration](#configuration) - [Configuration](#configuration)
- [Running Engine](#running-engine) - [Running Engine](#running-engine)
- [Starting dependencies](#starting-dependencies)
- [Daemonized Engine](#daemonized-engine) - [Daemonized Engine](#daemonized-engine)
- [Running with Systemd](#running-with-systemd) - [Running with Systemd](#running-with-systemd)
- [Running with Supervisor](#running-with-supervisor) - [Running with Supervisor](#running-with-supervisor)
...@@ -59,9 +60,9 @@ Create your base configuration from the sample configuration ...@@ -59,9 +60,9 @@ Create your base configuration from the sample configuration
```shell ```shell
# Development # Development
cp config/sample.development.engine.ini config/engine.ini cp config/sample-development.engine.ini config/engine.ini
# Production # Production
cp config/sample.production.engine.ini config/engine.ini cp config/sample-production.engine.ini config/engine.ini
``` ```
### Setting up the database ### Setting up the database
...@@ -83,9 +84,9 @@ In your development environment edit following file to configure the engine: ...@@ -83,9 +84,9 @@ In your development environment edit following file to configure the engine:
./config/engine.ini ./config/engine.ini
``` ```
> Please note, if some configuration exists under `/etc/aura/engine.ini` the configuration by default is drawn from there. > Please note, if some configuration exists under `/etc/aura/engine.ini` the configuration by default is drawn from there. This overrides any configuration located in `./engine/config`.
While the configuration has plenty of configuration options, you only need to set a few mandatory ones, given you are running the other components (such as 'engine-core', "engine-api" etc.) at the default settings too. While the configuration file has plenty of options, you only need to set a few mandatory ones, given you are running the other components (such as 'engine-core', "engine-api" etc.) at their default settings too.
Required modifications are: Required modifications are:
- The password `db_pass` for the local database holding scheduling information - The password `db_pass` for the local database holding scheduling information
...@@ -96,16 +97,42 @@ Required modifications are: ...@@ -96,16 +97,42 @@ Required modifications are:
There's a convencience script `run.sh` to get engine started There's a convencience script `run.sh` to get engine started
```shell ```shell
engine$ ./run.sh engine$ ./run.sh
``` ```
Keep in mind you'll also need to start Engine Core separately The script executes the *default target*, which is usually `dev` for development environments.
You can call this target explicitely too:
```shell
engine$ ./run.sh dev
```
Or run Engine in production mode:
```shell
engine$ ./run.sh prod
```