Begins the lift of `web_server._register_automation_handlers` (1530 lines, 20 nested closures) into `core/automation/handlers/`. Each extracted handler is a top-level function that accepts `(config, deps)` instead of reaching for module-level globals -- makes them unit-testable in isolation. Infrastructure: - `core/automation/deps.py`: `AutomationDeps` (dependency-injection bundle of clients + callables) and `AutomationState` (mutable flags shared across handler invocations, with thread-safe accessors). - `core/automation/handlers/__init__.py` + `registration.py`: one-stop `register_all(deps)` that wires every extracted handler to the engine. First batch of handlers extracted: - `process_wishlist` -> `core/automation/handlers/process_wishlist.py` - `scan_watchlist` -> `core/automation/handlers/scan_watchlist.py` - `scan_library` -> `core/automation/handlers/scan_library.py` `web_server._register_automation_handlers` now builds the deps once and calls `register_all(deps)` for the extracted batch. Remaining 17 closures still live below; subsequent commits in this branch finish the lift. 14 boundary tests in `tests/automation/test_handlers_simple.py` pin every shape: success path, exception swallow contract, fresh-vs-stale state detection (scan_watchlist's id() trick), guard short-circuits, state cleanup on exceptions, AutomationState concurrent-safe accessors. All 101 automation tests pass; no regression.
45 lines
1.7 KiB
Python
45 lines
1.7 KiB
Python
"""One-stop registration of every extracted automation handler.
|
|
|
|
``web_server`` builds the deps once at startup and calls
|
|
:func:`register_all` here. Each new handler module gets one line in
|
|
this file when it lands.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from core.automation.deps import AutomationDeps
|
|
from core.automation.handlers.process_wishlist import auto_process_wishlist
|
|
from core.automation.handlers.scan_watchlist import auto_scan_watchlist
|
|
from core.automation.handlers.scan_library import auto_scan_library
|
|
|
|
|
|
def register_all(deps: AutomationDeps) -> None:
|
|
"""Wire every extracted handler to the engine.
|
|
|
|
Each ``register_action_handler`` call binds the action name (the
|
|
string the trigger uses to look up its action) to a thin lambda
|
|
that injects ``deps`` and forwards the engine-supplied config.
|
|
Guards stay alongside their handler so duplicate-run prevention
|
|
behaves identically to the pre-extraction code.
|
|
"""
|
|
engine = deps.engine
|
|
|
|
# Self-guards prevent duplicate runs of the SAME operation, but
|
|
# different operations can run concurrently — wishlist downloads
|
|
# use bandwidth, watchlist scans use API calls, library scans use
|
|
# media-server CPU. Different resources, no contention.
|
|
engine.register_action_handler(
|
|
'process_wishlist',
|
|
lambda config: auto_process_wishlist(config, deps),
|
|
guard_fn=deps.is_wishlist_actually_processing,
|
|
)
|
|
engine.register_action_handler(
|
|
'scan_watchlist',
|
|
lambda config: auto_scan_watchlist(config, deps),
|
|
guard_fn=deps.is_watchlist_actually_scanning,
|
|
)
|
|
engine.register_action_handler(
|
|
'scan_library',
|
|
lambda config: auto_scan_library(config, deps),
|
|
deps.state.is_scan_library_active,
|
|
)
|