forked from p15670423/monkey
Common: Prevent topic collision between types and tags
If an event tag happened to be the same as an event type, subscribers could receive event types that they were not prepared to handle, resulting in difficult-to-diagnose bugs. Prevent tags and types from being sent to the wrong subscribers by appending unique strings to the topics.
This commit is contained in:
parent
3384c049a4
commit
a6c24af622
|
@ -22,10 +22,12 @@ class PyPubSubEventQueue(IEventQueue):
|
||||||
self, event_type: Type[AbstractEvent], subscriber: Callable[[AbstractEvent], None]
|
self, event_type: Type[AbstractEvent], subscriber: Callable[[AbstractEvent], None]
|
||||||
):
|
):
|
||||||
# pypubsub.pub.subscribe needs a string as the topic/event name
|
# pypubsub.pub.subscribe needs a string as the topic/event name
|
||||||
self._pypubsub_publisher.subscribe(listener=subscriber, topicName=event_type.__name__)
|
event_type_topic = PyPubSubEventQueue._get_type_topic(event_type)
|
||||||
|
self._pypubsub_publisher.subscribe(listener=subscriber, topicName=event_type_topic)
|
||||||
|
|
||||||
def subscribe_tag(self, tag: str, subscriber: Callable[[AbstractEvent], None]):
|
def subscribe_tag(self, tag: str, subscriber: Callable[[AbstractEvent], None]):
|
||||||
self._pypubsub_publisher.subscribe(listener=subscriber, topicName=tag)
|
tag_topic = PyPubSubEventQueue._get_tag_topic(tag)
|
||||||
|
self._pypubsub_publisher.subscribe(listener=subscriber, topicName=tag_topic)
|
||||||
|
|
||||||
def publish(self, event: AbstractEvent):
|
def publish(self, event: AbstractEvent):
|
||||||
self._publish_to_all_events_topic(event)
|
self._publish_to_all_events_topic(event)
|
||||||
|
@ -36,8 +38,20 @@ class PyPubSubEventQueue(IEventQueue):
|
||||||
self._pypubsub_publisher.sendMessage(_INTERNAL_ALL_EVENT_TYPES_TOPIC, event=event)
|
self._pypubsub_publisher.sendMessage(_INTERNAL_ALL_EVENT_TYPES_TOPIC, event=event)
|
||||||
|
|
||||||
def _publish_to_type_topic(self, event: AbstractEvent):
|
def _publish_to_type_topic(self, event: AbstractEvent):
|
||||||
self._pypubsub_publisher.sendMessage(event.__class__.__name__, event=event)
|
event_type_topic = PyPubSubEventQueue._get_type_topic(event.__class__)
|
||||||
|
self._pypubsub_publisher.sendMessage(event_type_topic, event=event)
|
||||||
|
|
||||||
def _publish_to_tags_topics(self, event: AbstractEvent):
|
def _publish_to_tags_topics(self, event: AbstractEvent):
|
||||||
for tag in event.tags:
|
for tag in event.tags:
|
||||||
self._pypubsub_publisher.sendMessage(tag, event=event)
|
tag_topic = PyPubSubEventQueue._get_tag_topic(tag)
|
||||||
|
self._pypubsub_publisher.sendMessage(tag_topic, event=event)
|
||||||
|
|
||||||
|
# Appending a unique string to the topics for type and tags prevents bugs caused by collisions
|
||||||
|
# between type names and tag names.
|
||||||
|
@staticmethod
|
||||||
|
def _get_type_topic(event_type: Type[AbstractEvent]) -> str:
|
||||||
|
return f"{event_type.__name__}-type"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_tag_topic(tag: str) -> str:
|
||||||
|
return f"{tag}-tag"
|
||||||
|
|
|
@ -99,3 +99,11 @@ def test_subscribe_tags_multiple_types(event_queue, subscriber):
|
||||||
assert TestEvent1 in subscriber.call_types
|
assert TestEvent1 in subscriber.call_types
|
||||||
assert TestEvent2 in subscriber.call_types
|
assert TestEvent2 in subscriber.call_types
|
||||||
assert {EVENT_TAG_1, EVENT_TAG_2}.issubset(subscriber.call_tags)
|
assert {EVENT_TAG_1, EVENT_TAG_2}.issubset(subscriber.call_tags)
|
||||||
|
|
||||||
|
|
||||||
|
def test_type_tag_collision(event_queue, subscriber):
|
||||||
|
event_queue.subscribe_type(TestEvent1, subscriber)
|
||||||
|
|
||||||
|
event_queue.publish(TestEvent2(tags={TestEvent1.__name__}))
|
||||||
|
|
||||||
|
assert subscriber.call_count == 0
|
||||||
|
|
Loading…
Reference in New Issue