communicator.py 26.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#
#  engine
#
#  Playout Daemon for autoradio project
#
#
#  Copyright (C) 2017-2018 Gottfried Gaisbauer <gottfried.gaisbauer@servus.at>
#
#  This file is part of engine.
#
#  engine is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  any later version.
#
#  engine 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 General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with engine. If not, see <http://www.gnu.org/licenses/>.
#

25
26
import time
import logging
27
import json
28

29
from modules.communication.liquidsoap.playerclient import LiquidSoapPlayerClient
30
# from modules.communication.liquidsoap.recorderclient import LiquidSoapRecorderClient
31
from modules.communication.liquidsoap.initthread import LiquidSoapInitThread
32
33
from modules.communication.mail.mail import AuraMailer

34
from libraries.enum.auraenumerations import TerminalColors, ScheduleEntryType
35
from libraries.exceptions.auraexceptions import LQConnectionError
36
#from libraries.database.broadcasts import TrackService
37
from libraries.exceptions.exception_logger import ExceptionLogger
38

39
40
41
42
""" 
    LiquidSoapCommunicator Class 
    Uses LiquidSoapClient, but introduces more complex commands, transactions and error handling
"""
43

44
class LiquidSoapCommunicator(ExceptionLogger):
45
    client = None
46
    logger = None
47
    transaction = 0
48
    channels = None
49
    scheduler = None
50
    error_data = None
51
    auramailer = None
52
    is_liquidsoap_running = False
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
53
    connection_attempts = 0
54
    active_channel = None
55
    disable_logging = False
56
57
    fade_in_active = False
    fade_out_active = False
58
59

    # ------------------------------------------------------------------------------------------ #
60
    def __init__(self, config):
61
        """
62
63
        Constructor
        """
64
        self.config = config
65
66
        self.logger = logging.getLogger("AuraEngine")

67
68
        self.client = LiquidSoapPlayerClient(config, "engine.sock")
        # self.lqcr = LiquidSoapRecorderClient(config, "record.sock")
69

70
        errors_file = self.config.get("install_dir") + "/errormessages/controller_error.js"
71
        f = open(errors_file)
72
        self.error_data = json.load(f)
73
        f.close()
74

75
        self.auramailer = AuraMailer(self.config)
76

77
78
79
80
81
82
83
84
85
86
87
88
89
90
        self.is_liquidsoap_up_and_running()

    # ------------------------------------------------------------------------------------------ #
    def is_liquidsoap_up_and_running(self):
        try:
            self.uptime()
            self.is_liquidsoap_running = True
        except LQConnectionError as e:
            self.logger.info("Liquidsoap is not running so far")
            self.is_liquidsoap_running = False
        except Exception as e:
            self.logger.error("Cannot check if Liquidsoap is running. Reason: " + str(e))
            self.is_liquidsoap_running = False

91
92
    # ------------------------------------------------------------------------------------------ #
    def set_volume(self, mixernumber, volume):
93
        return self.__send_lqc_command__(self.client, "mixer", "volume", mixernumber, volume)
94
95
96

    # ------------------------------------------------------------------------------------------ #
    def get_active_mixer(self):
97
98
99
100
        """
        get active mixer in liquidsoap server
        :return:
        """
101
102
        activeinputs = []

103
        # enable more control over the connection
104
        self.enable_transaction()
105

106
        inputs = self.get_all_channels()
107
108
109

        cnt = 0
        for input in inputs:
110
            status = self.__get_mixer_status__(cnt)
111
112
113
114
115
116

            if "selected=true" in status:
                activeinputs.append(input)

            cnt = cnt + 1

117
        self.disable_transaction()
118
119
120

        return activeinputs

121
122
123
    # ------------------------------------------------------------------------------------------ #
    def get_active_channel(self):
        """
David Trattnig's avatar
David Trattnig committed
124
125
126
127
        Retrieves the active channel from programme.

        Returns:
            (String):   The channel type, empty string if no channel is active.
128
        """
David Trattnig's avatar
David Trattnig committed
129
        active_entry = self.scheduler.get_active_entry()
130
        if active_entry is None:
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
131
            return ""
132
        return active_entry.type
133

134
135
    # ------------------------------------------------------------------------------------------ #
    def get_mixer_status(self):
136
137
        inputstate = {}

Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
138
        self.enable_transaction()
139

140
        inputs = self.get_all_channels()
141
142
143

        cnt = 0
        for input in inputs:
144
            inputstate[input] = self.__get_mixer_status__(cnt)
145
146
            cnt = cnt + 1

Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
147
        self.disable_transaction()
148
149
150

        return inputstate

151
152
153
154
    # ------------------------------------------------------------------------------------------ #
    def get_mixer_volume(self, channel):
        return False

155
156
    # ------------------------------------------------------------------------------------------ #
    def get_recorder_status(self):
157
158
159
        self.enable_transaction(self.client)
        recorder_state = self.__send_lqc_command__(self.client, "record", "status")
        self.disable_transaction(self.client)
160
161
162

        return recorder_state

163
164
165
166
167
168
169
170
171
    # ------------------------------------------------------------------------------------------ #
    def http_start_stop(self, start):
        if start:
            cmd = "start"
        else:
            cmd = "stop"

        try:
            self.enable_transaction()
172
            self.__send_lqc_command__(self.client, "http", cmd)
173
            self.disable_transaction()
174
        except LQConnectionError:
175
176
177
            # we already caught and handled this error in __send_lqc_command__, but we do not want to execute this function further
            pass

178
179
180
181
182
183
184
185
186
187
188
189
    # ------------------------------------------------------------------------------------------ #
    def recorder_stop(self):
        self.enable_transaction()

        for i in range(5):
            if self.config.get("rec_" + str(i)) == "y":
                self.__send_lqc_command__(self.client, "recorder_" + str(i), "stop")

        self.disable_transaction()

    # ------------------------------------------------------------------------------------------ #
    def recorder_start(self, num=-1):
190
191
192
193
194
195
196
197
        if not self.is_liquidsoap_running:
            if num==-1:
                msg = "Want to start recorder, but LiquidSoap is not running"
            else:
                msg = "Want to start recorder " + str(num) + ", but LiquidSoap is not running"
            self.logger.warning(msg)
            return False

198
199
200
201
202
203
204
        self.enable_transaction()

        if num == -1:
            self.recorder_start_all()
        else:
            self.recorder_start_one(num)

205
206
        self.disable_transaction()

207
208
    # ------------------------------------------------------------------------------------------ #
    def recorder_start_all(self):
209
210
211
212
        if not self.is_liquidsoap_running:
            self.logger.warning("Want to start all recorder, but LiquidSoap is not running")
            return False

213
        self.enable_transaction()
214
215
        for i in range(5):
            self.recorder_start_one(i)
216
        self.disable_transaction()
217
218
219

    # ------------------------------------------------------------------------------------------ #
    def recorder_start_one(self, num):
220
221
        if not self.is_liquidsoap_running:
            return False
222

223
224
225
226
227
        if self.config.get("rec_" + str(num)) == "y":
            returnvalue = self.__send_lqc_command__(self.client, "recorder", str(num), "status")

            if returnvalue == "off":
                self.__send_lqc_command__(self.client, "recorder", str(num), "start")
228

229
    # ------------------------------------------------------------------------------------------ #
230
231
232
233
234
235
236
    def fade_in(self, new_entry):
        try:
            fade_in_time = float(self.config.get("fade_in_time"))

            if fade_in_time > 0:
                self.fade_in_active = True
                target_volume = new_entry.volume
David Trattnig's avatar
David Trattnig committed
237

238
                step = fade_in_time / target_volume
239

240
                self.logger.info("Starting to fading " + new_entry.type.value + " in. step is " + str(step) + "s. target volume is " + str(target_volume))
241

242
243
                self.disable_logging = True
                self.client.disable_logging = True
244

245
246
247
248
249
250
251
252
253
254
255
256
                for i in range(target_volume):
                    self.channel_volume(new_entry.type.value, i + 1)
                    time.sleep(step)

                self.logger.info("Finished with fading " + new_entry.type.value + " in.")

                self.fade_in_active = False
                if not self.fade_out_active:
                    self.disable_logging = False
                    self.client.disable_logging = False
        except LQConnectionError as e:
            self.logger.critical(str(e))
257
258
259
260

        return True

    # ------------------------------------------------------------------------------------------ #
261
262
263
264
265
266
    def fade_out(self, old_entry):
        try:
            fade_out_time = float(self.config.get("fade_out_time"))

            if fade_out_time > 0:
                step = abs(fade_out_time) / old_entry.volume
267

268
                self.logger.info("Starting to fading " + old_entry.type.value + " out. step is " + str(step) + "s")
269

270
271
272
                # disable logging... it is going to be enabled again after fadein and -out is finished
                self.disable_logging = True
                self.client.disable_logging = True
273

274
275
276
277
278
279
280
281
282
283
284
285
286
                for i in range(old_entry.volume):
                    self.channel_volume(old_entry.type.value, old_entry.volume-i-1)
                    time.sleep(step)

                self.logger.info("Finished with fading " + old_entry.type.value + " out.")

                # enable logging again
                self.fade_out_active = False
                if not self.fade_in_active:
                    self.disable_logging = False
                    self.client.disable_logging = False
        except LQConnectionError as e:
            self.logger.critical(str(e))
287

288
289
        return True

290
    # ------------------------------------------------------------------------------------------ #
David Trattnig's avatar
David Trattnig committed
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
    def activate(self, new_entry, cue_in=0.0):
        """
        Activates a new Playlist Entry.

        Args:
            new_entry (PlaylistEntry): The track to be played
        
        Raises:
            (LQConnectionError): In case connecting to LiquidSoap isn't possible
        """
        
        # Grab the actual active entry
        active_entry = self.scheduler.get_active_entry()
        # Set default channel, if no previous track is available
        current_channel = ScheduleEntryType.FILESYSTEM 
        if active_entry:
            current_channel = active_entry.type
308

309
        try:
310
            self.enable_transaction()
David Trattnig's avatar
David Trattnig committed
311
312
            if current_channel == new_entry.type:
                self.activate_same_channel(new_entry, cue_in)
313
            else:
David Trattnig's avatar
David Trattnig committed
314
                self.activate_different_channel(new_entry, cue_in, current_channel)
315
            self.disable_transaction()
316

David Trattnig's avatar
David Trattnig committed
317
318
319
            # FIXME Implement TrackService bi-directionally, log fallbacks too.
            self.logger.critical("FIXME: Implement TrackService")
#           self.insert_track_service_entry(new_entry)
320
        except LQConnectionError:
David Trattnig's avatar
David Trattnig committed
321
322
            # we already caught and handled this error in __send_lqc_command__, 
            # but we do not want to execute this function further and pass the exception
323
            pass
324

David Trattnig's avatar
David Trattnig committed
325
326
327
328
329
330
331
332
333

    def activate_same_channel(self, entry, cue_in=0.0, activate_different_channel=False):
        """
        Activates a playlist entry for the current channel.

        Args:
            entry (PlaylistEntry):  The entry to play.
            cue_in (Float):         A value in seconds where to cue the start of the entry.
        """
334
        if not activate_different_channel:
335
336
            self.logger.info(TerminalColors.PINK.value + entry.type.value + " already active!" + TerminalColors.ENDC.value)

David Trattnig's avatar
David Trattnig committed
337
        # Check if it needs to be pushed to a filesystem queue or stream
338
        if entry.type == ScheduleEntryType.FILESYSTEM:
David Trattnig's avatar
David Trattnig committed
339
340
341
342
            uri = entry.filename
            if cue_in > 0.0:
                uri = "annotate:liq_cue_in=\"%s\":%s" % (str(cue_in), entry.filename)
            self.playlist_push(uri)
343
344
345
            self.active_channel = entry.type

        elif entry.type == ScheduleEntryType.STREAM:
346
            self.set_http_url(entry.source)
347
            self.http_start_stop(True)
348
349
350
            self.active_channel = entry.type

        # else: # live
David Trattnig's avatar
David Trattnig committed
351
        # Nothing to do when we are live => just leave it as is
352

353
354
        self.active_channel = entry.type

David Trattnig's avatar
David Trattnig committed
355
        # Set active channel to wanted volume
356
357
358
        if not activate_different_channel:
            self.channel_volume(entry.type.value, entry.volume)

David Trattnig's avatar
David Trattnig committed
359
360
361
362
363
364
365
366
367
368

    def activate_different_channel(self, entry, cue_in, active_type):
        """
        Activates a playlist entry for a channel other then the currently active one.

        Args:
            entry (PlaylistEntry):            The entry to play.
            cue_in (Float):                   A value in seconds where to cue the start of the entry.
            active_type (ScheduleEntryType):  The type of the currently active channel
        """     
369
        self.logger.info(TerminalColors.PINK.value + "LiquidSoapCommunicator is activating " + entry.type.value + " & deactivating " + active_type.value + "!" + TerminalColors.ENDC.value)
370

David Trattnig's avatar
David Trattnig committed
371
372
373
        # Reuse of this function, because activate_same_channel and activate_different_channel 
        # are doing pretty the same except setting of the volume to zero
        self.activate_same_channel(entry, cue_in, True)
374

David Trattnig's avatar
David Trattnig committed
375
        # Set other channels to zero volume
376
        others = self.all_inputs_but(entry.getChannel())
377
378
        for o in others:
            self.channel_volume(o, 0)
379

David Trattnig's avatar
David Trattnig committed
380
        # Set active channel to wanted volume
381
        self.channel_volume(entry.type.value, entry.volume)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
382
383
384

    # ------------------------------------------------------------------------------------------ #
    def insert_track_service_entry(self, schedule_entry):
385
        # create trackservice entry
386
        trackservice_entry = TrackService()
387
388

        # set foreign keys
389
390
391
        trackservice_entry.playlist_id = schedule_entry.playlist_id
        trackservice_entry.entry_num = schedule_entry.entry_num
        trackservice_entry.source = schedule_entry.source
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
392

393
        # store
394
        trackservice_entry.store(add=True, commit=True)
395
396
397

    # ------------------------------------------------------------------------------------------ #
    def all_inputs_but(self, input_type):
398
        try:
399
            activemixer_copy = self.get_all_channels().copy()
400
            activemixer_copy.remove(input_type)
401
402
        except ValueError as e:
            self.logger.error("Requested channel (" + input_type + ") not in channellist. Reason: " + str(e))
403
404
        except AttributeError:
            self.logger.critical("Channellist is None")
405

406
407
408
409
        return activemixer_copy

    # ------------------------------------------------------------------------------------------ #
    def get_all_channels(self):
410
        if self.channels is None or len(self.channels) == 0:
411
            self.channels = self.__send_lqc_command__(self.client, "mixer", "inputs")
412
413

        return self.channels
414

415
416
417
418
419
    # ------------------------------------------------------------------------------------------ #
    def reload_channels(self):
        self.channels = None
        return self.get_all_channels()

420
421
    # ------------------------------------------------------------------------------------------ #
    def __get_mixer_status__(self, mixernumber):
422
        return self.__send_lqc_command__(self.client, "mixer", "status", mixernumber)
423
424

    # ------------------------------------------------------------------------------------------ #
425
    def init_player(self):
David Trattnig's avatar
David Trattnig committed
426
427
428
429
430
431
432
        """
        Initializes the LiquidSoap Player after startup of the engine.

        Returns:
            (String):   Message that the player is started.
        """
        active_entry = self.scheduler.get_active_entry()
433
434

        t = LiquidSoapInitThread(self, active_entry)
435
        t.start()
436

437
        return "LiquidSoapInitThread started!"
438

439
    # ------------------------------------------------------------------------------------------ #
440
441
442
443
444
445
    def channel_activate(self, channel, activate):
        channels = self.get_all_channels()

        try:
            index = channels.index(channel)
            if len(channel) < 1:
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
446
447
448
449
450
451
                self.logger.critical("Cannot activate channel. There are no channels!")
            else:
                message = self.__send_lqc_command__(self.client, "mixer", "select", index, activate)
                return message
        except Exception as e:
            self.logger.critical("Ran into exception when activating channel. Reason: " + str(e))
452

453
454
455
    # ------------------------------------------------------------------------------------------ #
    def channel_volume(self, channel, volume):
        """
456
        set volume of a channel
457
        @type     channel:  string
458
        @param    channel:  Channel
459
        @type     volume:   int
460
        @param    volume:   Volume between 0 and 100
461
        """
462

463
        try:
464
            channels = self.get_all_channels()
465
            index = channels.index(channel)
466
        except ValueError as e:
467
            self.logger.error("Cannot set volume of channel " + channel + " to " + str(volume) + "!. Reason: " + str(e))
468
469
470
            return

        try:
471
            if len(channel) < 1:
472
                self.logger.warning("Cannot set volume of channel " + channel + " to " + str(volume) + "! There are no channels.")
473
            else:
474
                message = self.__send_lqc_command__(self.client, "mixer", "volume", str(index), str(int(volume)))
475

476
477
478
479
480
                if not self.disable_logging:
                    if message.find('volume=' + str(volume) + '%'):
                        self.logger.debug("Set volume of channel " + channel + " to " + str(volume))
                    else:
                        self.logger.warning("Setting volume of channel " + channel + " gone wrong! Liquidsoap message: " + message)
481

482
                return message
483
        except AttributeError as e: #(LQConnectionError, AttributeError):
484
            self.disable_transaction(force=True)
485
            self.logger.error("Ran into exception when setting volume of channel " + channel + ". Reason: " + str(e))
486

487
488
489
490
491
    # ------------------------------------------------------------------------------------------ #
    def auraengine_state(self):
        state = self.__send_lqc_command__(self.client, "auraengine", "state")
        return state

492
493
    # ------------------------------------------------------------------------------------------ #
    def liquidsoap_help(self):
David Trattnig's avatar
David Trattnig committed
494
        data = self.__send_lqc_command__(self.client, "help", "")
495
        if not data:
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
496
            self.logger.warning("Could not get Liquidsoap's help")
497
        else:
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
498
499
            self.logger.debug("Got Liquidsoap's help")
        return data
500

501
502
    # ------------------------------------------------------------------------------------------ #
    def set_http_url(self, uri):
503
        return self.__send_lqc_command__(self.client, "http", "url", uri)
504

505
506
507
    # ------------------------------------------------------------------------------------------ #
    def playlist_push(self, uri):
        """
David Trattnig's avatar
David Trattnig committed
508
509
510
511
512
513
        Adds an filesystem URI to the playlist

        Args:
            uri (String):   The URI of the file
        Returns:
            LiquidSoap Response
514
        """
515
        return self.__send_lqc_command__(self.client, "fs", "push", uri)
516
517
518

    # ------------------------------------------------------------------------------------------ #
    def playlist_seek(self, seconds_to_seek):
David Trattnig's avatar
David Trattnig committed
519
520
521
522
523
524
525
        """
        Forwards the player (n) seconds.

        Args:
            seconds_to_seeks (Float):   The seconds to skip
        """
        return self.__send_lqc_command__(self.client, "fs", "seek", str(seconds_to_seek))
526
527
528
529
530
531

    # ------------------------------------------------------------------------------------------ #
    def version(self):
        """
        get version
        """
532
        data = self.__send_lqc_command__(self.client, "version", "")
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
533
534
        self.logger.debug("Got Liquidsoap's version")
        return data
535
536

    # ------------------------------------------------------------------------------------------ #
537
538
539
540
    def uptime(self):
        """
        get uptime
        """
541
542
        data = self.__send_lqc_command__(self.client, "uptime", "")
        self.logger.debug("Got Liquidsoap's uptime")
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
543
        return data
544
545

    # ------------------------------------------------------------------------------------------ #
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
546
    def __send_lqc_command__(self, lqs_instance, namespace, command, *args):
547
548
549
550
551
552
553
554
555
556
557
558
559
560
        """
        Ein Kommando an Liquidsoap senden
        @type  lqs_instance: object
        @param lqs_instance: Instance of LiquidSoap Client
        @type  namespace:    string
        @param namespace:    Namespace of function
        @type  command:      string
        @param command:      Function name
        @type args:          list
        @param args:         List of parameters
        @rtype:              string
        @return:             Response from LiquidSoap
        """
        try:
561
562
563
            if not self.disable_logging:
                if namespace == "recorder":
                    self.logger.info("LiquidSoapCommunicator is calling " + str(namespace) + "_" + str(command) + "." + str(args))
564
                else:
565
566
567
568
                    if command == "":
                        self.logger.info("LiquidSoapCommunicator is calling " + str(namespace) + str(args))
                    else:
                        self.logger.info("LiquidSoapCommunicator is calling " + str(namespace) + "." + str(command) + str(args))
569

570
571
572
573
574
            # call wanted function ...
            func = getattr(lqs_instance, namespace)
            # ... and fetch the result
            result = func(command, *args)

575
576
            if not self.disable_logging:
                self.logger.debug("LiquidSoapCommunicator got response " + str(result))
577

Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
578
            self.connection_attempts = 0
579

580
581
            return result

582
        except LQConnectionError as e:
583
            self.logger.error("Connection Error when sending " + str(namespace) + "." + str(command) + str(args))
584
            if self.try_to_reconnect():
585
                time.sleep(0.2)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
586
587
                self.connection_attempts += 1
                if self.connection_attempts < 5:
588
589
590
591
592
593
594
595
596
                    # reconnect
                    self.__open_conn(self.client)
                    self.logger.info("Trying to resend " + str(namespace) + "." + str(command) + str(args))
                    # grab return value
                    retval = self.__send_lqc_command__(lqs_instance, namespace, command, *args)
                    # disconnect
                    self.__close_conn(self.client)
                    # return the val
                    return retval
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
597
                else:
598
599
600
601
602
603
                    if command == "":
                        msg = "Rethrowing Exception while trying to send " + str(namespace) + str(args)
                    else:
                        msg = "Rethrowing Exception while trying to send " + str(namespace) + "." + str(command) + str(args)

                    self.logger.info(msg)
604
                    self.disable_transaction(socket=self.client, force=True)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
605
                    raise e
606
            else:
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
607
                # also store when was last admin mail sent with which content...
David Trattnig's avatar
David Trattnig committed
608
                # FIXME implement admin mail sending
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
609
                self.logger.critical("SEND ADMIN MAIL AT THIS POINT")
610
611
                raise e

612
    # ------------------------------------------------------------------------------------------ #
613
614
615
616
617
618
619
620
    def try_to_reconnect(self):
        self.enable_transaction()
        return self.transaction > 0

    # ------------------------------------------------------------------------------------------ #
    def enable_transaction(self, socket=None):
        # set socket to playout if nothing else is given
        if socket is None:
621
            socket = self.client
622

623
624
        self.transaction = self.transaction + 1

625
        self.logger.debug(TerminalColors.WARNING.value + "ENabling transaction! cnt: " + str(self.transaction) + TerminalColors.ENDC.value)
626
627
628
629

        if self.transaction > 1:
            return

630
631
632
633
634
        try:
            self.__open_conn(socket)
        except FileNotFoundError:
            self.disable_transaction(socket=socket, force=True)

Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
635
636
637
            msg = "socket file " + socket.socket_path + " not found. Is liquidsoap running?"
            self.logger.critical(TerminalColors.RED.value + msg + TerminalColors.ENDC.value)
            self.auramailer.send_admin_mail("CRITICAL Exception when connecting to Liquidsoap", msg)
638

639
    # ------------------------------------------------------------------------------------------ #
640
641
642
643
644
    def disable_transaction(self, socket=None, force=False):
        if not force:
            # nothing to disable
            if self.transaction == 0:
                return
645

646
647
            # decrease transaction counter
            self.transaction = self.transaction - 1
648

649
650
651
652
653
654
655
656
            # debug msg
            self.logger.debug(TerminalColors.WARNING.value + "DISabling transaction! cnt: " + str(self.transaction) + TerminalColors.ENDC.value)

            # return if connection is still needed
            if self.transaction > 0:
                return
        else:
            self.logger.debug(TerminalColors.WARNING.value + "Forcefully DISabling transaction! " + TerminalColors.ENDC.value)
657

658
659
        # close conn and set transactioncounter to 0
        self.__close_conn(socket)
660
        self.transaction = 0
661

662
    # ------------------------------------------------------------------------------------------ #
663
664
    def __open_conn(self, socket):
        # already connected
665
        if self.transaction > 1:
666
            return
667

668
        self.logger.debug(TerminalColors.GREEN.value + "LiquidSoapCommunicator opening conn" + TerminalColors.ENDC.value)
669

670
        # try to connect
671
672
        socket.connect()

673
    # ------------------------------------------------------------------------------------------ #
674
675
    def __close_conn(self, socket):
        # set socket to playout
676
        if socket is None:
677
            socket = self.client
678

679
        # do not disconnect if a transaction is going on
680
        if self.transaction > 0:
681
            return
682

683
        # say bye
684
        socket.byebye()
685

686
687
        # debug msg
        self.logger.debug(TerminalColors.BLUE.value + "LiquidSoapCommunicator closed conn" + TerminalColors.ENDC.value)