Skip to content

Commit 363c6e5

Browse files
committed
Fix up EventListenerManager to reduce processing load of method by using a Sentinal
1 parent c71c604 commit 363c6e5

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

streamdeck/event_listener.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,25 @@
1111
from collections.abc import Generator
1212
from typing import Any, ClassVar
1313

14+
from typing_extensions import TypeIs
15+
1416
from streamdeck.models.events import EventBase
1517

1618

19+
1720
logger = getLogger("streamdeck.event_listener")
1821

1922

23+
class _SENTINAL:
24+
"""A sentinel object used to signal the end of the event stream.
25+
26+
Not meant to be instantiated, but rather used as a singleton (e.g. `_SENTINAL`).
27+
"""
28+
@classmethod
29+
def is_sentinal(cls, event: str | bytes | type[_SENTINAL]) -> TypeIs[type[_SENTINAL]]:
30+
"""Check if an event is the sentinal object. Provided to enable better type-checking."""
31+
return event is cls
32+
2033

2134
class EventListenerManager:
2235
"""Manages event listeners and provides a shared event queue for them to push events into.
@@ -25,7 +38,7 @@ class EventListenerManager:
2538
This allows for us to listen for not only Stream Deck events, but also other events plugin-developer -defined events.
2639
"""
2740
def __init__(self) -> None:
28-
self.event_queue: Queue[str | bytes] = Queue()
41+
self.event_queue: Queue[str | bytes | type[_SENTINAL]] = Queue()
2942
self.listeners_lookup_by_thread: dict[threading.Thread, EventListener] = {}
3043
self._running = False
3144

@@ -60,7 +73,11 @@ def stop(self) -> None:
6073
6174
Listeners will check the running flag if implemented to stop listening.
6275
"""
76+
# Set the running flag to False to stop the listeners running in separate threads.
6377
self.running = False
78+
# Push the sentinel to immediately unblock the queue.get() in event_stream.
79+
self.event_queue.put(_SENTINAL)
80+
6481
for thread in self.listeners_lookup_by_thread:
6582
self.listeners_lookup_by_thread[thread].stop()
6683
thread.join()
@@ -70,21 +87,21 @@ def stop(self) -> None:
7087
def event_stream(self) -> Generator[str | bytes, None, None]:
7188
"""Starts all registered listeners, sets the running flag to True, and yields events from the shared queue."""
7289
logger.info("Starting event stream.")
90+
# Set the running flag to True and start the listeners in their separate threads.
7391
self.running = True
74-
7592
for thread in self.listeners_lookup_by_thread:
7693
thread.start()
7794

7895
try:
79-
while self.running:
80-
if not self.event_queue.empty():
81-
yield self.event_queue.get()
96+
while True:
97+
event = self.event_queue.get()
98+
if _SENTINAL.is_sentinal(event):
99+
break # Exit loop immediately if the sentinal is received
100+
yield event
82101
finally:
83102
self.stop()
84103

85104

86-
87-
88105
class EventListener(ABC):
89106
"""Base class for event listeners.
90107

0 commit comments

Comments
 (0)