From a490fc56621114ee8861e91e90a6b1c4c42c00f0 Mon Sep 17 00:00:00 2001 From: Trysdyn Black Date: Wed, 25 Dec 2024 19:48:13 -0800 Subject: [PATCH] Rework admission webhook to not need sleep There's a one-second sleep in the old hook, because the Oven API did not always record the stream change quickly. Sometimes even that was not enough. This attempts to work around that by managing the stream list directly. --- admission.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/admission.py b/admission.py index d493145..532e531 100644 --- a/admission.py +++ b/admission.py @@ -63,14 +63,31 @@ def check_authorized(host, app, stream, source) -> bool: @cherrypy.tools.register("on_end_request") def handle_notify() -> None: + """ + Inspect and react to live streamer state after an admission webhook has fired. + + After the new stream has been authorized and the connection closed, this hook fires. + It expects two variables inserted into the cherrypy.request namespace named "update_stream" + and "update_opening" to let it process who has changed and in which direction. After + altering our stream list appropriately it checks if a notification webhook needs to fire. + """ # If we don't have API creds we can't do this, abort if not (config.API_USER and config.API_PASS): return - # Get stream list from API - # Unfortunately Oven doesn't reflect the new stream fast enough so we have to wait :( - time.sleep(1) - stream_list = ovenapi.OvenAPI(config.API_USER, config.API_PASS).get_stream_list() + # If we didn't fill out a state change, we don't need to do anything + if not hasattr(cherrypy.request, "update_opening") or not hasattr(cherrypy.request, "update_stream"): + return + + # Copy over our prior stream list so we have a clean one to alter + stream_list = config.LAST_STREAM_LIST.copy() + + # Remove or add the changed stream, as appropriate + if cherrypy.request.update_opening and cherrypy.request.update_stream not in stream_list: + stream_list.append(cherrypy.request.update_stream) + + if not cherrypy.request.update_opening and cherrypy.request.update_stream in stream_list: + stream_list.remove(cherrypy.request.update_stream) # If we haven't gone empty->active or active->empty we need to do nothing if bool(stream_list) != bool(config.LAST_STREAM_LIST): @@ -82,6 +99,7 @@ def handle_notify() -> None: webhook_online(stream_list[0]) if stream_list else webhook_offline() # Save our stream list into a durable value + cherrypy.log(str(stream_list)) config.LAST_STREAM_LIST = stream_list.copy() @@ -108,8 +126,12 @@ class Admission: _, _, host, app, path = input_json["request"]["url"].split("/")[:5] stream = path.split("?")[0] + # Populate variables for our on_end_request tool into request object + cherrypy.request.update_stream = ("default", app, stream) + # If we are closing, return a fast 200 if input_json["request"]["status"] == "closing": + cherrypy.request.update_opening = False return {} # Get client IP for ACL checking @@ -121,4 +143,5 @@ class Admission: return {"allowed": False} # Compile and dispatch our response + cherrypy.request.update_opening = True return {"allowed": True}