server state

This commit is contained in:
michael-grace 2020-11-09 00:10:36 +00:00
parent bdda886e10
commit b1e20eae5c
4 changed files with 54 additions and 34 deletions

View file

@ -1,6 +1,2 @@
# Flask Details
HOST: str = "localhost"
PORT: int = 13500
# BAPSicle Details # BAPSicle Details
VERSION: float = 1.0 VERSION: float = 1.0

View file

@ -16,8 +16,7 @@ class LoggingManager():
try: try:
# Try creating the file. # Try creating the file.
open(filename, "x") open(filename, "x")
except Exception as e: except:
print(e)
print("Failed to create log file") print("Failed to create log file")
return return

View file

@ -19,8 +19,7 @@ class StateManager:
__rate_limit_params_until = {} __rate_limit_params_until = {}
__rate_limit_period_s = 0 __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.logger = logger
self.filepath = resolve_external_file_path("/state/" + name + ".json") self.filepath = resolve_external_file_path("/state/" + name + ".json")
@ -47,9 +46,10 @@ class StateManager:
file_state = json.loads(file_state) file_state = json.loads(file_state)
# Turn from JSON -> PlanObject # Turn from JSON -> PlanObject
file_state["loaded_item"] = PlanObject(file_state["loaded_item"]) if file_state["loaded_item"] else None if "channel" in file_state:
file_state["loaded_item"] = PlanObject(
file_state["show_plan"] = [PlanObject(obj) for obj in file_state["show_plan"]] 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. # Now feed the loaded state into the initialised state manager.
self.state = file_state self.state = file_state
@ -73,7 +73,7 @@ class StateManager:
def state(self, state): def state(self, state):
self.__state = copy(state) self.__state = copy(state)
def write_to_file(self,state): def write_to_file(self, state):
if self.__state_in_file == state: if self.__state_in_file == state:
# No change to be updated. # No change to be updated.
return return
@ -89,8 +89,9 @@ class StateManager:
state_to_json["last_updated"] = current_time state_to_json["last_updated"] = current_time
# Not the biggest fan of this, but maybe I'll get a better solution for this later # 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 if "channel" in state_to_json: # If its a channel object
state_to_json["show_plan"] = [repr.__dict__ for repr in state_to_json["show_plan"]] 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: try:
state_json = json.dumps(state_to_json, indent=2, sort_keys=True) state_json = json.dumps(state_to_json, indent=2, sort_keys=True)
except: except:
@ -109,7 +110,6 @@ class StateManager:
else: else:
self.__rate_limit_params_until[key] = self._currentTimeS + self.__rate_limit_period_s self.__rate_limit_params_until[key] = self._currentTimeS + self.__rate_limit_period_s
state_to_update = self.state state_to_update = self.state
if key in state_to_update and state_to_update[key] == value: if key in state_to_update and state_to_update[key] == value:

View file

@ -28,9 +28,19 @@ if not isMacOS():
import config import config
from typing import Dict, List from typing import Dict, List
from helpers.state_manager import StateManager
from helpers.logging_manager import LoggingManager
setproctitle.setproctitle("BAPSicle - Server") setproctitle.setproctitle("BAPSicle - Server")
default_state = {
"server_version": 0,
"server_name": "URY BAPSicle",
"host": "localhost",
"port": 13500,
"num_channels": 3
}
class BAPSicleServer(): class BAPSicleServer():
@ -46,6 +56,11 @@ class BAPSicleServer():
stopServer() stopServer()
logger = LoggingManager("BAPSicleServer")
state = StateManager("BAPSicleServer", logger, default_state)
state.update("server_version", config.VERSION)
app = Flask(__name__, static_url_path='') app = Flask(__name__, static_url_path='')
log = logging.getLogger('werkzeug') log = logging.getLogger('werkzeug')
@ -59,7 +74,7 @@ channel_p = []
stopping = False stopping = False
### General Endpoints # General Endpoints
@app.errorhandler(404) @app.errorhandler(404)
def page_not_found(e): def page_not_found(e):
@ -109,7 +124,8 @@ def ui_status():
} }
return render_template('status.html', data=data) return render_template('status.html', data=data)
### Channel Audio Options # Channel Audio Options
@app.route("/player/<int:channel>/play") @app.route("/player/<int:channel>/play")
def play(channel): def play(channel):
@ -156,28 +172,33 @@ def output(channel, name):
channel_to_q[channel].put("OUTPUT:" + name) channel_to_q[channel].put("OUTPUT:" + name)
return ui_status() return ui_status()
@app.route("/player/<int:channel>/autoadvance/<int:state>") @app.route("/player/<int:channel>/autoadvance/<int:state>")
def autoadvance(channel: int, state: int): def autoadvance(channel: int, state: int):
channel_to_q[channel].put("AUTOADVANCE:" + str(state)) channel_to_q[channel].put("AUTOADVANCE:" + str(state))
return ui_status() return ui_status()
@app.route("/player/<int:channel>/repeat/<state>") @app.route("/player/<int:channel>/repeat/<state>")
def repeat(channel: int, state): def repeat(channel: int, state):
channel_to_q[channel].put("REPEAT:" + state.upper()) channel_to_q[channel].put("REPEAT:" + state.upper())
return ui_status() return ui_status()
@app.route("/player/<int:channel>/playonload/<int:state>") @app.route("/player/<int:channel>/playonload/<int:state>")
def playonload(channel: int, state: int): def playonload(channel: int, state: int):
channel_to_q[channel].put("PLAYONLOAD:" + str(state)) channel_to_q[channel].put("PLAYONLOAD:" + str(state))
return ui_status() return ui_status()
### Channel Items # Channel Items
@app.route("/player/<int:channel>/load/<int:timeslotitemid>") @app.route("/player/<int:channel>/load/<int:timeslotitemid>")
def load(channel:int, timeslotitemid: int): def load(channel: int, timeslotitemid: int):
channel_to_q[channel].put("LOAD:" + str(timeslotitemid)) channel_to_q[channel].put("LOAD:" + str(timeslotitemid))
return ui_status() return ui_status()
@app.route("/player/<int:channel>/unload") @app.route("/player/<int:channel>/unload")
def unload(channel): def unload(channel):
@ -185,6 +206,7 @@ def unload(channel):
return ui_status() return ui_status()
@app.route("/player/<int:channel>/add", methods=["POST"]) @app.route("/player/<int:channel>/add", methods=["POST"])
def add_to_plan(channel: int): def add_to_plan(channel: int):
new_item: Dict[str, any] = { new_item: Dict[str, any] = {
@ -198,28 +220,32 @@ def add_to_plan(channel: int):
return new_item return new_item
@app.route("/player/<int:channel>/move/<int:timeslotitemid>/<int:position>") @app.route("/player/<int:channel>/move/<int:timeslotitemid>/<int:position>")
def move_plan(channel: int, timeslotitemid: int, position: int): def move_plan(channel: int, timeslotitemid: int, position: int):
channel_to_q[channel].put("MOVE:" + json.dumps({"timeslotitemid": timeslotitemid, "position": position})) channel_to_q[channel].put("MOVE:" + json.dumps({"timeslotitemid": timeslotitemid, "position": position}))
#TODO Return # TODO Return
return True return True
@app.route("/player/<int:channel>/remove/<int:timeslotitemid>") @app.route("/player/<int:channel>/remove/<int:timeslotitemid>")
def remove_plan(channel: int, timeslotitemid: int): def remove_plan(channel: int, timeslotitemid: int):
channel_to_q[channel].put("REMOVE:" + timeslotitemid) channel_to_q[channel].put("REMOVE:" + timeslotitemid)
#TODO Return # TODO Return
return True return True
@app.route("/player/<int:channel>/clear") @app.route("/player/<int:channel>/clear")
def clear_channel_plan(channel: int): def clear_channel_plan(channel: int):
channel_to_q[channel].put("CLEAR") channel_to_q[channel].put("CLEAR")
#TODO Return # TODO Return
return True return True
### General Channel Endpoints # General Channel Endpoints
@app.route("/player/<int:channel>/status") @app.route("/player/<int:channel>/status")
def status(channel): def status(channel):
@ -266,7 +292,7 @@ def send_static(path):
def startServer(): def startServer():
if isMacOS(): if isMacOS():
multiprocessing.set_start_method("spawn", True) 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_to_q.append(multiprocessing.Queue())
channel_from_q.append(multiprocessing.Queue()) channel_from_q.append(multiprocessing.Queue())
@ -287,14 +313,13 @@ def startServer():
text_to_speach = pyttsx3.init() text_to_speach = pyttsx3.init()
text_to_speach.save_to_file( text_to_speach.save_to_file(
"""Thank-you for installing BAPSicle - the play-out server from the broadcasting and presenting suite. """Thank-you for installing BAPSicle - the play-out server from the broadcasting and presenting suite.
This server is accepting connections on port {0} This server is accepting connections on port 13500
The version of the server service is {1} The version of the server service is {}
Please refer to the documentation included with this application for further assistance.""".format( Please refer to the documentation included with this application for further assistance.""".format(
config.PORT, config.VERSION
config.VERSION ),
), "dev/welcome.mp3"
"dev/welcome.mp3"
) )
text_to_speach.runAndWait() 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("ADD:" + json.dumps(new_item))
#channel_to_q[0].put("LOAD:0") # channel_to_q[0].put("LOAD:0")
#channel_to_q[0].put("PLAY") # channel_to_q[0].put("PLAY")
# Don't use reloader, it causes Nested Processes! # 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(): def stopServer():
print("Stopping server.py") print("Stopping server.py")