bigchaindb/bigchaindb/events.py

110 lines
2.8 KiB
Python
Raw Normal View History

# Copyright © 2020 Interplanetary Database Association e.V.,
# BigchainDB and IPDB software contributors.
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
from queue import Empty
from collections import defaultdict
from multiprocessing import Queue
2017-07-31 01:58:58 +02:00
POISON_PILL = 'POISON_PILL'
class EventTypes:
2017-08-09 09:28:28 +02:00
"""Container class that holds all the possible
events BigchainDB manages.
"""
2017-08-09 16:14:14 +02:00
# If you add a new Event Type, make sure to add it
# to the docs in docs/server/source/event-plugin-api.rst
ALL = ~0
BLOCK_VALID = 1
BLOCK_INVALID = 2
# NEW_EVENT = 4
# NEW_EVENT = 8
# NEW_EVENT = 16...
2017-04-03 14:31:38 +02:00
class Event:
2017-08-09 09:28:28 +02:00
"""An Event."""
def __init__(self, event_type, event_data):
2017-08-09 09:28:28 +02:00
"""Creates a new event.
Args:
event_type (int): the type of the event, see
:class:`~bigchaindb.events.EventTypes`
event_data (obj): the data of the event.
"""
self.type = event_type
self.data = event_data
2017-08-09 09:28:28 +02:00
class Exchange:
"""Dispatch events to subscribers."""
2017-07-31 01:58:58 +02:00
def __init__(self):
self.publisher_queue = Queue()
self.started_queue = Queue()
2017-08-09 09:28:28 +02:00
# Map <event_types -> queues>
self.queues = defaultdict(list)
2017-07-31 01:58:58 +02:00
def get_publisher_queue(self):
2017-08-09 09:28:28 +02:00
"""Get the queue used by the publisher.
Returns:
a :class:`multiprocessing.Queue`.
"""
2017-07-31 01:58:58 +02:00
return self.publisher_queue
2017-08-09 16:35:12 +02:00
def get_subscriber_queue(self, event_types=None):
2017-08-09 09:28:28 +02:00
"""Create a new queue for a specific combination of event types
and return it.
Returns:
a :class:`multiprocessing.Queue`.
Raises:
RuntimeError if called after `run`
2017-08-09 09:28:28 +02:00
"""
try:
self.started_queue.get(timeout=1)
raise RuntimeError('Cannot create a new subscriber queue while Exchange is running.')
except Empty:
pass
2017-08-09 16:35:12 +02:00
if event_types is None:
event_types = EventTypes.ALL
2017-07-31 01:58:58 +02:00
queue = Queue()
self.queues[event_types].append(queue)
2017-07-31 01:58:58 +02:00
return queue
2017-08-09 09:28:28 +02:00
def dispatch(self, event):
"""Given an event, send it to all the subscribers.
Args
event (:class:`~bigchaindb.events.EventTypes`): the event to
dispatch to all the subscribers.
"""
for event_types, queues in self.queues.items():
if event.type & event_types:
for queue in queues:
queue.put(event)
2017-07-31 01:58:58 +02:00
def run(self):
2017-08-09 09:28:28 +02:00
"""Start the exchange"""
self.started_queue.put('STARTED')
2017-08-09 09:28:28 +02:00
2017-07-31 01:58:58 +02:00
while True:
event = self.publisher_queue.get()
2017-08-09 16:23:03 +02:00
if event == POISON_PILL:
2017-07-31 01:58:58 +02:00
return
else:
2017-08-09 09:28:28 +02:00
self.dispatch(event)