From b1e20eae5c305ec043e42cb67f3bc892b3ca27c2 Mon Sep 17 00:00:00 2001 From: michael-grace Date: Mon, 9 Nov 2020 00:10:36 +0000 Subject: [PATCH] server state --- config.py.example | 4 --- helpers/logging_manager.py | 3 +- helpers/state_manager.py | 18 +++++------ server.py | 63 ++++++++++++++++++++++++++------------ 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/config.py.example b/config.py.example index f50f5ad..9925970 100644 --- a/config.py.example +++ b/config.py.example @@ -1,6 +1,2 @@ -# Flask Details -HOST: str = "localhost" -PORT: int = 13500 - # BAPSicle Details VERSION: float = 1.0 \ No newline at end of file diff --git a/helpers/logging_manager.py b/helpers/logging_manager.py index c51d4a4..0a11e25 100644 --- a/helpers/logging_manager.py +++ b/helpers/logging_manager.py @@ -16,8 +16,7 @@ class LoggingManager(): try: # Try creating the file. open(filename, "x") - except Exception as e: - print(e) + except: print("Failed to create log file") return diff --git a/helpers/state_manager.py b/helpers/state_manager.py index 40257b5..8e1b28c 100644 --- a/helpers/state_manager.py +++ b/helpers/state_manager.py @@ -19,8 +19,7 @@ class StateManager: __rate_limit_params_until = {} __rate_limit_period_s = 0 - - def __init__(self, name, logger: LoggingManager, default_state=None, rate_limit_params=[], rate_limit_period_s = 5): + def __init__(self, name, logger: LoggingManager, default_state=None, rate_limit_params=[], rate_limit_period_s=5): self.logger = logger self.filepath = resolve_external_file_path("/state/" + name + ".json") @@ -47,9 +46,10 @@ class StateManager: file_state = json.loads(file_state) # Turn from JSON -> PlanObject - file_state["loaded_item"] = PlanObject(file_state["loaded_item"]) if file_state["loaded_item"] else None - - file_state["show_plan"] = [PlanObject(obj) for obj in file_state["show_plan"]] + if "channel" in file_state: + file_state["loaded_item"] = PlanObject( + file_state["loaded_item"]) if file_state["loaded_item"] else None + file_state["show_plan"] = [PlanObject(obj) for obj in file_state["show_plan"]] # Now feed the loaded state into the initialised state manager. self.state = file_state @@ -73,7 +73,7 @@ class StateManager: def state(self, state): self.__state = copy(state) - def write_to_file(self,state): + def write_to_file(self, state): if self.__state_in_file == state: # No change to be updated. return @@ -89,8 +89,9 @@ class StateManager: state_to_json["last_updated"] = current_time # Not the biggest fan of this, but maybe I'll get a better solution for this later - state_to_json["loaded_item"] = state_to_json["loaded_item"].__dict__ if state_to_json["loaded_item"] else None - state_to_json["show_plan"] = [repr.__dict__ for repr in state_to_json["show_plan"]] + if "channel" in state_to_json: # If its a channel object + state_to_json["loaded_item"] = state_to_json["loaded_item"].__dict__ if state_to_json["loaded_item"] else None + state_to_json["show_plan"] = [repr.__dict__ for repr in state_to_json["show_plan"]] try: state_json = json.dumps(state_to_json, indent=2, sort_keys=True) except: @@ -109,7 +110,6 @@ class StateManager: else: self.__rate_limit_params_until[key] = self._currentTimeS + self.__rate_limit_period_s - state_to_update = self.state if key in state_to_update and state_to_update[key] == value: diff --git a/server.py b/server.py index b1c0e54..bd8e707 100644 --- a/server.py +++ b/server.py @@ -28,9 +28,19 @@ if not isMacOS(): import config from typing import Dict, List +from helpers.state_manager import StateManager +from helpers.logging_manager import LoggingManager setproctitle.setproctitle("BAPSicle - Server") +default_state = { + "server_version": 0, + "server_name": "URY BAPSicle", + "host": "localhost", + "port": 13500, + "num_channels": 3 +} + class BAPSicleServer(): @@ -46,6 +56,11 @@ class BAPSicleServer(): stopServer() +logger = LoggingManager("BAPSicleServer") + +state = StateManager("BAPSicleServer", logger, default_state) +state.update("server_version", config.VERSION) + app = Flask(__name__, static_url_path='') log = logging.getLogger('werkzeug') @@ -59,7 +74,7 @@ channel_p = [] stopping = False -### General Endpoints +# General Endpoints @app.errorhandler(404) def page_not_found(e): @@ -109,7 +124,8 @@ def ui_status(): } return render_template('status.html', data=data) -### Channel Audio Options +# Channel Audio Options + @app.route("/player//play") def play(channel): @@ -156,28 +172,33 @@ def output(channel, name): channel_to_q[channel].put("OUTPUT:" + name) return ui_status() + @app.route("/player//autoadvance/") def autoadvance(channel: int, state: int): channel_to_q[channel].put("AUTOADVANCE:" + str(state)) return ui_status() + @app.route("/player//repeat/") def repeat(channel: int, state): channel_to_q[channel].put("REPEAT:" + state.upper()) return ui_status() + @app.route("/player//playonload/") def playonload(channel: int, state: int): channel_to_q[channel].put("PLAYONLOAD:" + str(state)) return ui_status() -### Channel Items +# Channel Items + @app.route("/player//load/") -def load(channel:int, timeslotitemid: int): +def load(channel: int, timeslotitemid: int): channel_to_q[channel].put("LOAD:" + str(timeslotitemid)) return ui_status() + @app.route("/player//unload") def unload(channel): @@ -185,6 +206,7 @@ def unload(channel): return ui_status() + @app.route("/player//add", methods=["POST"]) def add_to_plan(channel: int): new_item: Dict[str, any] = { @@ -198,28 +220,32 @@ def add_to_plan(channel: int): return new_item + @app.route("/player//move//") def move_plan(channel: int, timeslotitemid: int, position: int): channel_to_q[channel].put("MOVE:" + json.dumps({"timeslotitemid": timeslotitemid, "position": position})) - #TODO Return + # TODO Return return True + @app.route("/player//remove/") def remove_plan(channel: int, timeslotitemid: int): channel_to_q[channel].put("REMOVE:" + timeslotitemid) - #TODO Return + # TODO Return return True + @app.route("/player//clear") def clear_channel_plan(channel: int): channel_to_q[channel].put("CLEAR") - #TODO Return + # TODO Return return True -### General Channel Endpoints +# General Channel Endpoints + @app.route("/player//status") def status(channel): @@ -266,7 +292,7 @@ def send_static(path): def startServer(): if isMacOS(): multiprocessing.set_start_method("spawn", True) - for channel in range(3): + for channel in range(state.state["num_channels"]): channel_to_q.append(multiprocessing.Queue()) channel_from_q.append(multiprocessing.Queue()) @@ -287,14 +313,13 @@ def startServer(): text_to_speach = pyttsx3.init() text_to_speach.save_to_file( - """Thank-you for installing BAPSicle - the play-out server from the broadcasting and presenting suite. - This server is accepting connections on port {0} - The version of the server service is {1} + """Thank-you for installing BAPSicle - the play-out server from the broadcasting and presenting suite. + This server is accepting connections on port 13500 + The version of the server service is {} Please refer to the documentation included with this application for further assistance.""".format( - config.PORT, - config.VERSION - ), - "dev/welcome.mp3" + config.VERSION + ), + "dev/welcome.mp3" ) text_to_speach.runAndWait() @@ -306,12 +331,12 @@ def startServer(): } channel_to_q[0].put("ADD:" + json.dumps(new_item)) - #channel_to_q[0].put("LOAD:0") - #channel_to_q[0].put("PLAY") + # channel_to_q[0].put("LOAD:0") + # channel_to_q[0].put("PLAY") # Don't use reloader, it causes Nested Processes! + app.run(host=state.state["host"], port=state.state["port"], debug=True, use_reloader=False) - app.run(host='0.0.0.0', port=13500, debug=True, use_reloader=False) def stopServer(): print("Stopping server.py")