77import time
88from typing import TYPE_CHECKING , cast
99
10- from eth_typing import HexStr
1110from web3 ._utils .filters import LogFilter
1211from web3 .contract import Contract
1312from web3 .contract .contract import ContractEvent
1413from web3 .types import EventData , LogReceipt
1514
16- from .contract import EVENTS
15+ from .events_base import EventFilterBase
1716from .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
3124if TYPE_CHECKING :
3225 pass
3326
3427logger = 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 )
0 commit comments