chainsyncer/chainsyncer/filter.py

97 lines
3.1 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# standard imports
import logging
# local imports
from .error import BackendError
logg = logging.getLogger(__name__)
class SyncFilter:
"""Manages the collection of filters on behalf of a specific backend.
A filter is a pluggable piece of code to execute for every transaction retrieved by the syncer. Filters are executed in the sequence they were added to the instance.
:param backend: Syncer backend to apply filter state changes to
:type backend: chainsyncer.backend.base.Backend implementation
"""
def __init__(self, backend):
self.filters = []
self.backend = backend
def add(self, fltr):
"""Add a filter instance.
:param fltr: Filter instance.
:type fltr: Object instance implementing signature as in chainsyncer.filter.NoopFilter.filter
:raises ValueError: Object instance is incorrect implementation
"""
if getattr(fltr, 'filter') == None:
raise ValueError('filter object must implement have method filter')
logg.debug('added filter "{}"'.format(str(fltr)))
self.filters.append(fltr)
def __apply_one(self, fltr, idx, conn, block, tx, session):
self.backend.begin_filter(idx)
fltr.filter(conn, block, tx, session)
self.backend.complete_filter(idx)
def apply(self, conn, block, tx):
"""Apply all registered filters on the given transaction.
:param conn: RPC Connection, will be passed to the filter method
:type conn: chainlib.connection.RPCConnection
:param block: Block object
:type block: chainlib.block.Block
:param tx: Transaction object
:type tx: chainlib.tx.Tx
:raises BackendError: Backend connection failed
"""
session = None
try:
session = self.backend.connect()
except TimeoutError as e:
self.backend.disconnect()
raise BackendError('database connection fail: {}'.format(e))
i = 0
(pair, flags) = self.backend.get()
for f in self.filters:
if not self.backend.check_filter(i, flags):
logg.debug('applying filter {} {}'.format(str(f), flags))
self.__apply_one(f, i, conn, block, tx, session)
else:
logg.debug('skipping previously applied filter {} {}'.format(str(f), flags))
i += 1
self.backend.disconnect()
class NoopFilter:
"""A noop implemenation of a sync filter.
Logs the filter inputs at debug log level.
"""
def filter(self, conn, block, tx, db_session=None):
"""Filter method implementation:
:param conn: RPC Connection, will be passed to the filter method
:type conn: chainlib.connection.RPCConnection
:param block: Block object
:type block: chainlib.block.Block
:param tx: Transaction object
:type tx: chainlib.tx.Tx
:param db_session: Backend session object
:type db_session: varies
"""
logg.debug('noop filter :received\n{} {} {}'.format(block, tx, id(db_session)))
def __str__(self):
return 'noopfilter'