Source code for cadrumo.adapters.outbound.aeat.auth.browser_lifecycle
"""Shared browser lifecycle primitives for AEAT authentication providers."""from__future__importannotationsimportasyncioimportloggingfromcollections.abcimportAsyncGeneratorfromcontextlibimportasynccontextmanagerfrom.....application.auth.protocolsimportBrowserContextPort,BrowserSessionPort
[docs]classCloseIntentBarrier:"""Serialize closers and bar new work while any close intent exists."""def__init__(self)->None:self._gate=asyncio.Lock()self._state_lock=asyncio.Lock()self._close_intents=0self._no_close_intents=asyncio.Event()self._no_close_intents.set()@propertydefclosing(self)->bool:"""Return whether one or more close callers are registered."""returnself._close_intents>0@propertydefclose_intents(self)->int:"""Return the number of registered close callers."""returnself._close_intents
[docs]@asynccontextmanagerasyncdefwork(self)->AsyncGenerator[None]:"""Enter ordinary work only when every registered closer has exited."""whileTrue:awaitself._no_close_intents.wait()awaitself._gate.acquire()ifnotself.closing:breakself._gate.release()try:yieldfinally:self._gate.release()
[docs]@asynccontextmanagerasyncdefclose(self)->AsyncGenerator[None]:"""Register one close intent and serialize its teardown sequence."""asyncwithself._state_lock:self._close_intents+=1self._no_close_intents.clear()try:asyncwithself._gate:yieldfinally:asyncwithself._state_lock:self._close_intents-=1ifself._close_intents==0:self._no_close_intents.set()
[docs]asyncdefclose_owned_browser_context(context:BrowserContextPort|None,*,timeout_ms:int,logger:logging.Logger,owner:str,)->bool:"""Close an owned browser context within ``timeout_ms`` and report completion."""ifcontextisNone:returnTruetry:awaitasyncio.wait_for(context.close(),timeout=timeout_ms/1000,)exceptTimeoutError:logger.warning("%s: browser context close exceeded %d ms",owner,timeout_ms,)returnFalseexceptException:logger.warning("%s: browser context close failed",owner,exc_info=True)returnFalsereturnTrue
[docs]asyncdefclose_owned_browser_session(session:BrowserSessionPort|None,*,timeout_ms:int,logger:logging.Logger,owner:str,)->bool:"""Close an owned browser session within ``timeout_ms``. Returns ``True`` when no session exists or teardown completes. A timeout or close failure is logged and returns ``False`` so the provider retains the session reference and a later :meth:`~cadrumo.application.auth.protocols.BrowserSessionPort.close` call can retry. """ifsessionisNone:returnTruetry:awaitasyncio.wait_for(session.close(),timeout=timeout_ms/1000,)exceptTimeoutError:logger.warning("%s: browser session close exceeded %d ms",owner,timeout_ms,)returnFalseexceptException:# Browser-session teardown must not mask the primary auth failure.logger.warning("%s: browser session close failed",owner,exc_info=True)returnFalsereturnTrue