From 3e64cf0612daae1d944772efc6cec69edb5874c9 Mon Sep 17 00:00:00 2001 From: Trysdyn Black Date: Thu, 6 Mar 2025 20:26:11 -0800 Subject: [PATCH 1/2] Use the same API handle across the entire app This opens doors in the future to storing state in the API class, and is just cleaner in general. --- main.py | 7 ++++--- management.py | 2 +- ovenapi.py | 12 ++++++++++++ status.py | 2 +- viewer.py | 2 +- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index 2b5a256..5785faa 100644 --- a/main.py +++ b/main.py @@ -44,9 +44,10 @@ if __name__ == "__main__": # Load config values config.load() - # If we have API access, use it to pull our stream list - if config.is_api_ready(): - config.LAST_STREAM_LIST = ovenapi.OvenAPI(config.API_USER, config.API_PASS).get_stream_list() + # If we have API access, use it to pull our stream list into cache + config.LAST_STREAM_LIST = ovenapi.get_api_handle( + username=config.API_USER, password=config.API_PASS + ).get_stream_list() runpath = Path(Path(__file__).parent.resolve(), "assets") diff --git a/management.py b/management.py index 493ec40..95ad191 100644 --- a/management.py +++ b/management.py @@ -13,7 +13,7 @@ class Management: def __init__(self): self.page_template = Path("template/management.mako").read_text(encoding="utf-8") self.redirect_template = Path("template/message.mako").read_text(encoding="utf-8") - self.api = ovenapi.OvenAPI(config.API_USER, config.API_PASS) + self.api = ovenapi.get_api_handle(username=config.API_USER, password=config.API_PASS) @staticmethod def __verify_same_domain() -> bool: diff --git a/ovenapi.py b/ovenapi.py index f77829d..d674c5e 100644 --- a/ovenapi.py +++ b/ovenapi.py @@ -1,6 +1,9 @@ import requests +API_HANDLE = None + + class OvenAPI: def __init__(self, username: str, password: str, api_path: str = "http://localhost:8081/v1") -> None: self.opener = requests.Session() @@ -111,3 +114,12 @@ class OvenAPI: return resp["response"]["input"]["sourceUrl"].split("://")[1].split(":")[0] except Exception: return None + + +def get_api_handle(**kwargs): + """Cache and return a single canonical API handle.""" + global API_HANDLE # noqa: PLW0603 + if API_HANDLE is None: + API_HANDLE = OvenAPI(**kwargs) + + return API_HANDLE diff --git a/status.py b/status.py index 5245424..6a759cb 100644 --- a/status.py +++ b/status.py @@ -16,7 +16,7 @@ class Status: return self def __init__(self): - self.api = ovenapi.OvenAPI(config.API_USER, config.API_PASS) + self.api = ovenapi.get_api_handle(username=config.API_USER, password=config.API_PASS) @cherrypy.expose @cherrypy.tools.json_out() diff --git a/viewer.py b/viewer.py index a38d8d3..c427024 100644 --- a/viewer.py +++ b/viewer.py @@ -12,7 +12,7 @@ class Viewer: def __init__(self): self.webcall_template = Path("template/webcall.mako").read_text(encoding="utf-8") self.single_template = Path("template/single.mako").read_text(encoding="utf-8") - self.api = ovenapi.OvenAPI(config.API_USER, config.API_PASS) + self.api = ovenapi.get_api_handle(username=config.API_USER, password=config.API_PASS) def app_is_okay(self, app_name): # If we can't access the API, we can't check if an app exists, just okay it From a3c273bad4d676c0afb8bcf7ff88f0588dc776dc Mon Sep 17 00:00:00 2001 From: Trysdyn Black Date: Thu, 6 Mar 2025 21:01:44 -0800 Subject: [PATCH 2/2] Don't de-dupe additions to live stream list De-duping those additions seems like a good idea, but we found out that in some cases, OME will emit open and closes for streams while they're still live. De-duping those resulted in streams erroneously being removed from the live list. One such scenario is someone trying to "Steal" and already live key. OME will emit an open and an immediate close as the connection is rejected. The close was removing the still-live stream from the list. Fixes #9 --- admission.py | 6 +++++- status.py | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/admission.py b/admission.py index 1e4c5b3..254ce03 100644 --- a/admission.py +++ b/admission.py @@ -88,7 +88,11 @@ def handle_notify() -> None: 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: + # NOTE: This can result in the list containing duplicates; we need to de-dupe before we use it + # This is necessary because OME emits open and close events for rejections due to key + # already being in use. Without dupes, this scenario would knock the stream out of the + # list entirely. + if cherrypy.request.update_opening: stream_list.append(cherrypy.request.update_stream) if not cherrypy.request.update_opening and cherrypy.request.update_stream in stream_list: diff --git a/status.py b/status.py index 6a759cb..d44d7e0 100644 --- a/status.py +++ b/status.py @@ -30,8 +30,10 @@ class Status: # Use config.LAST_STREAM_LIST here because this is a cache of the last # stream list the last time the list of streams changed. It should be # accurate. + # We de-dupe because the cached list can end up with duplicates but + # in all cases, one live entry should mean that stream is live. for s_vhost, s_app, s_stream in config.LAST_STREAM_LIST: - if s_vhost == vhost and s_app == app: + if s_vhost == vhost and s_app == app and s_stream not in streams: streams.append(s_stream) return streams