run.py 5.69 KB
Newer Older
1
2
3
4
#!/bin/sh
''''which python3.8 >/dev/null 2>&1 && exec python3.8 "$0" "$@"     # '''
''''which python3.7  >/dev/null 2>&1 && exec python3.7  "$0" "$@"   # '''
''''exec echo "Error: Snaaakey Python, where are you?"                # '''
5
6

#
David Trattnig's avatar
David Trattnig committed
7
8
9
# Aura Engine (https://gitlab.servus.at/aura/engine)
#
# Copyright (C) 2017-2020 - The Aura Engine Team.
10
11
12
13
14
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
David Trattnig's avatar
David Trattnig committed
15
#
16
17
18
19
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
David Trattnig's avatar
David Trattnig committed
20
#
21
22
23
24
25
26
27
28
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


import os
import sys
import signal
import logging
29
import subprocess
30

31
32
from flask               import Flask
from flask_sqlalchemy    import SQLAlchemy
33
34
35

from modules.base.logger import AuraLogger
from modules.base.config import AuraConfig
36
from modules.base.utils  import SimpleUtil
37
38
39
40
41
42
43
44
45
46
47
48
49


config = AuraConfig()
def configure_flask():
    app.config["SQLALCHEMY_DATABASE_URI"] = config.get_database_uri()
    app.config['BABEL_DEFAULT_LOCALE'] = 'de'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# FIXME Instatiate SQLAlchemy without the need for Flask
app = Flask(__name__)
configure_flask()
DB = SQLAlchemy(app)

50
51

class AuraEngine:
52
    """
53
54
    AuraEngine does the following:

David Trattnig's avatar
David Trattnig committed
55
    1. Initialize the engine and scheduler
56
    3. Start Liquidsoap in a separate thread which connects to the engine
57
58
59
60
61
62
63

    """
    logger = None
    config = None
    server = None
    messenger = None
    controller = None
David Trattnig's avatar
David Trattnig committed
64
    engine = None
65
    scheduler = None
66
    lqs = None
67
68
    lqs_startup = None

69
70
71
72


    def __init__(self):
        """
73
        Initializes Engine Core.
74
75
        """
        self.config = config
David Trattnig's avatar
David Trattnig committed
76
77
78
        AuraLogger(self.config)
        self.logger = logging.getLogger("AuraEngine")
        
79
80


81
82

    def startup(self, lqs_startup):
83
        """
84
        Starts Engine Core.
David Trattnig's avatar
David Trattnig committed
85
        """                
86
        from modules.scheduling.scheduler import AuraScheduler
David Trattnig's avatar
David Trattnig committed
87
        from modules.core.engine import Engine
88

89
90
91
        # If Liquidsoap should be started automatically
        self.lqs_startup = lqs_startup

92
93
        # Check if the database has to be re-created
        if self.config.get("recreate_db") is not None:
94
            AuraScheduler.init_database()
95
96

        # Create scheduler and Liquidsoap communicator
97
98
99
100
101
102
103
104
105
106
107
108
109
110
        self.engine = Engine()
        
        # Sleep needed, because the socket is created too slowly by Liquidsoap
        # time.sleep(1)

        # def on_initialized():
        #     """
        #     Called when the engine is initialized, before the Liquidsoap connection is established."
        #     """
        #     self.logger.info(SU.green("Engine Core initialized - Waiting for Liquidsoap connection ..."))
        #     if self.lqs_startup:
        #         self.start_lqs(False, False)
        #     else:
        #         self.logger.info(SU.yellow("Please note, Liquidsoap needs to be started manually."))        
111

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142


    def start_lqs(self, debug_output, verbose_output):
        """
        Starts Liquidsoap.
        """
        lqs_path = self.config.get("liquidsoap_path")
        lqs_cwd = os.getcwd() + "/" + self.config.get("liquidsoap_working_dir")
        lqs_output = ""
        lqs_output = self.get_debug_flags(debug_output, verbose_output)

        self.lqs = subprocess.Popen([lqs_path, lqs_output, "engine.liq"], \
            cwd=lqs_cwd, \
            stdout=subprocess.PIPE, \
            shell=False)



    def get_lqs_cmd(self, debug_output, verbose_output):
        """
        Returns a shell command string to start Liquidsoap
        """
        lqs_path = self.config.get("liquidsoap_path")
        lqs_cwd = os.getcwd() + "/" + self.config.get("liquidsoap_working_dir")
        lqs_output = self.get_debug_flags(debug_output, verbose_output)
        return "(cd %s && %s %s ./engine.liq)" % (lqs_cwd, lqs_path, lqs_output)



    def get_debug_flags(self, debug_output, verbose_output):
        """
David Trattnig's avatar
David Trattnig committed
143
        Build Liquidsoap debug parameters.
144
145
146
147
148
149
150
        """
        output = ""
        if debug_output:
            output += "--debug " 
        if verbose_output:
            output += "--verbose "
        return output
151
152
153
154
155



    def exit_gracefully(self, signum, frame):
        """
156
        Shutdown of the engine. Also terminates the Liquidsoap thread.
157
        """
158
159
160
161
        if self.lqs:
            self.lqs.terminate()
            self.logger.info("Terminated Liquidsoap")

David Trattnig's avatar
David Trattnig committed
162
163
164
        if self.engine:
            self.engine.terminate()
                
165
166
167
        if self.messenger:
            self.messenger.terminate()
        
David Trattnig's avatar
David Trattnig committed
168
        self.logger.info("Gracefully terminated Aura Engine! (signum:%s, frame:%s)" % (signum, frame))
169
        sys.exit(0)        
170
171
172



173
174
175
176
177
#
# START THE ENGINE
#


178
179
if __name__ == "__main__":        
    engine = AuraEngine()
David Trattnig's avatar
David Trattnig committed
180
    start_lqs = True
181
    lqs_cmd = False
182
183
184

    signal.signal(signal.SIGINT, engine.exit_gracefully)
    signal.signal(signal.SIGTERM, engine.exit_gracefully)
185
186

    if len(sys.argv) >= 2:
187
        if "--without-lqs" in sys.argv:
David Trattnig's avatar
David Trattnig committed
188
            start_lqs = False
189
190
        if "--get-lqs-command" in sys.argv:
            lqs_cmd = True
191
        if "--use-test-data" in sys.argv:
192
            engine.config.set("use_test_data", True)
193
        if "--recreate-database" in sys.argv:
194
            engine.config.set("recreate_db", True)
195

196
197
198
    if lqs_cmd:
        print(engine.get_lqs_cmd(True, True))
    else:
David Trattnig's avatar
David Trattnig committed
199
        engine.startup(start_lqs)