server state
This commit is contained in:
parent
bdda886e10
commit
b1e20eae5c
4 changed files with 54 additions and 34 deletions
|
@ -1,6 +1,2 @@
|
||||||
# Flask Details
|
|
||||||
HOST: str = "localhost"
|
|
||||||
PORT: int = 13500
|
|
||||||
|
|
||||||
# BAPSicle Details
|
# BAPSicle Details
|
||||||
VERSION: float = 1.0
|
VERSION: float = 1.0
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
63
server.py
63
server.py
|
@ -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")
|
||||||
|
|
Loading…
Reference in a new issue