Skip to content

Commit 12a9bee

Browse files
refactor EventFilter to inherit from EventFilterBase
1 parent 657d279 commit 12a9bee

File tree

2 files changed

+23
-116
lines changed

2 files changed

+23
-116
lines changed

src/arkiv/events.py

Lines changed: 22 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,44 @@
77
import time
88
from typing import TYPE_CHECKING, cast
99

10-
from eth_typing import HexStr
1110
from web3._utils.filters import LogFilter
1211
from web3.contract import Contract
1312
from web3.contract.contract import ContractEvent
1413
from web3.types import EventData, LogReceipt
1514

16-
from .contract import EVENTS
15+
from .events_base import EventFilterBase
1716
from .types import (
1817
CreateCallback,
19-
CreateEvent,
2018
DeleteCallback,
21-
DeleteEvent,
2219
EventType,
2320
ExtendCallback,
24-
ExtendEvent,
25-
TxHash,
2621
UpdateCallback,
27-
UpdateEvent,
2822
)
29-
from .utils import to_entity_key
3023

3124
if TYPE_CHECKING:
3225
pass
3326

3427
logger = logging.getLogger(__name__)
3528

29+
# Union of all sync callback types
30+
SyncCallback = CreateCallback | UpdateCallback | ExtendCallback | DeleteCallback
3631

37-
class EventFilter:
32+
33+
class EventFilter(EventFilterBase[SyncCallback]):
3834
"""
3935
Handle for watching entity events using HTTP polling.
4036
4137
Uses polling-based filter with get_new_entries() for event monitoring.
4238
WebSocket providers are not supported by the sync Arkiv client.
39+
40+
Inherits shared event parsing logic from EventFilterBase.
4341
"""
4442

4543
def __init__(
4644
self,
4745
contract: Contract,
4846
event_type: EventType,
49-
callback: CreateCallback | UpdateCallback | ExtendCallback | DeleteCallback,
47+
callback: SyncCallback,
5048
from_block: str | int = "latest",
5149
auto_start: bool = True,
5250
) -> None:
@@ -56,22 +54,16 @@ def __init__(
5654
Args:
5755
contract: Web3 contract instance
5856
event_type: Type of event to watch
59-
callback: Callback function for the event
57+
callback: Callback function for the event (sync)
6058
from_block: Starting block for the filter
6159
auto_start: If True, starts polling immediately
6260
"""
63-
self.contract: Contract = contract
64-
self.event_type: EventType = event_type
65-
self.callback: (
66-
CreateCallback | UpdateCallback | ExtendCallback | DeleteCallback
67-
) = callback
68-
self.from_block: str | int = from_block
69-
70-
# Internal state for HTTP polling
71-
self._running: bool = False
61+
# Initialize base class (but don't auto-start yet)
62+
super().__init__(contract, event_type, callback, from_block, auto_start=False)
63+
64+
# Sync-specific state for HTTP polling
7265
self._thread: threading.Thread | None = None
7366
self._filter: LogFilter | None = None
74-
self._poll_interval: float = 2.0 # seconds
7567

7668
if auto_start:
7769
self.start()
@@ -86,16 +78,10 @@ def start(self) -> None:
8678

8779
logger.info(f"Starting event filter for {self.event_type}")
8880

89-
# Create the Web3 filter
90-
contract_event: ContractEvent
91-
if self.event_type in EVENTS.keys():
92-
event_name = EVENTS[self.event_type]
93-
contract_event = self.contract.events[event_name]
94-
self._filter = contract_event.create_filter(from_block=self.from_block)
95-
else:
96-
raise NotImplementedError(
97-
f"Event type {self.event_type} not yet implemented"
98-
)
81+
# Create the Web3 filter using base class helper
82+
event_name = self._get_contract_event_name()
83+
contract_event: ContractEvent = self.contract.events[event_name]
84+
self._filter = contract_event.create_filter(from_block=self.from_block)
9985

10086
# Start polling thread
10187
self._running = True
@@ -122,16 +108,6 @@ def stop(self) -> None:
122108

123109
logger.info(f"Event filter for {self.event_type} stopped")
124110

125-
@property
126-
def is_running(self) -> bool:
127-
"""
128-
Check if the filter is currently running.
129-
130-
Returns:
131-
True if the filter's polling loop is active, False otherwise
132-
"""
133-
return self._running
134-
135111
def uninstall(self) -> None:
136112
"""Uninstall the filter and cleanup resources."""
137113
logger.info(f"Uninstalling event filter for {self.event_type}")
@@ -174,85 +150,16 @@ def _poll_loop(self) -> None:
174150

175151
def _process_event(self, event_data: EventData) -> None:
176152
"""
177-
Process a single event and trigger callback.
153+
Process a single event and trigger sync callback.
178154
179155
Args:
180156
event_data: Event data from Web3 filter
181157
"""
182-
logger.info(f"Processing event: {event_data}")
183-
184-
# Extract common data
185-
entity_key = to_entity_key(event_data["args"]["entityKey"])
186-
tx_hash = self._extract_tx_hash(event_data)
187-
188-
# Create event object and trigger callback based on type
189-
if self.event_type == "created":
190-
create_event = CreateEvent(
191-
entity_key=entity_key,
192-
expiration_block=event_data["args"]["expirationBlock"],
193-
)
194-
self._trigger_callback(
195-
cast(CreateCallback, self.callback), create_event, tx_hash
196-
)
197-
198-
elif self.event_type == "updated":
199-
update_event = UpdateEvent(
200-
entity_key=entity_key,
201-
expiration_block=event_data["args"]["expirationBlock"],
202-
)
203-
self._trigger_callback(
204-
cast(UpdateCallback, self.callback), update_event, tx_hash
205-
)
206-
207-
elif self.event_type == "extended":
208-
extend_event = ExtendEvent(
209-
entity_key=entity_key,
210-
old_expiration_block=event_data["args"]["oldExpirationBlock"],
211-
new_expiration_block=event_data["args"]["newExpirationBlock"],
212-
)
213-
self._trigger_callback(
214-
cast(ExtendCallback, self.callback), extend_event, tx_hash
215-
)
216-
217-
elif self.event_type == "deleted":
218-
delete_event = DeleteEvent(entity_key=entity_key)
219-
self._trigger_callback(
220-
cast(DeleteCallback, self.callback), delete_event, tx_hash
221-
)
222-
223-
else:
224-
logger.warning(f"Unknown event type: {self.event_type}")
225-
226-
def _extract_tx_hash(self, event_data: EventData) -> TxHash:
227-
"""
228-
Extract and normalize transaction hash from event data.
158+
# Use base class to parse event data
159+
event, tx_hash = self._parse_event_data(event_data)
229160

230-
Args:
231-
event_data: Event data from Web3 filter
232-
233-
Returns:
234-
Transaction hash with 0x prefix
235-
"""
236-
tx_hash_hex = event_data["transactionHash"].hex()
237-
if not tx_hash_hex.startswith("0x"):
238-
tx_hash_hex = f"0x{tx_hash_hex}"
239-
return TxHash(HexStr(tx_hash_hex))
240-
241-
def _trigger_callback(
242-
self,
243-
callback: CreateCallback | UpdateCallback | ExtendCallback | DeleteCallback,
244-
event: CreateEvent | UpdateEvent | ExtendEvent | DeleteEvent,
245-
tx_hash: TxHash,
246-
) -> None:
247-
"""
248-
Trigger callback with error handling.
249-
250-
Args:
251-
callback: Callback function to invoke
252-
event: Event object to pass to callback
253-
tx_hash: Transaction hash to pass to callback
254-
"""
161+
# Trigger sync callback with error handling
255162
try:
256-
callback(event, tx_hash) # type: ignore[arg-type]
163+
self.callback(event, tx_hash) # type: ignore[arg-type]
257164
except Exception as e:
258165
logger.error(f"Error in callback: {e}", exc_info=True)

src/arkiv/module_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
ClientT = TypeVar("ClientT")
3535

3636

37-
class ArkivModuleBase(Generic[ClientT]): # noqa: UP046 - Generic syntax for Python 3.10+ compat
37+
class ArkivModuleBase(Generic[ClientT]):
3838
"""Base class for Arkiv modules with shared functionality.
3939
4040
This class contains the common initialization and utility methods

0 commit comments

Comments
 (0)