From 30d20728bca05c3aa9dab2212884e30127d663b5 Mon Sep 17 00:00:00 2001 From: Sp4rky Date: Thu, 26 Feb 2026 13:51:26 -0700 Subject: [PATCH] feat: add automatic session expiry to prevent stale session accumulation Sessions now track their creation time and are automatically cleaned up after SESSION_TIMEOUT (30s) when a new session is opened. This prevents stale sessions from accumulating when clients crash or disconnect without calling close(), which would otherwise permanently exhaust the 16-session limit and make the CDM unusable until server restart. Mirrors the existing implementation in csplayready. Closes #4 --- pyplayready/cdm.py | 10 ++++++++++ pyplayready/system/session.py | 2 ++ 2 files changed, 12 insertions(+) diff --git a/pyplayready/cdm.py b/pyplayready/cdm.py index adb533c..22c7e37 100644 --- a/pyplayready/cdm.py +++ b/pyplayready/cdm.py @@ -1,5 +1,6 @@ from __future__ import annotations +import time import xml.etree.ElementTree as ET from typing import List, Union, Optional from uuid import UUID @@ -24,6 +25,7 @@ from pyplayready.system.wrmheader import WRMHeader class Cdm: MAX_NUM_OF_SESSIONS = 16 + SESSION_TIMEOUT = 30 def __init__( self, @@ -59,6 +61,14 @@ class Cdm: def open(self) -> bytes: """Open a Playready Content Decryption Module (CDM) session""" + now = time.time() + expired = [ + session_id for session_id, session in self.__sessions.items() + if (now - session.opened_at) > self.SESSION_TIMEOUT + ] + for session_id in expired: + del self.__sessions[session_id] + if len(self.__sessions) > self.MAX_NUM_OF_SESSIONS: raise TooManySessions(f"Too many Sessions open ({self.MAX_NUM_OF_SESSIONS}).") diff --git a/pyplayready/system/session.py b/pyplayready/system/session.py index 516860d..119ddb2 100644 --- a/pyplayready/system/session.py +++ b/pyplayready/system/session.py @@ -1,3 +1,4 @@ +import time from typing import Optional from Crypto.Random import get_random_bytes @@ -15,3 +16,4 @@ class Session: self.signing_key: Optional[ECCKey] = None self.encryption_key: Optional[ECCKey] = None self.keys: list[Key] = [] + self.opened_at: float = time.time()