From 4c63ef71fc893ae4b22214949f00ab6103113bbc Mon Sep 17 00:00:00 2001
From: jo <ljonas@riseup.net>
Date: Thu, 23 Mar 2023 02:06:39 +0100
Subject: [PATCH] feat(playout): replace thread timeout with socket timeout

Prefer the lower level socket timeout feature, to the hand made threaded
timeout. The thread timeout does not raise or log the errors that may occur
during the communication with liquidsoap, and we should handle them
instead.
---
 playout/libretime_playout/player/fetch.py     |  5 ----
 .../player/liquidsoap_gateway.py              | 11 -------
 playout/libretime_playout/timeout.py          | 30 -------------------
 3 files changed, 46 deletions(-)
 delete mode 100644 playout/libretime_playout/timeout.py

diff --git a/playout/libretime_playout/player/fetch.py b/playout/libretime_playout/player/fetch.py
index 068df5721..c9eecdbae 100644
--- a/playout/libretime_playout/player/fetch.py
+++ b/playout/libretime_playout/player/fetch.py
@@ -15,7 +15,6 @@ from requests import RequestException
 from ..config import CACHE_DIR, POLL_INTERVAL, Config
 from ..liquidsoap.client import LiquidsoapClient
 from ..liquidsoap.models import Info, MessageFormatKind, StreamPreferences, StreamState
-from ..timeout import ls_timeout
 from .events import Events, FileEvent, FileEvents
 from .liquidsoap import PypoLiquidsoap
 from .schedule import get_schedule, receive_schedule
@@ -157,7 +156,6 @@ class PypoFetch(Thread):
         self.pypo_liquidsoap.clear_all_queues()
         self.pypo_liquidsoap.clear_queue_tracker()
 
-    @ls_timeout
     def update_liquidsoap_stream_format(
         self,
         stream_format: Union[MessageFormatKind, int],
@@ -167,21 +165,18 @@ class PypoFetch(Thread):
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def update_liquidsoap_message_offline(self, message_offline: str) -> None:
         try:
             self.liq_client.settings_update(message_offline=message_offline)
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def update_liquidsoap_transition_fade(self, fade: float) -> None:
         try:
             self.liq_client.settings_update(input_fade_transition=fade)
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def update_liquidsoap_station_name(self, station_name: str) -> None:
         try:
             self.liq_client.settings_update(station_name=station_name)
diff --git a/playout/libretime_playout/player/liquidsoap_gateway.py b/playout/libretime_playout/player/liquidsoap_gateway.py
index 976704c56..52d09e09c 100644
--- a/playout/libretime_playout/player/liquidsoap_gateway.py
+++ b/playout/libretime_playout/player/liquidsoap_gateway.py
@@ -2,7 +2,6 @@ import logging
 from typing import List, Optional
 
 from ..liquidsoap.client import LiquidsoapClient
-from ..timeout import ls_timeout
 from .events import FileEvent, WebStreamEvent
 
 logger = logging.getLogger(__name__)
@@ -49,21 +48,18 @@ class TelnetLiquidsoap:
         self.liq_client = liq_client
         self.queues = queues
 
-    @ls_timeout
     def queue_clear_all(self):
         try:
             self.liq_client.queues_remove(*self.queues)
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def queue_remove(self, queue_id: int):
         try:
             self.liq_client.queues_remove(queue_id)
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def queue_push(self, queue_id: int, file_event: FileEvent):
         try:
             annotation = create_liquidsoap_annotation(file_event)
@@ -71,21 +67,18 @@ class TelnetLiquidsoap:
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def stop_web_stream_buffer(self):
         try:
             self.liq_client.web_stream_stop_buffer()
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def stop_web_stream_output(self):
         try:
             self.liq_client.web_stream_stop()
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def start_web_stream(self):
         try:
             self.liq_client.web_stream_start()
@@ -93,7 +86,6 @@ class TelnetLiquidsoap:
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def start_web_stream_buffer(self, event: WebStreamEvent):
         try:
             self.liq_client.web_stream_start_buffer(event.row_id, event.uri)
@@ -101,7 +93,6 @@ class TelnetLiquidsoap:
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def get_current_stream_id(self) -> str:
         try:
             return self.liq_client.web_stream_get_id()
@@ -109,7 +100,6 @@ class TelnetLiquidsoap:
             logger.exception(exception)
             return "-1"
 
-    @ls_timeout
     def disconnect_source(self, sourcename):
         if sourcename not in ("master_dj", "live_dj"):
             raise ValueError(f"invalid source name: {sourcename}")
@@ -120,7 +110,6 @@ class TelnetLiquidsoap:
         except OSError as exception:
             logger.exception(exception)
 
-    @ls_timeout
     def switch_source(self, sourcename, status):
         if sourcename not in ("master_dj", "live_dj", "scheduled_play"):
             raise ValueError(f"invalid source name: {sourcename}")
diff --git a/playout/libretime_playout/timeout.py b/playout/libretime_playout/timeout.py
deleted file mode 100644
index f1416cae9..000000000
--- a/playout/libretime_playout/timeout.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import threading
-
-
-def __timeout(func, timeout_duration, default, args, kwargs):
-    class InterruptableThread(threading.Thread):
-        name = "liquidsoap_timeout"
-
-        def __init__(self):
-            threading.Thread.__init__(self)
-            self.result = default
-
-        def run(self):
-            self.result = func(*args, **kwargs)
-
-    while True:
-        thread = InterruptableThread()
-        thread.start()
-        thread.join(timeout_duration)
-
-        if thread.is_alive():
-            raise RuntimeError("Thread did not terminate")
-
-        return thread.result
-
-
-def ls_timeout(func, timeout=15, default=None):
-    def new_f(*args, **kwargs):
-        return __timeout(func, timeout, default, args, kwargs)
-
-    return new_f