Repository navigation
Expand file tree
/
Copy pathevents.py
More file actions
92 lines (73 loc) · 2.69 KB
/
Copy pathevents.py
File metadata and controls
92 lines (73 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
"""
events.py - Dual-mode Event Dispatcher
Uses Kivy's Clock if available, otherwise falls back to standard Python threading.
This allows the network engine to be tested in "headless" environments.
"""
try:
from kivy.event import EventDispatcher
from kivy.clock import Clock
except ImportError:
# --- HEADLESS FALLBACK (No Kivy installed) ---
import threading
class Clock:
@staticmethod
def schedule_once(callback, timeout=0):
def _run():
try:
callback(timeout if timeout else 0)
except TypeError:
callback()
t = threading.Timer(0 if timeout <= 0 else timeout, _run)
t.daemon = True
t.start()
return t
class EventDispatcher:
def __init__(self, **kwargs):
self._bindings = {}
def bind(self, **kwargs):
for name, fn in kwargs.items():
self._bindings.setdefault(name, []).append(fn)
def unbind(self, **kwargs):
for name, fn in kwargs.items():
if name in self._bindings:
try:
self._bindings[name].remove(fn)
except ValueError:
pass
def dispatch(self, event_name, *args, **kwargs):
method = getattr(self, event_name, None)
if callable(method):
try:
method(*args, **kwargs)
except TypeError:
method(*args)
except Exception as e:
import traceback
traceback.print_exc()
for h in list(self._bindings.get(event_name, [])):
try:
h(*args, **kwargs)
except Exception as e:
import traceback
traceback.print_exc()
# --- THE ACTUAL DISPATCHER ---
class NetworkDispatcher(EventDispatcher):
"""The bridge between background networking and the main thread."""
__events__ = ("on_connected", "on_disconnected", "on_message_received", "on_error")
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Default handlers
def on_connected(self):
pass
def on_disconnected(self):
pass
def on_message_received(self, message_data):
pass
def on_error(self, error_message):
pass
def trigger_event_safely(self, event_name, *args):
"""
The DRY way to safely push events to the main thread.
Example: self.trigger_event_safely('on_error', "Connection dropped!")
"""
Clock.schedule_once(lambda dt: self.dispatch(event_name, *args), 0)