from __future__ import annotations from copy import deepcopy from enum import Enum from typing import Any, Callable class Events: class Types(Enum): _reserved = 0 # A Track's segment has finished downloading SEGMENT_DOWNLOADED = 1 # Track has finished downloading TRACK_DOWNLOADED = 2 # Track has finished decrypting TRACK_DECRYPTED = 3 # Track has finished repacking TRACK_REPACKED = 4 # Track is about to be Multiplexed into a Container TRACK_MULTIPLEX = 5 def __init__(self): self.__subscriptions: dict[Events.Types, list[Callable]] = {} self.__ephemeral: dict[Events.Types, list[Callable]] = {} self.reset() def reset(self): """Reset Event Observer clearing all Subscriptions.""" self.__subscriptions = {k: [] for k in Events.Types.__members__.values()} self.__ephemeral = deepcopy(self.__subscriptions) def subscribe(self, event_type: Events.Types, callback: Callable, ephemeral: bool = False) -> None: """ Subscribe to an Event with a Callback. Parameters: event_type: The Events.Type to subscribe to. callback: The function or lambda to call on event emit. ephemeral: Unsubscribe the callback from the event on first emit. Note that this is not thread-safe and may be called multiple times at roughly the same time. """ [self.__subscriptions, self.__ephemeral][ephemeral][event_type].append(callback) def unsubscribe(self, event_type: Events.Types, callback: Callable) -> None: """ Unsubscribe a Callback from an Event. Parameters: event_type: The Events.Type to unsubscribe from. callback: The function or lambda to remove from event emit. """ if callback in self.__subscriptions[event_type]: self.__subscriptions[event_type].remove(callback) if callback in self.__ephemeral[event_type]: self.__ephemeral[event_type].remove(callback) def emit(self, event_type: Events.Types, *args: Any, **kwargs: Any) -> None: """ Emit an Event, executing all subscribed Callbacks. Parameters: event_type: The Events.Type to emit. args: Positional arguments to pass to callbacks. kwargs: Keyword arguments to pass to callbacks. """ if event_type not in self.__subscriptions: raise ValueError(f'Event type "{event_type}" is invalid') for callback in self.__subscriptions[event_type] + self.__ephemeral[event_type]: callback(*args, **kwargs) self.__ephemeral[event_type].clear() events = Events()